📄 http.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * http.c - HTTP protocol server and client implementation * * Implements major parts of the Hypertext Transfer Protocol HTTP/1.1 (RFC 2616) * See http://www.w3.org/Protocols/rfc2616/rfc2616.txt * * Lars Wirzenius */ /* XXX re-implement socket pools, with idle connection killing to save sockets *//* XXX implement http_abort *//* XXX give maximum input size *//* XXX kill http_get_real *//* XXX the proxy exceptions list should be a dict, I guess *//* XXX set maximum number of concurrent connections to same host, total? *//* XXX 100 status codes. *//* XXX stop destroying persistent connections when a request is redirected */#include <ctype.h>#include <errno.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include "gwlib.h"/* comment this out if you don't want Keep-Alive HTTP requests */#define USE_KEEPALIVE 1/* comment this out if you don't want HTTP responses to be dumped */#define DUMP_RESPONSE 1/*********************************************************************** * Stuff used in several sub-modules. *//* * Default port to connect to for HTTP connections. */enum { HTTP_PORT = 80, HTTPS_PORT = 443 };/* * Status of this module. */static enum { limbo, running, terminating } run_status = limbo;/* * Which interface to use for outgoing HTTP requests. */static Octstr *http_interface = NULL;/* * Read some headers, i.e., until the first empty line (read and discard * the empty line as well). Return -1 for error, 0 for all headers read, * 1 for more headers to follow. */static int read_some_headers(Connection *conn, List *headers){ Octstr *line, *prev; if (list_len(headers) == 0) prev = NULL; else prev = list_get(headers, list_len(headers) - 1); for (;;) { line = conn_read_line(conn); if (line == NULL) { if (conn_eof(conn)) return -1; return 1; } if (octstr_len(line) == 0) { octstr_destroy(line); break; } if (isspace(octstr_get_char(line, 0)) && prev != NULL) { octstr_append(prev, line); octstr_destroy(line); } else { list_append(headers, line); prev = line; } } return 0;}/* * Check that the HTTP version string is valid. Return -1 for invalid, * 0 for version 1.0, 1 for 1.x. */static int parse_http_version(Octstr *version){ Octstr *prefix; long prefix_len; int digit; prefix = octstr_imm("HTTP/1."); prefix_len = octstr_len(prefix); if (octstr_ncompare(version, prefix, prefix_len) != 0) return -1; if (octstr_len(version) != prefix_len + 1) return -1; digit = octstr_get_char(version, prefix_len); if (!isdigit(digit)) return -1; if (digit == '0') return 0; return 1;}/*********************************************************************** * Proxy support. *//* * Data and functions needed to support proxy operations. If proxy_hostname * is NULL, no proxy is used. */static Mutex *proxy_mutex = NULL;static Octstr *proxy_hostname = NULL;static int proxy_port = 0;static Octstr *proxy_username = NULL;static Octstr *proxy_password = NULL;static List *proxy_exceptions = NULL;static void proxy_add_authentication(List *headers){ Octstr *os; if (proxy_username == NULL || proxy_password == NULL) return; os = octstr_format("%S:%S", proxy_username, proxy_password); octstr_binary_to_base64(os); octstr_strip_blanks(os); octstr_insert(os, octstr_imm("Basic "), 0); http_header_add(headers, "Proxy-Authorization", octstr_get_cstr(os)); octstr_destroy(os);}static void proxy_init(void){ proxy_mutex = mutex_create(); proxy_exceptions = list_create();}static void proxy_shutdown(void){ http_close_proxy(); mutex_destroy(proxy_mutex); proxy_mutex = NULL;}static int proxy_used_for_host(Octstr *host){ int i; mutex_lock(proxy_mutex); if (proxy_hostname == NULL) { mutex_unlock(proxy_mutex); return 0; } for (i = 0; i < list_len(proxy_exceptions); ++i) { if (octstr_compare(host, list_get(proxy_exceptions, i)) == 0) { mutex_unlock(proxy_mutex); return 0; } } mutex_unlock(proxy_mutex); return 1;}void http_use_proxy(Octstr *hostname, int port, List *exceptions, Octstr *username, Octstr *password){ Octstr *e; int i; gw_assert(run_status == running); gw_assert(hostname != NULL); gw_assert(octstr_len(hostname) > 0); gw_assert(port > 0); http_close_proxy(); mutex_lock(proxy_mutex); proxy_hostname = octstr_duplicate(hostname); proxy_port = port; proxy_exceptions = list_create(); for (i = 0; i < list_len(exceptions); ++i) { e = list_get(exceptions, i); debug("gwlib.http", 0, "HTTP: Proxy exception `%s'.", octstr_get_cstr(e)); list_append(proxy_exceptions, octstr_duplicate(e)); } proxy_username = octstr_duplicate(username); proxy_password = octstr_duplicate(password); debug("gwlib.http", 0, "Using proxy <%s:%d>", octstr_get_cstr(proxy_hostname), proxy_port); mutex_unlock(proxy_mutex);}void http_close_proxy(void){ gw_assert(run_status == running || run_status == terminating); mutex_lock(proxy_mutex); proxy_port = 0; octstr_destroy(proxy_hostname); octstr_destroy(proxy_username); octstr_destroy(proxy_password); proxy_hostname = NULL; proxy_username = NULL; proxy_password = NULL; list_destroy(proxy_exceptions, octstr_destroy_item); proxy_exceptions = NULL; mutex_unlock(proxy_mutex);}/*********************************************************************** * Common functions for reading request or result entities. *//* * Value to pass to entity_create. */enum body_expectation { /* * Message must not have a body, even if the headers indicate one. * (i.e. response to HEAD method). */ expect_no_body, /* * Message will have a body if Content-Length or Transfer-Encoding * headers are present (i.e. most request methods). */ expect_body_if_indicated, /* * Message will have a body, possibly zero-length. * (i.e. 200 OK responses to a GET method.) */ expect_body};enum entity_state { reading_headers, reading_chunked_body_len, reading_chunked_body_data, reading_chunked_body_crlf, reading_chunked_body_trailer, reading_body_until_eof, reading_body_with_length, body_error, entity_done};typedef struct { List *headers; Octstr *body; enum body_expectation expect_state; enum entity_state state; long chunked_body_chunk_len; long expected_body_len;} HTTPEntity;/* * The rules for message bodies (length and presence) are defined * in RFC2616 paragraph 4.3 and 4.4. */static void deduce_body_state(HTTPEntity *ent){ Octstr *h = NULL; if (ent->expect_state == expect_no_body) { ent->state = entity_done; return; } ent->state = body_error; /* safety net */ h = http_header_find_first(ent->headers, "Transfer-Encoding"); if (h != NULL) { octstr_strip_blanks(h); if (octstr_str_compare(h, "chunked") != 0) { error(0, "HTTP: Unknown Transfer-Encoding <%s>", octstr_get_cstr(h)); ent->state = body_error; } else { ent->state = reading_chunked_body_len; } octstr_destroy(h); return; } h = http_header_find_first(ent->headers, "Content-Length"); if (h != NULL) { if (octstr_parse_long(&ent->expected_body_len, h, 0, 10) == -1) { error(0, "HTTP: Content-Length header wrong: <%s>", octstr_get_cstr(h)); ent->state = body_error; } else { ent->state = reading_body_with_length; } octstr_destroy(h); return; } if (ent->expect_state == expect_body) ent->state = reading_body_until_eof; else ent->state = entity_done;}/* * Create a HTTPEntity structure suitable for reading the expected * result or request message and decoding the transferred entity (if any). * See the definition of enum body_expectation for the possible values * of exp. */static HTTPEntity *entity_create(enum body_expectation exp){ HTTPEntity *ent; ent = gw_malloc(sizeof(*ent)); ent->headers = http_create_empty_headers(); ent->body = octstr_create(""); ent->chunked_body_chunk_len = -1; ent->expected_body_len = -1; ent->state = reading_headers; ent->expect_state = exp; return ent;}static void entity_destroy(HTTPEntity *ent){ if (ent == NULL) return; http_destroy_headers(ent->headers); octstr_destroy(ent->body); gw_free(ent);}static void read_chunked_body_len(HTTPEntity *ent, Connection *conn){ Octstr *os; long len; os = conn_read_line(conn); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; return; } if (octstr_parse_long(&len, os, 0, 16) == -1) { octstr_destroy(os); ent->state = body_error; return; } octstr_destroy(os); if (len == 0) ent->state = reading_chunked_body_trailer; else { ent->state = reading_chunked_body_data; ent->chunked_body_chunk_len = len; }}static void read_chunked_body_data(HTTPEntity *ent, Connection *conn){ Octstr *os; os = conn_read_fixed(conn, ent->chunked_body_chunk_len); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; } else { octstr_append(ent->body, os); octstr_destroy(os); ent->state = reading_chunked_body_crlf; }}static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn){ Octstr *os; os = conn_read_line(conn); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; } else { octstr_destroy(os); ent->state = reading_chunked_body_len; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -