⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 5 页
字号:
static int parse_request_line(int *method, Octstr **url,                              int *use_version_1_0, Octstr *line){    List *words;    Octstr *version;    Octstr *method_str;    int ret;    words = octstr_split_words(line);    if (list_len(words) != 3) {        list_destroy(words, octstr_destroy_item);	return -1;    }    method_str = list_get(words, 0);    *url = list_get(words, 1);    version = list_get(words, 2);    list_destroy(words, NULL);    if (octstr_compare(method_str, octstr_imm("GET")) == 0)	*method = HTTP_METHOD_GET;    else if (octstr_compare(method_str, octstr_imm("POST")) == 0)	*method = HTTP_METHOD_POST;    else if (octstr_compare(method_str, octstr_imm("HEAD")) == 0)	*method = HTTP_METHOD_HEAD;    else        goto error;    ret = parse_http_version(version);    if (ret < 0)        goto error;    *use_version_1_0 = !ret;    octstr_destroy(method_str);    octstr_destroy(version);    return 0;error:    octstr_destroy(method_str);    octstr_destroy(*url);    octstr_destroy(version);    *url = NULL;    return -1;}static void receive_request(Connection *conn, void *data){    HTTPClient *client;    Octstr *line;    int ret;    if (run_status != running) {	conn_unregister(conn);	return;    }    client = data;        for (;;) {	switch (client->state) {	case reading_request_line:    	    line = conn_read_line(conn);	    if (line == NULL) {		if (conn_eof(conn) || conn_error(conn))		    goto error;	    	return;	    }	    ret = parse_request_line(&client->method, &client->url,                                     &client->use_version_1_0, line);	    octstr_destroy(line);	    if (ret == -1)	    	goto error;   	    /*	     * RFC2616 (4.3) says we should read a message body if there	     * is one, even on GET requests.	     */	    client->request = entity_create(expect_body_if_indicated);	    client->state = reading_request;	    break;	    	case reading_request:	    ret = entity_read(client->request, conn);	    if (ret < 0)		goto error;	    if (ret == 0) {	    	client->state = request_is_being_handled;		conn_unregister(conn);		port_put_request(client);	    }	    return;	case sending_reply:        /* Implicite conn_unregister() and _destroy */        if (conn_error(conn))            goto error;	    if (conn_outbuf_len(conn) > 0)            return;	    /* Reply has been sent completely */	    if (!client->persistent_conn) {            conn_unregister(conn);            client_destroy(client);            return;	    }	    /* Start reading another request */	    client_reset(client);	    break;    	default:	    panic(0, "Internal error: HTTPClient state is wrong.");	}    }    error:    client_destroy(client);}struct server {    int fd;    int port;    int ssl;};static void server_thread(void *dummy){    struct pollfd tab[MAX_SERVERS];    int ports[MAX_SERVERS];    int ssl[MAX_SERVERS];    long i, j, n, fd;    int *portno;    struct server *p;    struct sockaddr_in addr;    int addrlen;    Connection *conn;    HTTPClient *client;    int ret;    n = 0;    while (run_status == running && keep_servers_open) {        if (n == 0 || (n < MAX_SERVERS && list_len(new_server_sockets) > 0)) {            p = list_consume(new_server_sockets);            if (p == NULL) {                debug("gwlib.http", 0, "HTTP: No new servers. Quitting.");                break;            }            tab[n].fd = p->fd;            tab[n].events = POLLIN;            ports[n] = p->port;            ssl[n] = p->ssl;            ++n;            gw_free(p);        }        if ((ret = gwthread_poll(tab, n, -1.0)) == -1) {            if (errno != EINTR) /* a signal was caught during poll() function */                warning(0, "HTTP: gwthread_poll failed.");            continue;        }        for (i = 0; i < n; ++i) {            if (tab[i].revents & POLLIN) {                addrlen = sizeof(addr);                fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen);                if (fd == -1) {                    error(errno, "HTTP: Error accepting a client.");                    (void) close(tab[i].fd);                    port_remove(ports[i]);                    tab[i].fd = -1;                    ports[i] = -1;                    ssl[i] = 0;                } else {                    Octstr *client_ip = host_ip(addr);                    /*                     * Be aware that conn_wrap_fd() will return NULL if SSL                      * handshake has failed, so we only client_create() if                     * there is an conn.                     */                                 if ((conn = conn_wrap_fd(fd, ssl[i]))) {                        client = client_create(ports[i], conn, client_ip);                        conn_register(conn, server_fdset, receive_request, client);                    } else {                        error(0, "HTTP: unsuccessful SSL handshake for client `%s'",                        octstr_get_cstr(client_ip));                        octstr_destroy(client_ip);                    }                }            }        }	        while ((portno = list_extract_first(closed_server_sockets)) != NULL) {            for (i = 0; i < n; ++i) {                if (ports[i] == *portno) {                    (void) close(tab[i].fd);                    port_remove(ports[i]);                    tab[i].fd = -1;                    ports[i] = -1;                    ssl[i] = 0;                }            }            gw_free(portno);        }               j = 0;        for (i = 0; i < n; ++i) {            if (tab[i].fd != -1) {                tab[j] = tab[i];                ports[j] = ports[i];                ssl[j] = ssl[i];                ++j;            }        }        n = j;    }        /* make sure we close all ports */    for (i = 0; i < n; ++i) {        (void) close(tab[i].fd);        port_remove(ports[i]);    }    server_thread_id = -1;}static void start_server_thread(void){    if (!server_thread_is_running) {	/* 	 * To be really certain, we must repeat the test, but use the	 * lock first. If the test failed, however, we _know_ we've	 * already initialized. This strategy of double testing avoids	 * using the lock more than a few times at startup.	 */	mutex_lock(server_thread_lock);	if (!server_thread_is_running) {	    server_fdset = fdset_create();	    server_thread_id = gwthread_create(server_thread, NULL);	    server_thread_is_running = 1;	}	mutex_unlock(server_thread_lock);    }}int http_open_port_if(int port, int ssl, Octstr *interface){    struct server *p;    if (ssl)         info(0, "HTTP: Opening SSL server at port %d.", port);    else         info(0, "HTTP: Opening server at port %d.", port);    p = gw_malloc(sizeof(*p));    p->port = port;    p->ssl = ssl;    p->fd = make_server_socket(port, (interface ? octstr_get_cstr(interface) : NULL));    if (p->fd == -1) {	gw_free(p);    	return -1;    }    port_add(port);    list_produce(new_server_sockets, p);    keep_servers_open = 1;    start_server_thread();    gwthread_wakeup(server_thread_id);    return 0;}int http_open_port(int port, int ssl){    return http_open_port_if(port, ssl, NULL);}void http_close_port(int port){    int *p;        p = gw_malloc(sizeof(*p));    *p = port;    list_produce(closed_server_sockets, p);    gwthread_wakeup(server_thread_id);}void http_close_all_ports(void){    if (server_thread_id != -1) {        keep_servers_open = 0;        gwthread_wakeup(server_thread_id);        gwthread_join_every(server_thread);        fdset_destroy(server_fdset);        server_fdset = NULL;    }}/* * Parse CGI variables from the path given in a GET. Return a list * of HTTPCGIvar pointers. Modify the url so that the variables are * removed. */static List *parse_cgivars(Octstr *url){    HTTPCGIVar *v;    List *list;    int query, et, equals;    Octstr *arg, *args;    query = octstr_search_char(url, '?', 0);    if (query == -1)        return list_create();    args = octstr_copy(url, query + 1, octstr_len(url));    octstr_truncate(url, query);    list = list_create();    while (octstr_len(args) > 0) {        et = octstr_search_char(args, '&', 0);        if (et == -1)            et = octstr_len(args);        arg = octstr_copy(args, 0, et);        octstr_delete(args, 0, et + 1);        equals = octstr_search_char(arg, '=', 0);        if (equals == -1)            equals = octstr_len(arg);        v = gw_malloc(sizeof(HTTPCGIVar));        v->name = octstr_copy(arg, 0, equals);        v->value = octstr_copy(arg, equals + 1, octstr_len(arg));        octstr_url_decode(v->name);        octstr_url_decode(v->value);        octstr_destroy(arg);        list_append(list, v);    }    octstr_destroy(args);    return list;}HTTPClient *http_accept_request(int port, Octstr **client_ip, Octstr **url,     	    	    	    	List **headers, Octstr **body, 				List **cgivars){    HTTPClient *client;    client = port_get_request(port);    if (client == NULL) {	debug("gwlib.http", 0, "HTTP: No clients with requests, quitting.");    	return NULL;    }    *client_ip = octstr_duplicate(client->ip);    *url = client->url;    *headers = client->request->headers;    *body = client->request->body;    *cgivars = parse_cgivars(client->url);    if (client->method != HTTP_METHOD_POST) {	octstr_destroy(*body);	*body = NULL;    }    client->persistent_conn = client_is_persistent(client->request->headers,						   client->use_version_1_0);        client->url = NULL;    client->request->headers = NULL;    client->request->body = NULL;    entity_destroy(client->request);    client->request = NULL;    return client;}/* * The http_send_reply(...) uses this function to determinate the * reason pahrase for a status code. */static const char *http_reason_phrase(int status){	switch (status) {	case HTTP_OK:		return "OK";						/* 200 */	case HTTP_CREATED:                   		return "Created";					/* 201 */	case HTTP_ACCEPTED:		return "Accepted";					/* 202 */	case HTTP_NO_CONTENT:		return "No Content";				/* 204 */	case HTTP_RESET_CONTENT: 		return "Reset Content";				/* 205 */	case HTTP_MOVED_PERMANENTLY:		return "Moved Permanently"; 		/* 301 */	case HTTP_FOUND:		return "Found";						/* 302 */	case HTTP_SEE_OTHER:		return "See Other";					/* 303 */	case HTTP_NOT_MODIFIED:		return "Not Modified";				/* 304 */	case HTTP_TEMPORARY_REDIRECT:		return "Temporary Redirect";		/* 307 */	case HTTP_BAD_REQUEST:		return "Bad Request";				/* 400 */	case HTTP_UNAUTHORIZED:		return "Unauthorized";				/* 401 */	case HTTP_FORBIDDEN:		return "Forbidden";					/* 403 */	case HTTP_NOT_FOUND:           			return "Not Found";					/* 404 */	case HTTP_BAD_METHOD:		return "Method Not Allowed";		/* 405 */	case HTTP_NOT_ACCEPTABLE:		return "Not Acceptable";			/* 406 */	case HTTP_REQUEST_ENTITY_TOO_LARGE:		return "Request Entity Too Large";	/* 413 */	case HTTP_UNSUPPORTED_MEDIA_TYPE:		return "Unsupported Media Type";	/* 415 */	case HTTP_INTERNAL_SERVER_ERROR:		return "Internal Server Error";		/* 500 */	case HTTP_NOT_IMPLEMENTED:		return "Not Implemented";			/* 501 */	case HTTP_BAD_GATEWAY:		return "Bad Gateway";				/* 502 */	}	return "Foo";}void http_send_reply(HTTPClient *client, int status, List *headers,     	    	     Octstr *body){    Octstr *response;    long i;    int ret;    if (client->use_version_1_0)    	response = octstr_format("HTTP/1.0 %d %s\r\n", status, http_reason_phrase(status));    else    	response = octstr_format("HTTP/1.1 %d %s\r\n", status, http_reason_phrase(status));    /* identify ourselfs */    octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION);    octstr_format_append(response, "Content-Length: %ld\r\n",			 octstr_len(body));    /*      * RFC2616, sec. 8.1.2.1 says that if the server chooses to close the      * connection, it *should* send a coresponding header     */    if (!client->use_version_1_0 && !client->persistent_conn)        octstr_format_append(response, "Connection: close\r\n");    for (i = 0; i < list_len(headers); ++i)    	octstr_format_append(response, "%S\r\n", list_get(headers, i));    octstr_format_append(response, "\r\n");        if (body != NULL && client->method != HTTP_METHOD_HEAD)    	octstr_append(response, body);	    ret = conn_write(client->conn, response);    octstr_destroy(response);    /* obey return code of conn_write() */    /* sending response was successful */    if (ret == 0) {         /* HTTP/1.0 or 1.1, hence keep-alive or keep-alive */        if (!client->persistent_conn) {            client_destroy(client);             } else {            /* XXX mark this HTTPClient in the keep-alive cleaner thread */            client_reset(client);            conn_register(client->conn, ser

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -