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

📄 http.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ====================================================================  * 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 + -