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

📄 http.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 5 页
字号:
 error:  conn_destroy(conn);  error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));  return NULL;}/* * Build and send the HTTP request. Return socket from which the * response can be read or -1 for error. */static int send_request(HTTPServer *trans){  Octstr *request;  request = NULL;  /*    * we have to assume all values in trans are already set   * by parse_url() before calling this.   */  if (trans->username != NULL)    http_add_basic_auth(trans->request_headers, trans->username,			trans->password);  if (proxy_used_for_host(trans->host)) {    proxy_add_authentication(trans->request_headers);    request = build_request(http_method2name(trans->method),			    trans->url, trans->host, trans->port, 			    trans->request_headers, 			    trans->request_body);  } else {    request = build_request(http_method2name(trans->method), trans->uri, 			    trans->host, trans->port,			    trans->request_headers,			    trans->request_body);  }      debug("wsp.http", 0, "HTTP: Sending request:");    octstr_dump(request, 0);  if (conn_write(trans->conn, request) == -1)        goto error;    octstr_destroy(request);  return 0; error:  conn_destroy(trans->conn);  trans->conn = NULL;    octstr_destroy(request);    error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));  return -1;}/* * This thread starts the transaction: it connects to the server and sends * the request. It then sends the transaction to the read_response_thread * via started_requests_queue. */static void write_request_thread(void *arg){    HTTPServer *trans;    char buf[128];        int rc;    while (run_status == running) {        trans = list_consume(pending_requests);        if (trans == NULL)            break;        gw_assert(trans->state == request_not_sent);        /*          * get the connection to use         * also calls parse_url() to populate the trans values         */        trans->conn = get_connection(trans);	if (trans->conn == NULL)	  list_produce(trans->caller, trans);        else {          if (conn_is_connected(trans->conn) == 0) {	    debug("gwlib.http", 0, "Socket connected at once");        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 {              list_produce(trans->caller, trans);            }          } else { /* Socket not connected, wait for connection */            debug("gwlib.http", 0, "Socket connecting");            trans->state = connecting;            conn_register(trans->conn, client_fdset, handle_transaction, trans);        }	  	}    }}static void start_client_threads(void){    if (!client_threads_are_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(client_thread_lock);	if (!client_threads_are_running) {	    client_fdset = fdset_create();	    gwthread_create(write_request_thread, NULL);	    client_threads_are_running = 1;	}	mutex_unlock(client_thread_lock);    }}void http_set_interface(const Octstr *our_host){  http_interface = octstr_duplicate(our_host);}void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers,    	    	    	Octstr *body, int follow, void *id, Octstr *certkeyfile){    HTTPServer *trans;    int follow_remaining;        if (follow)    	follow_remaining = HTTP_MAX_FOLLOW;    else    	follow_remaining = 0;    trans = server_create(caller, method, url, headers, body, follow_remaining, 			  certkeyfile);    if (id == NULL)	/* We don't leave this NULL so http_receive_result can use NULL	 * to signal no more requests */	trans->request_id = http_start_request;    else	trans->request_id = id;    list_produce(pending_requests, trans);    start_client_threads();}void *http_receive_result(HTTPCaller *caller, int *status, Octstr **final_url,    	    	    	 List **headers, Octstr **body){    HTTPServer *trans;    void *request_id;    trans = list_consume(caller);    if (trans == NULL)    	return NULL;    request_id = trans->request_id;    *status = trans->status;        if (trans->status >= 0) {	*final_url = trans->url;	*headers = trans->response->headers;	*body = trans->response->body;	trans->url = NULL;	trans->response->headers = NULL;	trans->response->body = NULL;    } else {	*final_url = NULL;	*headers = NULL;	*body = NULL;    }    server_destroy(trans);    return request_id;}int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url,                  List **reply_headers, Octstr **reply_body){    HTTPCaller *caller;    int status;    void *ret;        caller = http_caller_create();    http_start_request(caller, method, url, request_headers,                        NULL, 1, http_get_real, NULL);    ret = http_receive_result(caller, &status, final_url,     	    	    	      reply_headers, reply_body);    http_caller_destroy(caller);    if (ret == NULL)    	return -1;    return status;}static void client_init(void){    pending_requests = list_create();    list_add_producer(pending_requests);    client_thread_lock = mutex_create();}static void client_shutdown(void){    list_remove_producer(pending_requests);    gwthread_join_every(write_request_thread);    list_destroy(pending_requests, server_destroy);    mutex_destroy(client_thread_lock);    fdset_destroy(client_fdset);    octstr_destroy(http_interface);    http_interface = NULL;}/*********************************************************************** * HTTP server interface. *//* * Information about a client that has connected to the server we implement. */struct HTTPClient {    int port;    Connection *conn;    Octstr *ip;    enum {        reading_request_line,        reading_request,        request_is_being_handled,        sending_reply    } state;    int method;  /* HTTP_METHOD_ value */    Octstr *url;    int use_version_1_0;    int persistent_conn;    unsigned long conn_time; /* store time for timeouting */    HTTPEntity *request;};static HTTPClient *client_create(int port, Connection *conn, Octstr *ip){    HTTPClient *p;    #ifdef HAVE_LIBSSL    if (conn_get_ssl(conn))         debug("gwlib.http", 0, "HTTP: Creating SSL-enabled HTTPClient for `%s', using cipher '%s'.",    	      octstr_get_cstr(ip), SSL_get_cipher_version(conn_get_ssl(conn)));    else#endif        debug("gwlib.http", 0, "HTTP: Creating HTTPClient for `%s'.",    	  octstr_get_cstr(ip));    p = gw_malloc(sizeof(*p));    p->port = port;    p->conn = conn;    p->ip = ip;    p->state = reading_request_line;    p->url = NULL;    p->use_version_1_0 = 0;    p->persistent_conn = 1;    p->conn_time = time(NULL);    p->request = NULL;    return p;}static void client_destroy(void *client){    HTTPClient *p;        if (client == NULL)    	return;    p = client;    debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p);    gw_assert_allocated(p, __FILE__, __LINE__, __func__);    debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.",    	  octstr_get_cstr(p->ip));    conn_destroy(p->conn);    octstr_destroy(p->ip);    octstr_destroy(p->url);    entity_destroy(p->request);    gw_free(p);}static void client_reset(HTTPClient *p){    debug("gwlib.http", 0, "HTTP: Resetting HTTPClient for `%s'.",    	  octstr_get_cstr(p->ip));    p->state = reading_request_line;    p->conn_time = time(NULL);    gw_assert(p->request == NULL);}/* * Checks whether the client connection is meant to be persistent or not. * Returns 1 for true, 0 for false. */static int client_is_persistent(List *headers, int use_version_1_0){    Octstr *h = http_header_find_first(headers, "Connection");    if (h == NULL) {        return !use_version_1_0;    } else {        if (!use_version_1_0) {            if (octstr_case_compare(h, octstr_imm("keep-alive")) == 0) {                octstr_destroy(h);                return 1;            } else {                octstr_destroy(h);                return 0;            }	    } else if (octstr_case_compare(h, octstr_imm("close")) == 0) {            octstr_destroy(h);            return 0;        }        octstr_destroy(h);    }    return 1;}/* * Port specific lists of clients with requests. */struct port {    List *clients_with_requests;    Counter *active_consumers;};static Mutex *port_mutex = NULL;static Dict *port_collection = NULL;static void port_init(void){    port_mutex = mutex_create();    port_collection = dict_create(1024, NULL);}static void port_shutdown(void){    mutex_destroy(port_mutex);    dict_destroy(port_collection);}static Octstr *port_key(int port){    return octstr_format("%d", port);}static void port_add(int port){    Octstr *key;    struct port *p;    p = gw_malloc(sizeof(*p));    p->clients_with_requests = list_create();    list_add_producer(p->clients_with_requests);    p->active_consumers = counter_create();    key = port_key(port);    mutex_lock(port_mutex);    dict_put(port_collection, key, p);    mutex_unlock(port_mutex);    octstr_destroy(key);}static void port_remove(int port){    Octstr *key;    struct port *p;    key = port_key(port);    mutex_lock(port_mutex);    p = dict_remove(port_collection, key);    mutex_unlock(port_mutex);    octstr_destroy(key);    list_remove_producer(p->clients_with_requests);    while (counter_value(p->active_consumers) > 0)       gwthread_sleep(0.1);    /* Reasonable use of busy waiting. */    list_destroy(p->clients_with_requests, client_destroy);    counter_destroy(p->active_consumers);    gw_free(p);}static void port_put_request(HTTPClient *client){    Octstr *key;    struct port *p;    mutex_lock(port_mutex);    key = port_key(client->port);    p = dict_get(port_collection, key);    gw_assert(p != NULL);    list_produce(p->clients_with_requests, client);    octstr_destroy(key);    mutex_unlock(port_mutex);}static HTTPClient *port_get_request(int port){    Octstr *key;    struct port *p;    HTTPClient *client;        mutex_lock(port_mutex);    key = port_key(port);    p = dict_get(port_collection, key);    octstr_destroy(key);    if (p == NULL) {       client = NULL;       mutex_unlock(port_mutex);    } else {       counter_increase(p->active_consumers);       mutex_unlock(port_mutex);   /* Placement of this unlock is tricky. */       client = list_consume(p->clients_with_requests);       counter_decrease(p->active_consumers);    }    return client;}/* * Maximum number of servers (ports) we have open at the same time. */enum { MAX_SERVERS = 32 };/* * Variables related to server side implementation. */static Mutex *server_thread_lock = NULL;static volatile sig_atomic_t server_thread_is_running = 0;static long server_thread_id = -1;static FDSet *server_fdset = NULL;static List *new_server_sockets = NULL;static List *closed_server_sockets = NULL;static int keep_servers_open = 0;

⌨️ 快捷键说明

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