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

📄 http.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 5 页
字号:
static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn){    int ret;    ret = read_some_headers(conn, ent->headers);    if (ret == -1)	ent->state = body_error;    if (ret == 0)        ent->state = entity_done;}static void read_body_until_eof(HTTPEntity *ent, Connection *conn){    Octstr *os;    while ((os = conn_read_everything(conn)) != NULL) {        octstr_append(ent->body, os);        octstr_destroy(os);    }    if (conn_error(conn))	ent->state = body_error;    if (conn_eof(conn))	ent->state = entity_done;}static void read_body_with_length(HTTPEntity *ent, Connection *conn){    Octstr *os;    os = conn_read_fixed(conn, ent->expected_body_len);    if (os == NULL)        return;    octstr_destroy(ent->body);    ent->body = os;    ent->state = entity_done;}/* * Read headers and body (if any) from this connection.  Return 0 if it's * complete, 1 if we expect more input, and -1 if there is something wrong. */static int entity_read(HTTPEntity *ent, Connection *conn){    int ret;    enum entity_state old_state;    /*     * In this loop, each state will process as much input as it needs     * and then switch to the next state, unless it's a final state in     * which case it returns directly, or unless it needs more input.     * So keep looping as long as the state changes.     */    do {	old_state = ent->state;	switch (ent->state) {	case reading_headers:	    ret = read_some_headers(conn, ent->headers);            if (ret == 0)	        deduce_body_state(ent);	    if (ret < 0)		return -1;	    break;	case reading_chunked_body_len:	    read_chunked_body_len(ent, conn);	    break;			case reading_chunked_body_data:	    read_chunked_body_data(ent, conn);	    break;	case reading_chunked_body_crlf:	    read_chunked_body_crlf(ent, conn);	    break;	case reading_chunked_body_trailer:	    read_chunked_body_trailer(ent, conn);	    break;	case reading_body_until_eof:	    read_body_until_eof(ent, conn);	    break;	case reading_body_with_length:	    read_body_with_length(ent, conn);	    break;	case body_error:	    return -1;	case entity_done:	    return 0;	default:	    panic(0, "Internal error: Invalid HTTPEntity state.");	}    } while (ent->state != old_state);    /*     * If we got here, then the loop ended because a non-final state     * needed more input.     */    return 1;}/*********************************************************************** * HTTP client interface. *//* * Maximum number of HTTP redirections to follow. Making this infinite * could cause infinite looping if the redirections loop. */enum { HTTP_MAX_FOLLOW = 5 };/* * The implemented HTTP method strings * Order is sequenced by the enum in the header */static char *http_methods[] = {    "GET", "POST", "HEAD"};/* * Information about a server we've connected to. */typedef struct {    HTTPCaller *caller;    void *request_id;    int method;             /* uses enums from http.h for the HTTP methods */    Octstr *url;            /* the full URL, including scheme, host, etc. */    Octstr *uri;            /* the HTTP URI path only */    List *request_headers;    Octstr *request_body;   /* NULL for GET or HEAD, non-NULL for POST */    enum {      connecting,	request_not_sent,	reading_status,	reading_entity,	transaction_done    } state;    long status;    int persistent;    HTTPEntity *response; /* Can only be NULL if status < 0 */    Connection *conn;    Octstr *host;    long port;    int retrying;    int follow_remaining;    Octstr *certkeyfile;    int ssl;    Octstr *username;	/* For basic authentication */    Octstr *password;} HTTPServer;static int send_request(HTTPServer *trans);static Octstr *build_response(List *headers, Octstr *body);static HTTPServer *server_create(HTTPCaller *caller, int method, Octstr *url,                                 List *headers, Octstr *body, int follow_remaining,                                 Octstr *certkeyfile){    HTTPServer *trans;        trans = gw_malloc(sizeof(*trans));    trans->caller = caller;    trans->request_id = NULL;    trans->method = method;    trans->url = octstr_duplicate(url);    trans->uri = NULL;    trans->request_headers = http_header_duplicate(headers);    trans->request_body = octstr_duplicate(body);    trans->state = request_not_sent;    trans->status = -1;    trans->persistent = 0;    trans->response = NULL;    trans->conn = NULL;    trans->host = NULL;    trans->port = 0;    trans->username = NULL;    trans->password = NULL;    trans->retrying = 0;    trans->follow_remaining = follow_remaining;    trans->certkeyfile = certkeyfile;    trans->ssl = 0;    return trans;}static void server_destroy(void *p){    HTTPServer *trans;        trans = p;    octstr_destroy(trans->url);    octstr_destroy(trans->uri);    http_destroy_headers(trans->request_headers);    trans->request_headers = NULL;    octstr_destroy(trans->request_body);    entity_destroy(trans->response);    octstr_destroy(trans->host);    octstr_destroy(trans->certkeyfile);    octstr_destroy(trans->username);    octstr_destroy(trans->password);    gw_free(trans);}/* * Pool of open, but unused connections to servers or proxies. Key is * "servername:port", value is List with Connection objects. */static Dict *conn_pool = NULL;static Mutex *conn_pool_lock = NULL;static void conn_pool_item_destroy(void *item){    Connection *conn;        while ((conn = list_extract_first(item)) != NULL)    	conn_destroy(conn);    list_destroy(item, NULL);}static void conn_pool_init(void){    conn_pool = dict_create(1024, conn_pool_item_destroy);    conn_pool_lock = mutex_create();}static void conn_pool_shutdown(void){    dict_destroy(conn_pool);    mutex_destroy(conn_pool_lock);}static Octstr *conn_pool_key(Octstr *host, int port){    return octstr_format("%S:%d", host, port);}static Connection *conn_pool_get(Octstr *host, int port, int ssl, Octstr *certkeyfile,		Octstr *our_host){    Octstr *key;    List *list;    Connection *conn;    mutex_lock(conn_pool_lock);    key = conn_pool_key(host, port);    list = dict_get(conn_pool, key);    octstr_destroy(key);    if (list == NULL)    	conn = NULL;    else {	while (1) {	    conn = list_extract_first(list);	    if (conn == NULL)		break;	    /* Check whether the server has closed the connection while	     * it has been in the pool. */	    conn_wait(conn, 0);	    if (!conn_eof(conn) && !conn_error(conn))		break;	    conn_destroy(conn);	}    }    mutex_unlock(conn_pool_lock);        if (conn == NULL) {#ifdef HAVE_LIBSSL	if (ssl) 	    conn = conn_open_ssl(host, port, certkeyfile, our_host);	else#endif /* HAVE_LIBSSL */	    conn = conn_open_tcp_nb(host, port, our_host);	debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",	      octstr_get_cstr(host), port, conn_get_id(conn));    } else {	debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).",	      octstr_get_cstr(host), port, conn_get_id(conn));     }        return conn;}#ifdef USE_KEEPALIVEstatic void conn_pool_put(Connection *conn, Octstr *host, int port){    Octstr *key;    List *list;        mutex_lock(conn_pool_lock);    key = conn_pool_key(host, port);    list = dict_get(conn_pool, key);    if (list == NULL) {    	list = list_create();        dict_put(conn_pool, key, list);    }    list_append(list, conn);    octstr_destroy(key);    mutex_unlock(conn_pool_lock);}#endif/* * Internal lists of completely unhandled requests and requests for which * a request has been sent but response has not yet been read. */static List *pending_requests = NULL;/* * Have background threads been started? */static Mutex *client_thread_lock = NULL;static volatile sig_atomic_t client_threads_are_running = 0;/* * Set of all connections to all servers. Used with conn_register to * do I/O on several connections with a single thread. */static FDSet *client_fdset = NULL;HTTPCaller *http_caller_create(void){    HTTPCaller *caller;        caller = list_create();    list_add_producer(caller);    return caller;}void http_caller_destroy(HTTPCaller *caller){    list_destroy(caller, server_destroy);}void http_caller_signal_shutdown(HTTPCaller *caller){    list_remove_producer(caller);}static Octstr *get_redirection_location(HTTPServer *trans){    if (trans->status < 0 || trans->follow_remaining <= 0)    	return NULL;    /* check for the redirection response codes */    if (trans->status != HTTP_MOVED_PERMANENTLY &&    	trans->status != HTTP_FOUND && trans->status != HTTP_SEE_OTHER &&        trans->status != HTTP_TEMPORARY_REDIRECT)	return NULL;    if (trans->response == NULL)        return NULL;    return http_header_find_first(trans->response->headers, "Location");}/* * Read and parse the status response line from an HTTP server. * Fill in trans->persistent and trans->status with the findings. * Return -1 for error, 1 for status line not yet available, 0 for OK. */static int client_read_status(HTTPServer *trans){    Octstr *line, *version;    long space;    int ret;    line = conn_read_line(trans->conn);    if (line == NULL) {	if (conn_eof(trans->conn) || conn_error(trans->conn))	    return -1;    	return 1;    }    debug("gwlib.http", 0, "HTTP: Status line: <%s>", octstr_get_cstr(line));    space = octstr_search_char(line, ' ', 0);    if (space == -1)    	goto error;	    version = octstr_copy(line, 0, space);    ret = parse_http_version(version);    octstr_destroy(version);    if (ret == -1)    	goto error;    trans->persistent = ret;    octstr_delete(line, 0, space + 1);    space = octstr_search_char(line, ' ', 0);    if (space == -1)    	goto error;    octstr_truncate(line, space);	    if (octstr_parse_long(&trans->status, line, 0, 10) == -1)        goto error;    octstr_destroy(line);    return 0;error:    error(0, "HTTP: Malformed status line from HTTP server: <%s>",	  octstr_get_cstr(line));    octstr_destroy(line);    return -1;}static int response_expectation(int method, int status){    if (status == HTTP_NO_CONTENT ||        status == HTTP_NOT_MODIFIED ||        http_status_class(status) == HTTP_STATUS_PROVISIONAL ||        method == HTTP_METHOD_HEAD)	return expect_no_body;    else        return expect_body;}static void handle_transaction(Connection *conn, void *data){    HTTPServer *trans;    int ret;    Octstr *h;    int rc;    char buf[128];        trans = data;    if (run_status != running) {	conn_unregister(conn);	return;    }    while (trans->state != transaction_done) {	switch (trans->state) {	case connecting:	  debug("gwlib.http", 0, "Get info about connecting socket");          if (conn_get_connect_result(trans->conn) != 0) {            debug("gwlib.http", 0, "Socket not connected");            conn_unregister(conn);            goto error;          }          if (trans->method == HTTP_METHOD_POST) {            /*              * Add a Content-Length header.  Override an existing one, if             * necessary.  We must have an accurate one in order to use the             * connection for more than a single request.             */            http_header_remove_all(trans->request_headers, "Content-Length");            sprintf(buf, "%ld", octstr_len(trans->request_body));            http_header_add(trans->request_headers, "Content-Length", buf);          }           /*            * ok, this has to be an GET or HEAD request method then,           * if it contains a body, then this is not HTTP conform, so at           * least warn the user            */          else if (trans->request_body != NULL) {            warning(0, "HTTP: GET or HEAD method request contains body:");            octstr_dump(trans->request_body, 0);          }          if ((rc = send_request(trans)) == 0) {            trans->state = reading_status;            conn_register(trans->conn, client_fdset, handle_transaction,                           trans);          } else {

⌨️ 快捷键说明

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