Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

http.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * http.c - HTTP protocol server and client implementation
00059  *
00060  * Implements major parts of the Hypertext Transfer Protocol HTTP/1.1 (RFC 2616)
00061  * See http://www.w3.org/Protocols/rfc2616/rfc2616.txt
00062  *
00063  * Lars Wirzenius
00064  */
00065  
00066 /* XXX re-implement socket pools, with idle connection killing to 
00067         save sockets */
00068 /* XXX implement http_abort */
00069 /* XXX give maximum input size */
00070 /* XXX kill http_get_real */
00071 /* XXX the proxy exceptions list should be a dict, I guess */
00072 /* XXX set maximum number of concurrent connections to same host, total? */
00073 /* XXX 100 status codes. */
00074 /* XXX stop destroying persistent connections when a request is redirected */
00075 
00076 #include <ctype.h>
00077 #include <errno.h>
00078 #include <unistd.h>
00079 #include <string.h>
00080 #include <signal.h>
00081 #include <sys/types.h>
00082 #include <sys/socket.h>
00083 
00084 #include "gwlib.h"
00085 #include "gwlib/regex.h"
00086 
00087 /* comment this out if you don't want HTTP responses to be dumped */
00088 #define DUMP_RESPONSE 1
00089 
00090 /* define http client connections timeout in seconds (set to -1 for disable) */
00091 static int http_client_timeout = 240;
00092 
00093 /* define http server connections timeout in seconds (set to -1 for disable) */
00094 #define HTTP_SERVER_TIMEOUT 60
00095 
00096 /***********************************************************************
00097  * Stuff used in several sub-modules.
00098  */
00099 
00100 
00101 /*
00102  * Default port to connect to for HTTP connections.
00103  */
00104 enum { HTTP_PORT = 80,
00105        HTTPS_PORT = 443 };
00106 
00107 
00108 /*
00109  * Status of this module.
00110  */
00111 static enum { 
00112     limbo, 
00113     running, 
00114     terminating 
00115 } run_status = limbo;
00116 
00117 
00118 /*
00119  * Which interface to use for outgoing HTTP requests.
00120  */
00121 static Octstr *http_interface = NULL;
00122 
00123 
00124 /*
00125  * Read some headers, i.e., until the first empty line (read and discard
00126  * the empty line as well). Return -1 for error, 0 for all headers read,
00127  * 1 for more headers to follow.
00128  */
00129 static int read_some_headers(Connection *conn, List *headers)
00130 {
00131     Octstr *line, *prev;
00132 
00133     if (gwlist_len(headers) == 0)
00134         prev = NULL;
00135     else
00136         prev = gwlist_get(headers, gwlist_len(headers) - 1);
00137 
00138     for (;;) {
00139     line = conn_read_line(conn);
00140     if (line == NULL) {
00141             if (conn_eof(conn) || conn_error(conn))
00142             return -1;
00143         return 1;
00144     }
00145         if (octstr_len(line) == 0) {
00146             octstr_destroy(line);
00147             break;
00148         }
00149         if (isspace(octstr_get_char(line, 0)) && prev != NULL) {
00150             octstr_append(prev, line);
00151             octstr_destroy(line);
00152         } else {
00153             gwlist_append(headers, line);
00154             prev = line;
00155         }
00156     }
00157 
00158     return 0;
00159 }
00160 
00161 
00162 /*
00163  * Check that the HTTP version string is valid. Return -1 for invalid,
00164  * 0 for version 1.0, 1 for 1.x.
00165  */
00166 static int parse_http_version(Octstr *version)
00167 {
00168     Octstr *prefix;
00169     long prefix_len;
00170     int digit;
00171     
00172     prefix = octstr_imm("HTTP/1.");
00173     prefix_len = octstr_len(prefix);
00174 
00175     if (octstr_ncompare(version, prefix, prefix_len) != 0)
00176         return -1;
00177     if (octstr_len(version) != prefix_len + 1)
00178         return -1;
00179     digit = octstr_get_char(version, prefix_len);
00180     if (!isdigit(digit))
00181         return -1;
00182     if (digit == '0')
00183         return 0;
00184     return 1;
00185 }
00186 
00187 
00188 /***********************************************************************
00189  * Proxy support.
00190  */
00191 
00192 
00193 /*
00194  * Data and functions needed to support proxy operations. If proxy_hostname 
00195  * is NULL, no proxy is used.
00196  */
00197 static Mutex *proxy_mutex = NULL;
00198 static Octstr *proxy_hostname = NULL;
00199 static int proxy_port = 0;
00200 static int proxy_ssl = 0;
00201 static Octstr *proxy_username = NULL;
00202 static Octstr *proxy_password = NULL;
00203 static List *proxy_exceptions = NULL;
00204 static regex_t *proxy_exceptions_regex = NULL;
00205 
00206 
00207 static void proxy_add_authentication(List *headers)
00208 {
00209     Octstr *os;
00210     
00211     if (proxy_username == NULL || proxy_password == NULL)
00212         return;
00213 
00214     os = octstr_format("%S:%S", proxy_username, proxy_password);
00215     octstr_binary_to_base64(os);
00216     octstr_strip_blanks(os);
00217     octstr_insert(os, octstr_imm("Basic "), 0);
00218     http_header_add(headers, "Proxy-Authorization", octstr_get_cstr(os));
00219     octstr_destroy(os);
00220 }
00221 
00222 
00223 static void proxy_init(void)
00224 {
00225     proxy_mutex = mutex_create();
00226     proxy_exceptions = gwlist_create();
00227 }
00228 
00229 
00230 static void proxy_shutdown(void)
00231 {
00232     http_close_proxy();
00233     mutex_destroy(proxy_mutex);
00234     proxy_mutex = NULL;
00235 }
00236 
00237 
00238 static int proxy_used_for_host(Octstr *host, Octstr *url)
00239 {
00240     int i;
00241 
00242     mutex_lock(proxy_mutex);
00243 
00244     if (proxy_hostname == NULL) {
00245         mutex_unlock(proxy_mutex);
00246         return 0;
00247     }
00248 
00249     for (i = 0; i < gwlist_len(proxy_exceptions); ++i) {
00250         if (octstr_compare(host, gwlist_get(proxy_exceptions, i)) == 0) {
00251             mutex_unlock(proxy_mutex);
00252             return 0;
00253         }
00254     }
00255 
00256     if (proxy_exceptions_regex != NULL && gw_regex_match_pre(proxy_exceptions_regex, url)) {
00257             mutex_unlock(proxy_mutex);
00258             return 0;
00259     }
00260 
00261     mutex_unlock(proxy_mutex);
00262     return 1;
00263 }
00264 
00265 
00266 void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions,
00267                     Octstr *username, Octstr *password, Octstr *exceptions_regex)
00268 {
00269     Octstr *e;
00270     int i;
00271 
00272     gw_assert(run_status == running);
00273     gw_assert(hostname != NULL);
00274     gw_assert(octstr_len(hostname) > 0);
00275     gw_assert(port > 0);
00276 
00277     http_close_proxy();
00278     mutex_lock(proxy_mutex);
00279 
00280     proxy_hostname = octstr_duplicate(hostname);
00281     proxy_port = port;
00282     proxy_ssl = ssl;
00283     proxy_exceptions = gwlist_create();
00284     for (i = 0; i < gwlist_len(exceptions); ++i) {
00285         e = gwlist_get(exceptions, i);
00286         debug("gwlib.http", 0, "HTTP: Proxy exception `%s'.", octstr_get_cstr(e));
00287         gwlist_append(proxy_exceptions, octstr_duplicate(e));
00288     }
00289     if (exceptions_regex != NULL &&
00290         (proxy_exceptions_regex = gw_regex_comp(exceptions_regex, REG_EXTENDED)) == NULL)
00291             panic(0, "Could not compile pattern '%s'", octstr_get_cstr(exceptions_regex));
00292     proxy_username = octstr_duplicate(username);
00293     proxy_password = octstr_duplicate(password);
00294     debug("gwlib.http", 0, "Using proxy <%s:%d> with %s scheme", 
00295           octstr_get_cstr(proxy_hostname), proxy_port,
00296           (proxy_ssl ? "HTTPS" : "HTTP"));
00297 
00298     mutex_unlock(proxy_mutex);
00299 }
00300 
00301 
00302 void http_close_proxy(void)
00303 {
00304     gw_assert(run_status == running || run_status == terminating);
00305 
00306     mutex_lock(proxy_mutex);
00307     proxy_port = 0;
00308     octstr_destroy(proxy_hostname);
00309     octstr_destroy(proxy_username);
00310     octstr_destroy(proxy_password);
00311     proxy_hostname = NULL;
00312     proxy_username = NULL;
00313     proxy_password = NULL;
00314     gwlist_destroy(proxy_exceptions, octstr_destroy_item);
00315     gw_regex_destroy(proxy_exceptions_regex);
00316     proxy_exceptions = NULL;
00317     proxy_exceptions_regex = NULL;
00318     mutex_unlock(proxy_mutex);
00319 }
00320 
00321 
00322 /***********************************************************************
00323  * Common functions for reading request or result entities.
00324  */
00325 
00326 /*
00327  * Value to pass to entity_create.
00328  */
00329 enum body_expectation {
00330    /*
00331     * Message must not have a body, even if the headers indicate one.
00332     * (i.e. response to HEAD method).
00333     */
00334    expect_no_body,
00335    /*
00336     * Message will have a body if Content-Length or Transfer-Encoding
00337     * headers are present (i.e. most request methods).
00338     */
00339    expect_body_if_indicated,
00340    /*
00341     * Message will have a body, possibly zero-length.
00342     * (i.e. 200 OK responses to a GET method.)
00343     */
00344    expect_body
00345 };
00346 
00347 enum entity_state {
00348     reading_headers,
00349     reading_chunked_body_len,
00350     reading_chunked_body_data,
00351     reading_chunked_body_crlf,
00352     reading_chunked_body_trailer,
00353     reading_body_until_eof,
00354     reading_body_with_length,
00355     body_error,
00356     entity_done
00357 };
00358 
00359 typedef struct {
00360     List *headers;
00361     Octstr *body;
00362     enum body_expectation expect_state;
00363     enum entity_state state;
00364     long chunked_body_chunk_len;
00365     long expected_body_len;
00366 } HTTPEntity;
00367 
00368 
00369 /*
00370  * The rules for message bodies (length and presence) are defined
00371  * in RFC2616 paragraph 4.3 and 4.4.
00372  */
00373 static void deduce_body_state(HTTPEntity *ent)
00374 {
00375     Octstr *h = NULL;
00376 
00377     if (ent->expect_state == expect_no_body) {
00378         ent->state = entity_done;
00379         return;
00380     }
00381 
00382     ent->state = body_error;  /* safety net */
00383 
00384     h = http_header_find_first(ent->headers, "Transfer-Encoding");
00385     if (h != NULL) {
00386         octstr_strip_blanks(h);
00387         if (octstr_str_compare(h, "chunked") != 0) {
00388             error(0, "HTTP: Unknown Transfer-Encoding <%s>",
00389                   octstr_get_cstr(h));
00390             ent->state = body_error;
00391         } else {
00392             ent->state = reading_chunked_body_len;
00393         }
00394         octstr_destroy(h);
00395         return;
00396     }
00397 
00398     h = http_header_find_first(ent->headers, "Content-Length");
00399     if (h != NULL) {
00400         if (octstr_parse_long(&ent->expected_body_len, h, 0, 10) == -1 ||
00401             ent->expected_body_len < 0) {
00402             error(0, "HTTP: Content-Length header wrong: <%s>",
00403                   octstr_get_cstr(h));
00404             ent->state = body_error;
00405         } else if (ent->expected_body_len == 0) {
00406             ent->state = entity_done;
00407         } else {
00408             ent->state = reading_body_with_length;
00409         }
00410         octstr_destroy(h);
00411         return;
00412     }
00413 
00414     if (ent->expect_state == expect_body)
00415         ent->state = reading_body_until_eof;
00416     else
00417         ent->state = entity_done;
00418 }
00419 
00420 
00421 /*
00422  * Create a HTTPEntity structure suitable for reading the expected
00423  * result or request message and decoding the transferred entity (if any).
00424  * See the definition of enum body_expectation for the possible values
00425  * of exp.
00426  */
00427 static HTTPEntity *entity_create(enum body_expectation exp)
00428 {
00429     HTTPEntity *ent;
00430 
00431     ent = gw_malloc(sizeof(*ent));
00432     ent->headers = http_create_empty_headers();
00433     ent->body = octstr_create("");
00434     ent->chunked_body_chunk_len = -1;
00435     ent->expected_body_len = -1;
00436     ent->state = reading_headers;
00437     ent->expect_state = exp;
00438 
00439     return ent;
00440 }
00441 
00442 
00443 static void entity_destroy(HTTPEntity *ent)
00444 {
00445     if (ent == NULL)
00446         return;
00447 
00448     http_destroy_headers(ent->headers);
00449     octstr_destroy(ent->body);
00450     gw_free(ent);
00451 }
00452 
00453 
00454 static void read_chunked_body_len(HTTPEntity *ent, Connection *conn)
00455 {
00456     Octstr *os;
00457     long len;
00458     
00459     os = conn_read_line(conn);
00460     if (os == NULL) {
00461         if (conn_error(conn) || conn_eof(conn))
00462         ent->state = body_error;
00463         return;
00464     }
00465     if (octstr_parse_long(&len, os, 0, 16) == -1) {
00466         octstr_destroy(os);
00467     ent->state = body_error;
00468         return;
00469     }
00470     octstr_destroy(os);
00471     if (len == 0)
00472         ent->state = reading_chunked_body_trailer;
00473     else {
00474         ent->state = reading_chunked_body_data;
00475         ent->chunked_body_chunk_len = len;
00476     }
00477 }
00478 
00479 
00480 static void read_chunked_body_data(HTTPEntity *ent, Connection *conn)
00481 {
00482     Octstr *os;
00483 
00484     os = conn_read_fixed(conn, ent->chunked_body_chunk_len);
00485     if (os == NULL) {
00486         if (conn_error(conn) || conn_eof(conn))
00487         ent->state = body_error;
00488     } else {
00489         octstr_append(ent->body, os);
00490         octstr_destroy(os);
00491         ent->state = reading_chunked_body_crlf;
00492     }
00493 }
00494 
00495 
00496 static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn)
00497 {
00498     Octstr *os;
00499 
00500     os = conn_read_line(conn);
00501     if (os == NULL) {
00502         if (conn_error(conn) || conn_eof(conn))
00503         ent->state = body_error;
00504     } else {
00505         octstr_destroy(os);
00506         ent->state = reading_chunked_body_len;
00507     }
00508 }
00509 
00510 
00511 static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn)
00512 {
00513     int ret;
00514 
00515     ret = read_some_headers(conn, ent->headers);
00516     if (ret == -1)
00517     ent->state = body_error;
00518     if (ret == 0)
00519         ent->state = entity_done;
00520 }
00521 
00522 
00523 static void read_body_until_eof(HTTPEntity *ent, Connection *conn)
00524 {
00525     Octstr *os;
00526 
00527     while ((os = conn_read_everything(conn)) != NULL) {
00528         octstr_append(ent->body, os);
00529         octstr_destroy(os);
00530     }
00531     if (conn_error(conn))
00532     ent->state = body_error;
00533     if (conn_eof(conn))
00534     ent->state = entity_done;
00535 }
00536 
00537 
00538 static void read_body_with_length(HTTPEntity *ent, Connection *conn)
00539 {
00540     Octstr *os;
00541 
00542     os = conn_read_fixed(conn, ent->expected_body_len);
00543     if (os == NULL) {
00544         if (conn_error(conn) || conn_eof(conn))
00545             ent->state = body_error;
00546         return;
00547     }
00548     octstr_destroy(ent->body);
00549     ent->body = os;
00550     ent->state = entity_done;
00551 }
00552 
00553 
00554 /*
00555  * Read headers and body (if any) from this connection.  Return 0 if it's
00556  * complete, 1 if we expect more input, and -1 if there is something wrong.
00557  */
00558 static int entity_read(HTTPEntity *ent, Connection *conn)
00559 {
00560     int ret;
00561     enum entity_state old_state;
00562 
00563     /*
00564      * In this loop, each state will process as much input as it needs
00565      * and then switch to the next state, unless it's a final state in
00566      * which case it returns directly, or unless it needs more input.
00567      * So keep looping as long as the state changes.
00568      */
00569     do {
00570     old_state = ent->state;
00571     switch (ent->state) {
00572     case reading_headers:
00573         ret = read_some_headers(conn, ent->headers);
00574             if (ret == 0)
00575             deduce_body_state(ent);
00576         if (ret < 0)
00577         return -1;
00578         break;
00579 
00580     case reading_chunked_body_len:
00581         read_chunked_body_len(ent, conn);
00582         break;
00583         
00584     case reading_chunked_body_data:
00585         read_chunked_body_data(ent, conn);
00586         break;
00587 
00588     case reading_chunked_body_crlf:
00589         read_chunked_body_crlf(ent, conn);
00590         break;
00591 
00592     case reading_chunked_body_trailer:
00593         read_chunked_body_trailer(ent, conn);
00594         break;
00595 
00596     case reading_body_until_eof:
00597         read_body_until_eof(ent, conn);
00598         break;
00599 
00600     case reading_body_with_length:
00601         read_body_with_length(ent, conn);
00602         break;
00603 
00604     case body_error:
00605         return -1;
00606 
00607     case entity_done:
00608         return 0;
00609 
00610     default:
00611         panic(0, "Internal error: Invalid HTTPEntity state.");
00612     }
00613     } while (ent->state != old_state);
00614 
00615     /*
00616      * If we got here, then the loop ended because a non-final state
00617      * needed more input.
00618      */
00619     return 1;
00620 }
00621 
00622 
00623 /***********************************************************************
00624  * HTTP client interface.
00625  */
00626 
00627 /*
00628  * Internal lists of completely unhandled requests and requests for which
00629  * a request has been sent but response has not yet been read.
00630  */
00631 static List *pending_requests = NULL;
00632 
00633 
00634 /*
00635  * Have background threads been started?
00636  */
00637 static Mutex *client_thread_lock = NULL;
00638 static volatile sig_atomic_t client_threads_are_running = 0;
00639 
00640 
00641 /*
00642  * Set of all connections to all servers. Used with conn_register to
00643  * do I/O on several connections with a single thread.
00644  */
00645 static FDSet *client_fdset = NULL;
00646 
00647 /*
00648  * Maximum number of HTTP redirections to follow. Making this infinite
00649  * could cause infinite looping if the redirections loop.
00650  */
00651 #define HTTP_MAX_FOLLOW 5
00652 
00653 
00654 /*
00655  * The implemented HTTP method strings
00656  * Order is sequenced by the enum in the header
00657  */
00658 static char *http_methods[] = {
00659     "GET", "POST", "HEAD"
00660 };
00661 
00662 /*
00663  * Information about a server we've connected to.
00664  */
00665 typedef struct {
00666     HTTPCaller *caller;
00667     void *request_id;
00668     int method;             /* uses enums from http.h for the HTTP methods */
00669     Octstr *url;            /* the full URL, including scheme, host, etc. */
00670     Octstr *uri;            /* the HTTP URI path only */
00671     List *request_headers;
00672     Octstr *request_body;   /* NULL for GET or HEAD, non-NULL for POST */
00673     enum {
00674     connecting,
00675     request_not_sent,
00676     reading_status,
00677     reading_entity,
00678     transaction_done
00679     } state;
00680     long status;
00681     int persistent;
00682     HTTPEntity *response; /* Can only be NULL if status < 0 */
00683     Connection *conn;
00684     Octstr *host;
00685     long port;
00686     int follow_remaining;
00687     Octstr *certkeyfile;
00688     int ssl;
00689     Octstr *username;   /* For basic authentication */
00690     Octstr *password;
00691 } HTTPServer;
00692 
00693 
00694 static int send_request(HTTPServer *trans);
00695 static Octstr *build_response(List *headers, Octstr *body);
00696 
00697 static HTTPServer *server_create(HTTPCaller *caller, int method, Octstr *url,
00698                                  List *headers, Octstr *body, int follow_remaining,
00699                                  Octstr *certkeyfile)
00700 {
00701     HTTPServer *trans;
00702     
00703     trans = gw_malloc(sizeof(*trans));
00704     trans->caller = caller;
00705     trans->request_id = NULL;
00706     trans->method = method;
00707     trans->url = octstr_duplicate(url);
00708     trans->uri = NULL;
00709     trans->request_headers = http_header_duplicate(headers);
00710     trans->request_body = octstr_duplicate(body);
00711     trans->state = request_not_sent;
00712     trans->status = -1;
00713     trans->persistent = 0;
00714     trans->response = NULL;
00715     trans->conn = NULL;
00716     trans->host = NULL;
00717     trans->port = 0;
00718     trans->username = NULL;
00719     trans->password = NULL;
00720     trans->follow_remaining = follow_remaining;
00721     trans->certkeyfile = octstr_duplicate(certkeyfile);
00722     trans->ssl = 0;
00723     return trans;
00724 }
00725 
00726 
00727 static void server_destroy(void *p)
00728 {
00729     HTTPServer *trans;
00730     
00731     trans = p;
00732     octstr_destroy(trans->url);
00733     octstr_destroy(trans->uri);
00734     http_destroy_headers(trans->request_headers);
00735     trans->request_headers = NULL;
00736     octstr_destroy(trans->request_body);
00737     entity_destroy(trans->response);
00738     octstr_destroy(trans->host);
00739     octstr_destroy(trans->certkeyfile);
00740     octstr_destroy(trans->username);
00741     octstr_destroy(trans->password);
00742     gw_free(trans);
00743 }
00744 
00745 
00746 /*
00747  * Pool of open, but unused connections to servers or proxies. Key is
00748  * "servername:port", value is List with Connection objects.
00749  */
00750 static Dict *conn_pool;
00751 static Mutex *conn_pool_lock;
00752 
00753 
00754 static void conn_pool_item_destroy(void *item)
00755 {
00756     gwlist_destroy(item, (void(*)(void*))conn_destroy);
00757 }
00758 
00759 static void conn_pool_init(void)
00760 {
00761     conn_pool = dict_create(1024, conn_pool_item_destroy);
00762     conn_pool_lock = mutex_create();
00763 }
00764 
00765 
00766 static void conn_pool_shutdown(void)
00767 {
00768     dict_destroy(conn_pool);
00769     mutex_destroy(conn_pool_lock);
00770 }
00771 
00772 
00773 static inline Octstr *conn_pool_key(Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host)
00774 {
00775     return octstr_format("%S:%d:%d:%S:%S", host, port, ssl?1:0, certfile?certfile:octstr_imm(""),
00776                          our_host?our_host:octstr_imm(""));
00777 }
00778 
00779 
00780 static Connection *conn_pool_get(Octstr *host, int port, int ssl, Octstr *certkeyfile,
00781         Octstr *our_host)
00782 {
00783     Octstr *key;
00784     List *list = NULL;
00785     Connection *conn = NULL;
00786     int retry;
00787 
00788     do {
00789         retry = 0;
00790         key = conn_pool_key(host, port, ssl, certkeyfile, our_host);
00791         mutex_lock(conn_pool_lock);
00792         list = dict_get(conn_pool, key);
00793         if (list != NULL)
00794             conn = gwlist_extract_first(list);
00795         mutex_unlock(conn_pool_lock);
00796         /*
00797          * Note: we don't hold conn_pool_lock when we check/destroy/unregister
00798          *       connection because otherwise we can deadlock! And it's even better
00799          *       not to delay other threads while we check connection.
00800          */
00801         if (conn != NULL) {
00802 #ifdef USE_KEEPALIVE
00803             /* unregister our server disconnect callback */
00804             conn_unregister(conn);
00805 #endif 
00806             /*
00807              * Check whether the server has closed the connection while
00808              * it has been in the pool.
00809              */
00810             conn_wait(conn, 0);
00811             if (conn_eof(conn) || conn_error(conn)) {
00812                 debug("gwlib.http", 0, "HTTP:conn_pool_get: Server closed connection, destroying it <%s><%p><fd:%d>.",
00813                       octstr_get_cstr(key), conn, conn_get_id(conn));
00814                 conn_destroy(conn);
00815                 retry = 1;
00816                 conn = NULL;
00817             }
00818         }
00819         octstr_destroy(key);
00820     } while(retry == 1);
00821     
00822     if (conn == NULL) {
00823 #ifdef HAVE_LIBSSL
00824         if (ssl) 
00825             conn = conn_open_ssl_nb(host, port, certkeyfile, our_host);
00826         else
00827 #endif /* HAVE_LIBSSL */
00828             conn = conn_open_tcp_nb(host, port, our_host);
00829         debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",
00830               octstr_get_cstr(host), port, conn_get_id(conn));
00831     } else {
00832         debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).",
00833               octstr_get_cstr(host), port, conn_get_id(conn)); 
00834     }
00835     
00836     return conn;
00837 }
00838 
00839 #ifdef USE_KEEPALIVE
00840 static void check_pool_conn(Connection *conn, void *data)
00841 {
00842     Octstr *key = data;
00843     
00844     if (run_status != running) {
00845         conn_unregister(conn);
00846         return;
00847     }
00848     /* check if connection still ok */
00849     if (conn_error(conn) || conn_eof(conn)) {
00850         List *list;
00851         mutex_lock(conn_pool_lock);
00852         list = dict_get(conn_pool, key);
00853         if (gwlist_delete_equal(list, conn) > 0) {
00854             /*
00855              * ok, connection was still within pool. So it's
00856              * safe to destroy this connection.
00857              */
00858             debug("gwlib.http", 0, "HTTP: Server closed connection, destroying it <%s><%p><fd:%d>.",
00859                   octstr_get_cstr(key), conn, conn_get_id(conn));
00860             conn_unregister(conn);
00861             conn_destroy(conn);
00862         }
00863         /*
00864          * it's perfectly valid if connection was not found in connection pool because
00865          * in 'conn_pool_get' we first removed connection from pool with conn_pool_lock locked
00866          * and then check connection for errors with conn_pool_lock unlocked. In the meantime
00867          * fdset's poller may call us. So just ignore such "dummy" call.
00868         */
00869         mutex_unlock(conn_pool_lock);
00870     }
00871 }
00872 
00873 
00874 static void conn_pool_put(Connection *conn, Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host)
00875 {
00876     Octstr *key;
00877     List *list;
00878 
00879     key = conn_pool_key(host, port, ssl, certfile, our_host);
00880     mutex_lock(conn_pool_lock);
00881     list = dict_get(conn_pool, key);
00882     if (list == NULL) {
00883         list = gwlist_create();
00884         dict_put(conn_pool, key, list);
00885     }
00886     gwlist_append(list, conn);
00887     /* register connection to get server disconnect */
00888     conn_register_real(conn, client_fdset, check_pool_conn, key, octstr_destroy_item);
00889     mutex_unlock(conn_pool_lock);
00890 }
00891 #endif
00892 
00893 
00894 HTTPCaller *http_caller_create(void)
00895 {
00896     HTTPCaller *caller;
00897     
00898     caller = gwlist_create();
00899     gwlist_add_producer(caller);
00900     return caller;
00901 }
00902 
00903 
00904 void http_caller_destroy(HTTPCaller *caller)
00905 {
00906     gwlist_destroy(caller, server_destroy);
00907 }
00908 
00909 
00910 void http_caller_signal_shutdown(HTTPCaller *caller)
00911 {
00912     gwlist_remove_producer(caller);
00913 }
00914 
00915 
00916 static Octstr *get_redirection_location(HTTPServer *trans)
00917 {
00918     if (trans->status < 0 || trans->follow_remaining <= 0)
00919         return NULL;
00920     /* check for the redirection response codes */
00921     if (trans->status != HTTP_MOVED_PERMANENTLY &&
00922         trans->status != HTTP_FOUND && trans->status != HTTP_SEE_OTHER &&
00923         trans->status != HTTP_TEMPORARY_REDIRECT)
00924     return NULL;
00925     if (trans->response == NULL)
00926         return NULL;
00927     return http_header_find_first(trans->response->headers, "Location");
00928 }
00929 
00930 
00931 /*
00932  * Read and parse the status response line from an HTTP server.
00933  * Fill in trans->persistent and trans->status with the findings.
00934  * Return -1 for error, 1 for status line not yet available, 0 for OK.
00935  */
00936 static int client_read_status(HTTPServer *trans)
00937 {
00938     Octstr *line, *version;
00939     long space;
00940     int ret;
00941 
00942     line = conn_read_line(trans->conn);
00943     if (line == NULL) {
00944     if (conn_eof(trans->conn) || conn_error(trans->conn))
00945         return -1;
00946         return 1;
00947     }
00948 
00949     debug("gwlib.http", 0, "HTTP: Status line: <%s>", octstr_get_cstr(line));
00950 
00951     space = octstr_search_char(line, ' ', 0);
00952     if (space == -1)
00953         goto error;
00954     
00955     version = octstr_copy(line, 0, space);
00956     ret = parse_http_version(version);
00957     octstr_destroy(version);
00958     if (ret == -1)
00959         goto error;
00960     trans->persistent = ret;
00961 
00962     octstr_delete(line, 0, space + 1);
00963     space = octstr_search_char(line, ' ', 0);
00964     if (space == -1)
00965         goto error;
00966     octstr_truncate(line, space);
00967     
00968     if (octstr_parse_long(&trans->status, line, 0, 10) == -1)
00969         goto error;
00970 
00971     octstr_destroy(line);
00972     return 0;
00973 
00974 error:
00975     error(0, "HTTP: Malformed status line from HTTP server: <%s>",
00976       octstr_get_cstr(line));
00977     octstr_destroy(line);
00978     return -1;
00979 }
00980 
00981 static int response_expectation(int method, int status)
00982 {
00983     if (status == HTTP_NO_CONTENT ||
00984         status == HTTP_NOT_MODIFIED ||
00985         http_status_class(status) == HTTP_STATUS_PROVISIONAL ||
00986         method == HTTP_METHOD_HEAD)
00987     return expect_no_body;
00988     else
00989         return expect_body;
00990 }
00991 
00992 static void handle_transaction(Connection *conn, void *data)
00993 {
00994     HTTPServer *trans;
00995     int ret;
00996     Octstr *h;
00997     int rc;
00998     
00999     trans = data;
01000 
01001     if (run_status != running) {
01002         conn_unregister(conn);
01003         return;
01004     }
01005 
01006     while (trans->state != transaction_done) {
01007         switch (trans->state) {
01008         case connecting:
01009             debug("gwlib.http", 0, "Get info about connecting socket");
01010             if (conn_get_connect_result(trans->conn) != 0) {
01011                 debug("gwlib.http", 0, "Socket not connected");
01012                 goto error;
01013             }
01014 
01015             if ((rc = send_request(trans)) == 0) {
01016                 trans->state = reading_status;
01017             } else {
01018                 debug("gwlib.http", 0, "Failed while sending request");
01019                 goto error;
01020             }
01021             break;
01022 
01023     case reading_status:
01024         ret = client_read_status(trans);
01025         if (ret < 0) {
01026         /*
01027          * Couldn't read the status from the socket. This may mean 
01028          * that the socket had been closed by the server after an 
01029          * idle timeout.
01030          */
01031                 debug("gwlib.http",0,"Failed while reading status");
01032                 goto error;
01033         } else if (ret == 0) {
01034         /* Got the status, go read headers and body next. */
01035         trans->state = reading_entity;
01036         trans->response =
01037             entity_create(response_expectation(trans->method, trans->status));
01038         } else
01039         return;
01040         break;
01041         
01042     case reading_entity:
01043         ret = entity_read(trans->response, conn);
01044         if (ret < 0) {
01045             debug("gwlib.http",0,"Failed reading entity");
01046             goto error;
01047         } else if (ret == 0 && 
01048                     http_status_class(trans->status) == HTTP_STATUS_PROVISIONAL) {
01049                 /* This was a provisional reply; get the real one now. */
01050                 trans->state = reading_status;
01051                 entity_destroy(trans->response);
01052                 trans->response = NULL;
01053             } else if (ret == 0) {
01054                 trans->state = transaction_done;
01055 #ifdef DUMP_RESPONSE
01056                 /* Dump the response */
01057                 debug("gwlib.http", 0, "HTTP: Received response:");
01058                 h = build_response(trans->response->headers, trans->response->body);
01059                 octstr_dump(h, 0);
01060                 octstr_destroy(h);
01061 #endif
01062         } else {
01063                 return;
01064             }
01065             break;
01066 
01067         default:
01068             panic(0, "Internal error: Invalid HTTPServer state.");
01069         }
01070     }
01071 
01072     conn_unregister(trans->conn);
01073 
01074     /* 
01075      * Take care of persistent connection handling. 
01076      * At this point we have only obeyed if server responds in HTTP/1.0 or 1.1
01077      * and have assigned trans->persistent accordingly. This can be keept
01078      * for default usage, but if we have [Proxy-]Connection: keep-alive, then
01079      * we're still forcing persistancy of the connection.
01080      */
01081     h = http_header_find_first(trans->response->headers, "Connection");
01082     if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0)
01083         trans->persistent = 0;
01084     if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0)
01085         trans->persistent = 1;
01086     octstr_destroy(h);
01087     if (proxy_used_for_host(trans->host, trans->url)) {
01088         h = http_header_find_first(trans->response->headers, "Proxy-Connection");
01089         if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0)
01090             trans->persistent = 0;
01091         if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0)
01092             trans->persistent = 1;
01093         octstr_destroy(h);
01094     }
01095 
01096 #ifdef USE_KEEPALIVE 
01097     if (trans->persistent) {
01098         if (proxy_used_for_host(trans->host, trans->url))
01099             conn_pool_put(trans->conn, proxy_hostname, proxy_port, trans->ssl, trans->certkeyfile, http_interface);
01100         else 
01101             conn_pool_put(trans->conn, trans->host, trans->port, trans->ssl, trans->certkeyfile, http_interface);
01102     } else
01103 #endif
01104         conn_destroy(trans->conn);
01105 
01106     trans->conn = NULL;
01107 
01108     /* 
01109      * Check if the HTTP server told us to look somewhere else,
01110      * hence if we got one of the following response codes:
01111      *   HTTP_MOVED_PERMANENTLY (301)
01112      *   HTTP_FOUND (302)
01113      *   HTTP_SEE_OTHER (303)
01114      *   HTTP_TEMPORARY_REDIRECT (307)
01115      */
01116     if ((h = get_redirection_location(trans)) != NULL) {
01117 
01118         /* 
01119          * This is a redirected response, we have to follow.
01120          * Clean up all trans stuff for the next request we do.
01121          */
01122         octstr_strip_blanks(h);
01123         octstr_destroy(trans->url);
01124         octstr_destroy(trans->host);
01125         trans->port = 0;
01126         octstr_destroy(trans->uri);
01127         octstr_destroy(trans->username);
01128         octstr_destroy(trans->password);
01129         trans->host = NULL;
01130         trans->port = 0;
01131         trans->uri = NULL;
01132         trans->username = NULL;
01133         trans->password = NULL;
01134         trans->ssl = 0;
01135         trans->url = h; /* apply new absolute URL to next request */
01136         trans->state = request_not_sent;
01137         trans->status = -1;
01138         http_destroy_headers(trans->response->headers);
01139         trans->response->headers = gwlist_create();
01140         octstr_destroy(trans->response->body);
01141         trans->response->body = octstr_create("");
01142         --trans->follow_remaining;
01143         conn_destroy(trans->conn);
01144         trans->conn = NULL;
01145 
01146         /* re-inject request to the front of the queue */
01147         gwlist_insert(pending_requests, 0, trans);
01148 
01149     } else {
01150         /* handle this response as usual */
01151         gwlist_produce(trans->caller, trans);
01152     }
01153     return;
01154 
01155 error:
01156     conn_unregister(trans->conn);
01157     conn_destroy(trans->conn);
01158     trans->conn = NULL;
01159     error(0, "Couldn't fetch <%s>", octstr_get_cstr(trans->url));
01160     trans->status = -1;
01161     gwlist_produce(trans->caller, trans);
01162 }
01163 
01164 
01165 /*
01166  * Build a complete HTTP request given the host, port, path and headers. 
01167  * Add Host: and Content-Length: headers (and others that may be necessary).
01168  * Return the request as an Octstr.
01169  */
01170 static Octstr *build_request(char *method_name, Octstr *path_or_url, 
01171                              Octstr *host, long port, List *headers, 
01172                              Octstr *request_body)
01173 {
01174     /* XXX headers missing */
01175     Octstr *request;
01176     int i;
01177 
01178     request = octstr_format("%s %S HTTP/1.1\r\n",
01179                             method_name, path_or_url);
01180 
01181     octstr_format_append(request, "Host: %S", host);
01182     if (port != HTTP_PORT)
01183         octstr_format_append(request, ":%ld", port);
01184     octstr_append(request, octstr_imm("\r\n"));
01185 #ifdef USE_KEEPALIVE 
01186     octstr_append(request, octstr_imm("Connection: keep-alive\r\n"));
01187 #endif
01188 
01189     for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
01190         octstr_append(request, gwlist_get(headers, i));
01191         octstr_append(request, octstr_imm("\r\n"));
01192     }
01193     octstr_append(request, octstr_imm("\r\n"));
01194 
01195     if (request_body != NULL)
01196         octstr_append(request, request_body);
01197 
01198     return request;
01199 }
01200 
01201 
01202 /*
01203  * Re-build the HTTP response given the headers and the body.
01204  * Return the response as an Octstr.
01205  */
01206 static Octstr *build_response(List *headers, Octstr *body)
01207 {
01208     Octstr *response;
01209     int i;
01210 
01211     response = octstr_create("");
01212 
01213     for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
01214         octstr_append(response, gwlist_get(headers, i));
01215         octstr_append(response, octstr_imm("\r\n"));
01216     }
01217     octstr_append(response, octstr_imm("\r\n"));
01218 
01219     if (body != NULL)
01220         octstr_append(response, body);
01221 
01222     return response;
01223 }
01224 
01225 
01226 HTTPURLParse *http_urlparse_create(void)
01227 {
01228     HTTPURLParse *p;
01229 
01230     p = gw_malloc(sizeof(HTTPURLParse));
01231     p->url = NULL;
01232     p->scheme = NULL;
01233     p->host = NULL;
01234     p->port = 0;
01235     p->user = NULL;
01236     p->pass = NULL;
01237     p->path = NULL;
01238     p->query = NULL;
01239     p->fragment = NULL;
01240     
01241     return p;
01242 }
01243 
01244 
01245 void http_urlparse_destroy(HTTPURLParse *p)
01246 {
01247     gw_assert(p != NULL);
01248 
01249     octstr_destroy(p->url);
01250     octstr_destroy(p->scheme);
01251     octstr_destroy(p->host);
01252     octstr_destroy(p->user);
01253     octstr_destroy(p->pass);
01254     octstr_destroy(p->path);
01255     octstr_destroy(p->query);
01256     octstr_destroy(p->fragment);
01257     gw_free(p);
01258 }
01259 
01260 
01261 void parse_dump(HTTPURLParse *p) 
01262 {
01263     if (p == NULL)
01264         return;
01265     debug("http.parse_url",0,"Parsing URL `%s':", octstr_get_cstr(p->url));
01266     debug("http.parse_url",0,"  Scheme: %s", octstr_get_cstr(p->scheme));  
01267     debug("http.parse_url",0,"  Host: %s", octstr_get_cstr(p->host));  
01268     debug("http.parse_url",0,"  Port: %ld", p->port);  
01269     debug("http.parse_url",0,"  Username: %s", octstr_get_cstr(p->user));  
01270     debug("http.parse_url",0,"  Password: %s", octstr_get_cstr(p->pass));  
01271     debug("http.parse_url",0,"  Path: %s", octstr_get_cstr(p->path));  
01272     debug("http.parse_url",0,"  Query: %s", octstr_get_cstr(p->query));  
01273     debug("http.parse_url",0,"  Fragment: %s", octstr_get_cstr(p->fragment));  
01274 }
01275 
01276 
01277 /*
01278  * Parse the URL to get all components, which are: scheme, hostname, 
01279  * port, username, password, path (URI), query (the CGI parameter list), 
01280  * fragment (#).
01281  *
01282  * On success return the HTTPURLParse structure, otherwise NULL if the URL 
01283  * seems malformed.
01284  *
01285  * We assume HTTP URLs of the form specified in "3.2.2 http URL" in
01286  * RFC 2616:
01287  * 
01288  *  http_URL = "http:" "//" [ userid : password "@"] host [ ":" port ] [ abs_path [ "?" query ]] 
01289  */
01290 HTTPURLParse *parse_url(Octstr *url)
01291 {
01292     HTTPURLParse *p;
01293     Octstr *prefix, *prefix_https;
01294     long prefix_len;
01295     int host_len, colon, slash, at, auth_sep, query;
01296     host_len = colon = slash = at = auth_sep = query = 0;
01297 
01298     prefix = octstr_imm("http://");
01299     prefix_https = octstr_imm("https://");
01300     prefix_len = octstr_len(prefix);
01301 
01302     if (octstr_case_search(url, prefix, 0) != 0) {
01303         if (octstr_case_search(url, prefix_https, 0) == 0) {
01304 #ifdef HAVE_LIBSSL
01305             debug("gwlib.http", 0, "HTTPS URL; Using SSL for the connection");
01306             prefix = prefix_https;
01307             prefix_len = octstr_len(prefix_https);  
01308 #else
01309             error(0, "Attempt to use HTTPS <%s> but SSL not compiled in", 
01310                   octstr_get_cstr(url));
01311             return NULL;
01312 #endif
01313         } else {
01314             error(0, "URL <%s> doesn't start with `%s' nor `%s'",
01315             octstr_get_cstr(url), octstr_get_cstr(prefix),
01316             octstr_get_cstr(prefix_https));
01317             return NULL;
01318         }
01319     }
01320 
01321     /* an URL should be more (at least one charset) then the scheme itself */
01322     if (octstr_len(url) == prefix_len) {
01323         error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
01324         return NULL;
01325     }
01326 
01327     /* check if colon and slashes are within scheme */
01328     colon = octstr_search_char(url, ':', prefix_len);
01329     slash = octstr_search_char(url, '/', prefix_len);
01330     if (colon == prefix_len || slash == prefix_len) {
01331         error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
01332         return NULL;
01333     }
01334 
01335     /* create struct and add values succesively while parsing */
01336     p = http_urlparse_create();
01337     p->url = octstr_duplicate(url);
01338     p->scheme = octstr_duplicate(prefix);
01339 
01340     /* try to parse authentication separator */
01341     at = octstr_search_char(url, '@', prefix_len);
01342     if (at != -1) {
01343         if ((slash == -1 || ( slash != -1 && at < slash))) {
01344             auth_sep = octstr_search_char(url, ':', prefix_len);
01345             if (auth_sep != -1 && (auth_sep < at)) {
01346                 octstr_set_char(url, auth_sep, '@');
01347                 colon = octstr_search_char(url, ':', prefix_len);
01348             }
01349         } else {
01350             at = -1;
01351         }
01352     }
01353 
01354     /*
01355      * We have to watch out here for 4 cases:
01356      *  a) hostname, no port or path
01357      *  b) hostname, port, no path
01358      *  c) hostname, path, no port
01359      *  d) hostname, port and path
01360      */
01361     
01362     /* we only have the hostname, no port or path. */
01363     if (slash == -1 && colon == -1) {
01364         host_len = octstr_len(url) - prefix_len;
01365 #ifdef HAVE_LIBSSL
01366         p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? 
01367             HTTPS_PORT : HTTP_PORT;
01368 #else
01369         p->port = HTTP_PORT;
01370 #endif /* HAVE_LIBSSL */
01371     } 
01372     /* we have a port, but no path. */
01373     else if (slash == -1) {
01374         host_len = colon - prefix_len;
01375         if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
01376             error(0, "URL <%s> has malformed port number.",
01377                   octstr_get_cstr(url));
01378             http_urlparse_destroy(p);
01379             return NULL;
01380         }
01381     } 
01382     /* we have a path, but no port. */
01383     else if (colon == -1 || colon > slash) {
01384         host_len = slash - prefix_len;
01385 #ifdef HAVE_LIBSSL
01386         p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? 
01387             HTTPS_PORT : HTTP_PORT;
01388 #else
01389         p->port = HTTP_PORT;
01390 #endif /* HAVE_LIBSSL */
01391     } 
01392     /* we have both, path and port. */
01393     else if (colon < slash) {
01394         host_len = colon - prefix_len;
01395         if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
01396             error(0, "URL <%s> has malformed port number.",
01397                   octstr_get_cstr(url));
01398             http_urlparse_destroy(p);
01399             return NULL;
01400         }
01401     /* none of the above, so there is something wrong here */
01402     } else {
01403         error(0, "Internal error in URL parsing logic.");
01404         http_urlparse_destroy(p);
01405         return NULL;
01406     }
01407 
01408     /* there was an authenticator separator, so try to parse 
01409      * the username and password credentials */
01410     if (at != -1) {
01411         int at2;
01412 
01413         at2 = octstr_search_char(url, '@', prefix_len);
01414         p->user = octstr_copy(url, prefix_len, at2 - prefix_len);
01415         p->pass = (at2 != at) ? octstr_copy(url, at2 + 1, at - at2 - 1) : NULL;
01416 
01417         if (auth_sep != -1)
01418             octstr_set_char(url, auth_sep, ':');
01419   
01420         host_len = host_len - at + prefix_len - 1;
01421         prefix_len = at + 1;
01422     }
01423 
01424     /* query (CGI vars) */
01425     query = octstr_search_char(url, '?', (slash == -1) ? prefix_len : slash);
01426     if (query != -1) {
01427         p->query = octstr_copy(url, query + 1, octstr_len(url));
01428     }
01429 
01430     /* path */
01431     p->path = (slash == -1) ? 
01432         octstr_create("/") : ((query != -1) && (query > slash) ? 
01433             octstr_copy(url, slash, query - slash) :
01434             octstr_copy(url, slash, octstr_len(url) - slash)); 
01435 
01436     /* hostname */
01437     p->host = octstr_copy(url, prefix_len, 
01438         (query == -1 || slash != -1) ? host_len : query - prefix_len);
01439 
01440     /* XXX add fragment too */
01441    
01442     /* dump components */
01443     parse_dump(p);
01444 
01445     return p;
01446 }
01447 
01448 /* copy all relevant parsed data to the server info struct */
01449 static void parse2trans(HTTPURLParse *p, HTTPServer *t)
01450 {
01451     if (p == NULL || t == NULL)
01452         return;
01453 
01454     if (p->user && !t->username)
01455         t->username = octstr_duplicate(p->user);
01456     if (p->pass && !t->password)
01457         t->password = octstr_duplicate(p->pass);
01458     if (p->host && !t->host) 
01459         t->host = octstr_duplicate(p->host);
01460     if (p->port && !t->port)
01461         t->port = p->port;
01462     if (p->path && !t->uri) {
01463         t->uri = octstr_duplicate(p->path);
01464         if (p->query) { /* add the query too */
01465             octstr_append_char(t->uri, '?');
01466             octstr_append(t->uri, p->query);
01467         }
01468     }
01469     t->ssl = (p->scheme && (octstr_compare(p->scheme, octstr_imm("https://")) == 0) 
01470               && !t->ssl) ? 1 : 0;
01471 }
01472 
01473 static Connection *get_connection(HTTPServer *trans) 
01474 {
01475     Connection *conn = NULL;
01476     Octstr *host;
01477     HTTPURLParse *p;
01478     int port, ssl;
01479     
01480     /* if the parsing has not yet been done, then do it now */
01481     if (!trans->host && trans->port == 0 && trans->url != NULL) {
01482         if ((p = parse_url(trans->url)) != NULL) {
01483             parse2trans(p, trans);
01484             http_urlparse_destroy(p);
01485         } else {
01486             goto error;
01487         }
01488     }
01489 
01490     if (proxy_used_for_host(trans->host, trans->url)) {
01491         host = proxy_hostname;
01492         port = proxy_port;
01493         ssl = proxy_ssl;
01494     } else {
01495         host = trans->host;
01496         port = trans->port;
01497         ssl = trans->ssl;
01498     }
01499 
01500     conn = conn_pool_get(host, port, ssl, trans->certkeyfile,
01501                          http_interface);
01502     if (conn == NULL)
01503         goto error;
01504 
01505     return conn;
01506 
01507 error:
01508     conn_destroy(conn);
01509     error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
01510     return NULL;
01511 }
01512 
01513 
01514 /*
01515  * Build and send the HTTP request. Return 0 for success or -1 for error.
01516  */
01517 static int send_request(HTTPServer *trans)
01518 {
01519     char buf[128];    
01520     Octstr *request = NULL;
01521 
01522     if (trans->method == HTTP_METHOD_POST) {
01523         /* 
01524          * Add a Content-Length header.  Override an existing one, if
01525          * necessary.  We must have an accurate one in order to use the
01526          * connection for more than a single request.
01527          */
01528         http_header_remove_all(trans->request_headers, "Content-Length");
01529         snprintf(buf, sizeof(buf), "%ld", octstr_len(trans->request_body));
01530         http_header_add(trans->request_headers, "Content-Length", buf);
01531     } 
01532     /* 
01533      * ok, this has to be an GET or HEAD request method then,
01534      * if it contains a body, then this is not HTTP conform, so at
01535      * least warn the user 
01536      */
01537     else if (trans->request_body != NULL) {
01538         warning(0, "HTTP: GET or HEAD method request contains body:");
01539         octstr_dump(trans->request_body, 0);
01540     }
01541 
01542     /* 
01543      * we have to assume all values in trans are already set
01544      * by parse_url() before calling this.
01545      */
01546 
01547     if (trans->username != NULL)
01548         http_add_basic_auth(trans->request_headers, trans->username,
01549                             trans->password);
01550 
01551     if (proxy_used_for_host(trans->host, trans->url)) {
01552         proxy_add_authentication(trans->request_headers);
01553         request = build_request(http_method2name(trans->method),
01554                                 trans->url, trans->host, trans->port, 
01555                                 trans->request_headers, 
01556                                 trans->request_body);
01557     } else {
01558         request = build_request(http_method2name(trans->method), trans->uri, 
01559                                 trans->host, trans->port,
01560                                 trans->request_headers,
01561                                 trans->request_body);
01562     }
01563   
01564     debug("gwlib.http", 0, "HTTP: Sending request:");
01565     octstr_dump(request, 0);
01566     if (conn_write(trans->conn, request) == -1)
01567         goto error;
01568 
01569     octstr_destroy(request);
01570 
01571     return 0;
01572 
01573 error:
01574     conn_destroy(trans->conn);
01575     trans->conn = NULL;
01576     octstr_destroy(request);
01577     error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
01578     return -1;
01579 }
01580 
01581 
01582 /*
01583  * This thread starts the transaction: it connects to the server and sends
01584  * the request. It then sends the transaction to the read_response_thread
01585  * via started_requests_queue.
01586  */
01587 static void write_request_thread(void *arg)
01588 {
01589     HTTPServer *trans;
01590     int rc;
01591 
01592     while (run_status == running) {
01593         trans = gwlist_consume(pending_requests);
01594         if (trans == NULL)
01595             break;
01596 
01597         gw_assert(trans->state == request_not_sent);
01598 
01599         debug("gwlib.http", 0, "Queue contains %ld pending requests.", gwlist_len(pending_requests));
01600 
01601         /* 
01602          * get the connection to use
01603          * also calls parse_url() to populate the trans values
01604          */
01605         trans->conn = get_connection(trans);
01606 
01607         if (trans->conn == NULL)
01608             gwlist_produce(trans->caller, trans);
01609         else if (conn_is_connected(trans->conn) == 0) {
01610             debug("gwlib.http", 0, "Socket connected at once");
01611 
01612             if ((rc = send_request(trans)) == 0) {
01613                 trans->state = reading_status;
01614                 conn_register(trans->conn, client_fdset, handle_transaction, 
01615                                 trans);
01616             } else {
01617                 gwlist_produce(trans->caller, trans);
01618             }
01619 
01620         } else { /* Socket not connected, wait for connection */
01621             debug("gwlib.http", 0, "Socket connecting");
01622             trans->state = connecting;
01623             conn_register(trans->conn, client_fdset, handle_transaction, trans);
01624         }
01625     }
01626 }
01627 
01628 
01629 static void start_client_threads(void)
01630 {
01631     if (!client_threads_are_running) {
01632     /* 
01633      * To be really certain, we must repeat the test, but use the
01634      * lock first. If the test failed, however, we _know_ we've
01635      * already initialized. This strategy of double testing avoids
01636      * using the lock more than a few times at startup.
01637      */
01638     mutex_lock(client_thread_lock);
01639     if (!client_threads_are_running) {
01640         client_fdset = fdset_create_real(http_client_timeout);
01641         if (gwthread_create(write_request_thread, NULL) == -1) {
01642                 error(0, "HTTP: Could not start client write_request thread.");
01643                 fdset_destroy(client_fdset);
01644                 client_threads_are_running = 0;
01645             } else
01646                 client_threads_are_running = 1;
01647     }
01648     mutex_unlock(client_thread_lock);
01649     }
01650 }
01651 
01652 void http_set_interface(const Octstr *our_host)
01653 {
01654     http_interface = octstr_duplicate(our_host);
01655 }
01656 
01657 void http_set_client_timeout(long timeout)
01658 {
01659     http_client_timeout = timeout;
01660     if (client_fdset != NULL) {
01661         /* we are already initialized set timeout in fdset */
01662         fdset_set_timeout(client_fdset, http_client_timeout);
01663     }
01664 }
01665 
01666 void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers,
01667                         Octstr *body, int follow, void *id, Octstr *certkeyfile)
01668 {
01669     HTTPServer *trans;
01670     int follow_remaining;
01671     
01672     if (follow)
01673         follow_remaining = HTTP_MAX_FOLLOW;
01674     else
01675         follow_remaining = 0;
01676 
01677     trans = server_create(caller, method, url, headers, body, follow_remaining, 
01678               certkeyfile);
01679 
01680     if (id == NULL)
01681         /* We don't leave this NULL so http_receive_result can use NULL
01682          * to signal no more requests */
01683         trans->request_id = http_start_request;
01684     else
01685         trans->request_id = id;
01686         
01687     gwlist_produce(pending_requests, trans);
01688     start_client_threads();
01689 }
01690 
01691 
01692 void *http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url,
01693                          List **headers, Octstr **body, int blocking)
01694 {
01695     HTTPServer *trans;
01696     void *request_id;
01697 
01698     if (blocking == 0)
01699         trans = gwlist_extract_first(caller);
01700     else
01701         trans = gwlist_consume(caller);
01702     if (trans == NULL)
01703         return NULL;
01704 
01705     request_id = trans->request_id;
01706     *status = trans->status;
01707     
01708     if (trans->status >= 0) {
01709         *final_url = trans->url;
01710         *headers = trans->response->headers;
01711         *body = trans->response->body;
01712 
01713         trans->url = NULL;
01714         trans->response->headers = NULL;
01715         trans->response->body = NULL;
01716     } else {
01717        *final_url = NULL;
01718        *headers = NULL;
01719        *body = NULL;
01720     }
01721 
01722     server_destroy(trans);
01723     return request_id;
01724 }
01725 
01726 
01727 int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url,
01728                   List **reply_headers, Octstr **reply_body)
01729 {
01730     HTTPCaller *caller;
01731     int status;
01732     void *ret;
01733     
01734     caller = http_caller_create();
01735     http_start_request(caller, method, url, request_headers, 
01736                        NULL, 1, http_get_real, NULL);
01737     ret = http_receive_result(caller, &status, final_url, 
01738                               reply_headers, reply_body);
01739     http_caller_destroy(caller);
01740     if (ret == NULL)
01741         return -1;
01742     return status;
01743 }
01744 
01745 
01746 static void client_init(void)
01747 {
01748     pending_requests = gwlist_create();
01749     gwlist_add_producer(pending_requests);
01750     client_thread_lock = mutex_create();
01751 }
01752 
01753 
01754 static void client_shutdown(void)
01755 {
01756     gwlist_remove_producer(pending_requests);
01757     gwthread_join_every(write_request_thread);
01758     client_threads_are_running = 0;
01759     gwlist_destroy(pending_requests, server_destroy);
01760     mutex_destroy(client_thread_lock);
01761     fdset_destroy(client_fdset);
01762     client_fdset = NULL;
01763     octstr_destroy(http_interface);
01764     http_interface = NULL;
01765 }
01766 
01767 
01768 /***********************************************************************
01769  * HTTP server interface.
01770  */
01771 
01772 
01773 /*
01774  * Information about a client that has connected to the server we implement.
01775  */
01776 struct HTTPClient {
01777     int port;
01778     Connection *conn;
01779     Octstr *ip;
01780     enum {
01781         reading_request_line,
01782         reading_request,
01783         request_is_being_handled,
01784         sending_reply
01785     } state;
01786     int method;  /* HTTP_METHOD_ value */
01787     Octstr *url;
01788     int use_version_1_0;
01789     int persistent_conn;
01790     unsigned long conn_time; /* store time for timeouting */
01791     HTTPEntity *request;
01792 };
01793 
01794 
01795 /* List with all active HTTPClient's */
01796 static List *active_connections;
01797 
01798 
01799 static HTTPClient *client_create(int port, Connection *conn, Octstr *ip)
01800 {
01801     HTTPClient *p;
01802     
01803 #ifdef HAVE_LIBSSL
01804     if (conn_get_ssl(conn)) 
01805         debug("gwlib.http", 0, "HTTP: Creating SSL-enabled HTTPClient for `%s', using cipher '%s'.",
01806               octstr_get_cstr(ip), SSL_get_cipher_version(conn_get_ssl(conn)));
01807     else
01808 #endif    
01809         debug("gwlib.http", 0, "HTTP: Creating HTTPClient for `%s'.", octstr_get_cstr(ip));
01810     p = gw_malloc(sizeof(*p));
01811     p->port = port;
01812     p->conn = conn;
01813     p->ip = ip;
01814     p->state = reading_request_line;
01815     p->url = NULL;
01816     p->use_version_1_0 = 0;
01817     p->persistent_conn = 1;
01818     p->conn_time = time(NULL);
01819     p->request = NULL;
01820     debug("gwlib.http", 0, "HTTP: Created HTTPClient area %p.", p);
01821     
01822     /* add this client to active_connections */
01823     gwlist_produce(active_connections, p);
01824     
01825     return p;
01826 }
01827 
01828 
01829 static void client_destroy(void *client)
01830 {
01831     HTTPClient *p;
01832     
01833     if (client == NULL)
01834         return;
01835 
01836     p = client;
01837     
01838     /* drop this client from active_connections list */
01839     gwlist_lock(active_connections);
01840     if (gwlist_delete_equal(active_connections, p) != 1)
01841         panic(0, "HTTP: Race condition in client_destroy(%p) detected!", client);
01842     gwlist_unlock(active_connections);
01843     
01844     debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p);
01845     gw_assert_allocated(p, __FILE__, __LINE__, __func__);
01846     debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.",
01847           octstr_get_cstr(p->ip));
01848     
01849     conn_destroy(p->conn);
01850     octstr_destroy(p->ip);
01851     octstr_destroy(p->url);
01852     entity_destroy(p->request);
01853     gw_free(p);
01854 }
01855 
01856 
01857 static void client_reset(HTTPClient *p)
01858 {
01859     debug("gwlib.http", 0, "HTTP: Resetting HTTPClient for `%s'.",
01860           octstr_get_cstr(p->ip));
01861     p->state = reading_request_line;
01862     p->conn_time = time(NULL);
01863     gw_assert(p->request == NULL);
01864 }
01865 
01866 
01867 /*
01868  * Checks whether the client connection is meant to be persistent or not.
01869  * Returns 1 for true, 0 for false.
01870  */
01871 
01872 static int client_is_persistent(List *headers, int use_version_1_0)
01873 {
01874     Octstr *h = http_header_find_first(headers, "Connection");
01875 
01876     if (h == NULL) {
01877         return !use_version_1_0;
01878     } else {
01879         if (!use_version_1_0) {
01880             if (octstr_case_compare(h, octstr_imm("keep-alive")) == 0) {
01881                 octstr_destroy(h);
01882                 return 1;
01883             } else {
01884                 octstr_destroy(h);
01885                 return 0;
01886             }
01887         } else if (octstr_case_compare(h, octstr_imm("close")) == 0) {
01888             octstr_destroy(h);
01889             return 0;
01890         }
01891         octstr_destroy(h);
01892     }
01893 
01894     return 1;
01895 }
01896 
01897 
01898 /*
01899  * Port specific lists of clients with requests.
01900  */
01901 struct port {
01902     List *clients_with_requests;
01903     Counter *active_consumers;
01904 };
01905 
01906 
01907 static Mutex *port_mutex = NULL;
01908 static Dict *port_collection = NULL;
01909 
01910 
01911 static int port_match(void *client, void *port)
01912 {
01913     return ((HTTPClient*)client)->port == *((int*)port);
01914 }
01915 
01916 
01917 static void port_init(void)
01918 {
01919     port_mutex = mutex_create();
01920     port_collection = dict_create(1024, NULL);
01921     /* create list with all active_connections */
01922     active_connections = gwlist_create();
01923 }
01924 
01925 static void port_shutdown(void)
01926 {
01927     mutex_destroy(port_mutex);
01928     dict_destroy(port_collection);
01929     /* destroy active_connections list */
01930     gwlist_destroy(active_connections, client_destroy);
01931 }
01932 
01933 
01934 static Octstr *port_key(int port)
01935 {
01936     return octstr_format("%d", port);
01937 }
01938 
01939 
01940 static void port_add(int port)
01941 {
01942     Octstr *key;
01943     struct port *p;
01944 
01945     key = port_key(port);
01946     mutex_lock(port_mutex);
01947     if ((p = dict_get(port_collection, key)) == NULL) {
01948         p = gw_malloc(sizeof(*p));
01949         p->clients_with_requests = gwlist_create();
01950         gwlist_add_producer(p->clients_with_requests);
01951         p->active_consumers = counter_create();
01952         dict_put(port_collection, key, p);
01953     } else {
01954         warning(0, "HTTP: port_add called for existing port (%d)", port);
01955     }
01956     mutex_unlock(port_mutex);
01957     octstr_destroy(key);
01958 }
01959 
01960 
01961 static void port_remove(int port)
01962 {
01963     Octstr *key;
01964     struct port *p;
01965     List *l;
01966     HTTPClient *client;
01967 
01968     key = port_key(port);
01969     mutex_lock(port_mutex);
01970     p = dict_remove(port_collection, key);
01971     mutex_unlock(port_mutex);
01972     octstr_destroy(key);
01973     
01974     if (p == NULL) {
01975         error(0, "HTTP: Could not find port (%d) in port_collection.", port);
01976         return;
01977     }
01978 
01979     gwlist_remove_producer(p->clients_with_requests);
01980     while (counter_value(p->active_consumers) > 0)
01981        gwthread_sleep(0.1);    /* Reasonable use of busy waiting. */
01982     gwlist_destroy(p->clients_with_requests, client_destroy);
01983     counter_destroy(p->active_consumers);
01984     gw_free(p);
01985 
01986     /*
01987      * In order to avoid race conditions with FDSet thread, we
01988      * destroy Clients for this port in two steps:
01989      * 1) unregister from fdset with gwlist_lock held, so client_destroy
01990      *    cannot destroy our client that we currently use
01991      * 2) without gwlist_lock held destroy every client, we can do this
01992      *    because we only one thread that can use this client struct
01993      */
01994     gwlist_lock(active_connections);
01995     l = gwlist_search_all(active_connections, &port, port_match);
01996     while(l != NULL && (client = gwlist_extract_first(l)) != NULL)
01997         conn_unregister(client->conn);
01998     gwlist_unlock(active_connections);
01999     gwlist_destroy(l, NULL);
02000     while((client = gwlist_search(active_connections, &port, port_match)) != NULL)
02001         client_destroy(client);
02002 }
02003 
02004 
02005 static void port_put_request(HTTPClient *client)
02006 {
02007     Octstr *key;
02008     struct port *p;
02009 
02010     mutex_lock(port_mutex);
02011     key = port_key(client->port);
02012     p = dict_get(port_collection, key);
02013     octstr_destroy(key);
02014     if (p == NULL) {
02015         /* client was too slow and we closed port already */
02016         mutex_unlock(port_mutex);
02017         client_destroy(client);
02018         return;
02019     }
02020     gwlist_produce(p->clients_with_requests, client);
02021     mutex_unlock(port_mutex);
02022 }
02023 
02024 
02025 static HTTPClient *port_get_request(int port)
02026 {
02027     Octstr *key;
02028     struct port *p;
02029     HTTPClient *client;
02030     
02031     mutex_lock(port_mutex);
02032     key = port_key(port);
02033     p = dict_get(port_collection, key);
02034     octstr_destroy(key);
02035 
02036     if (p == NULL) {
02037        client = NULL;
02038        mutex_unlock(port_mutex);
02039     } else {
02040        counter_increase(p->active_consumers);
02041        mutex_unlock(port_mutex);   /* Placement of this unlock is tricky. */
02042        client = gwlist_consume(p->clients_with_requests);
02043        counter_decrease(p->active_consumers);
02044     }
02045     return client;
02046 }
02047 
02048 
02049 /*
02050  * Maximum number of servers (ports) we have open at the same time.
02051  */
02052 #define MAX_SERVERS 32
02053 
02054 
02055 /*
02056  * Variables related to server side implementation.
02057  */
02058 static Mutex *server_thread_lock = NULL;
02059 static volatile sig_atomic_t server_thread_is_running = 0;
02060 static long server_thread_id = -1;
02061 static FDSet *server_fdset = NULL;
02062 static List *new_server_sockets = NULL;
02063 static List *closed_server_sockets = NULL;
02064 static int keep_servers_open = 0;
02065 
02066 
02067 static int parse_request_line(int *method, Octstr **url,
02068                               int *use_version_1_0, Octstr *line)
02069 {
02070     List *words;
02071     Octstr *version;
02072     Octstr *method_str;
02073     int ret;
02074 
02075     words = octstr_split_words(line);
02076     if (gwlist_len(words) != 3) {
02077         gwlist_destroy(words, octstr_destroy_item);
02078     return -1;
02079     }
02080 
02081     method_str = gwlist_get(words, 0);
02082     *url = gwlist_get(words, 1);
02083     version = gwlist_get(words, 2);
02084     gwlist_destroy(words, NULL);
02085 
02086     if (octstr_compare(method_str, octstr_imm("GET")) == 0)
02087     *method = HTTP_METHOD_GET;
02088     else if (octstr_compare(method_str, octstr_imm("POST")) == 0)
02089     *method = HTTP_METHOD_POST;
02090     else if (octstr_compare(method_str, octstr_imm("HEAD")) == 0)
02091     *method = HTTP_METHOD_HEAD;
02092     else
02093         goto error;
02094 
02095     ret = parse_http_version(version);
02096     if (ret < 0)
02097         goto error;
02098     *use_version_1_0 = !ret;
02099 
02100     octstr_destroy(method_str);
02101     octstr_destroy(version);
02102     return 0;
02103 
02104 error:
02105     octstr_destroy(method_str);
02106     octstr_destroy(*url);
02107     octstr_destroy(version);
02108     *url = NULL;
02109     return -1;
02110 }
02111 
02112 
02113 static void receive_request(Connection *conn, void *data)
02114 {
02115     HTTPClient *client;
02116     Octstr *line;
02117     int ret;
02118 
02119     if (run_status != running) {
02120     conn_unregister(conn);
02121     return;
02122     }
02123 
02124     client = data;
02125     
02126     for (;;) {
02127     switch (client->state) {
02128     case reading_request_line:
02129             line = conn_read_line(conn);
02130         if (line == NULL) {
02131         if (conn_eof(conn) || conn_error(conn))
02132             goto error;
02133             return;
02134         }
02135         ret = parse_request_line(&client->method, &client->url,
02136                                      &client->use_version_1_0, line);
02137         octstr_destroy(line);
02138             /* client sent bad request? */
02139         if (ret == -1) {
02140                 /*
02141                  * mark client as not persistent in order to destroy connection
02142                  * afterwards
02143                  */
02144                 client->persistent_conn = 0;
02145                 /* unregister connection, http_send_reply handle this */
02146                 conn_unregister(conn);
02147                 http_send_reply(client, HTTP_BAD_REQUEST, NULL, NULL);
02148                 return;
02149             }
02150         /*
02151          * RFC2616 (4.3) says we should read a message body if there
02152          * is one, even on GET requests.
02153          */
02154         client->request = entity_create(expect_body_if_indicated);
02155         client->state = reading_request;
02156         break;
02157         
02158     case reading_request:
02159         ret = entity_read(client->request, conn);
02160         if (ret < 0)
02161         goto error;
02162         if (ret == 0) {
02163             client->state = request_is_being_handled;
02164         conn_unregister(conn);
02165         port_put_request(client);
02166         }
02167         return;
02168 
02169     case sending_reply:
02170             /* Implicit conn_unregister() and _destroy */
02171             if (conn_error(conn))
02172                 goto error;
02173         if (conn_outbuf_len(conn) > 0)
02174                 return;
02175         /* Reply has been sent completely */
02176         if (!client->persistent_conn) {
02177                 /*
02178                  * in order to avoid race conditions while conn will be destroyed but
02179                  * conn is still in use, we call conn_unregister explicit here because
02180                  * conn_unregister call uses locks
02181                  */
02182                 conn_unregister(conn);
02183                 client_destroy(client);
02184                 return;
02185         }
02186         /* Start reading another request */
02187         client_reset(client);
02188         break;
02189 
02190         default:
02191         panic(0, "Internal error: HTTPClient state is wrong.");
02192     }
02193     }
02194     
02195 error:
02196     /*
02197      * in order to avoid race conditions while conn will be destroyed but
02198      * conn is still in use, we call conn_unregister explicit here because
02199      * conn_unregister call uses locks
02200      */
02201     conn_unregister(conn);
02202     client_destroy(client);
02203 }
02204 
02205 
02206 struct server {
02207     int fd;
02208     int port;
02209     int ssl;
02210 };
02211 
02212 
02213 static void server_thread(void *dummy)
02214 {
02215     struct pollfd tab[MAX_SERVERS];
02216     int ports[MAX_SERVERS];
02217     int ssl[MAX_SERVERS];
02218     long i, j, n, fd;
02219     int *portno;
02220     struct server *p;
02221     struct sockaddr_in addr;
02222     socklen_t addrlen;
02223     Connection *conn;
02224     HTTPClient *client;
02225     int ret;
02226 
02227     n = 0;
02228     while (run_status == running && keep_servers_open) {
02229 
02230         if (n == 0 || (n < MAX_SERVERS && gwlist_len(new_server_sockets) > 0)) {
02231             p = gwlist_consume(new_server_sockets);
02232             if (p == NULL) {
02233                 debug("gwlib.http", 0, "HTTP: No new servers. Quitting.");
02234                 break;
02235             }
02236             tab[n].fd = p->fd;
02237             tab[n].events = POLLIN;
02238             ports[n] = p->port;
02239             ssl[n] = p->ssl;
02240             ++n;
02241             gw_free(p);
02242         }
02243 
02244         if ((ret = gwthread_poll(tab, n, -1.0)) == -1) {
02245             if (errno != EINTR) /* a signal was caught during poll() function */
02246                 warning(errno, "HTTP: gwthread_poll failed.");
02247             continue;
02248         }
02249 
02250         for (i = 0; i < n; ++i) {
02251             if (tab[i].revents & POLLIN) {
02252                 addrlen = sizeof(addr);
02253                 fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen);
02254                 if (fd == -1) {
02255                     error(errno, "HTTP: Error accepting a client.");
02256                 } else {
02257                     Octstr *client_ip = host_ip(addr);
02258                     /*
02259                      * Be aware that conn_wrap_fd() will return NULL if SSL 
02260                      * handshake has failed, so we only client_create() if
02261                      * there is an conn.
02262                      */             
02263                     if ((conn = conn_wrap_fd(fd, ssl[i]))) {
02264                         client = client_create(ports[i], conn, client_ip);
02265                         conn_register(conn, server_fdset, receive_request, client);
02266                     } else {
02267                         error(0, "HTTP: unsuccessful SSL handshake for client `%s'",
02268                         octstr_get_cstr(client_ip));
02269                         octstr_destroy(client_ip);
02270                     }
02271                 }
02272             }
02273         }
02274 
02275         while ((portno = gwlist_extract_first(closed_server_sockets)) != NULL) {
02276             for (i = 0; i < n; ++i) {
02277                 if (ports[i] == *portno) {
02278                     (void) close(tab[i].fd);
02279                     port_remove(ports[i]);
02280                     tab[i].fd = -1;
02281                     ports[i] = -1;
02282                     ssl[i] = 0;
02283                 }
02284             }
02285             gw_free(portno);
02286         }
02287         
02288         j = 0;
02289         for (i = 0; i < n; ++i) {
02290             if (tab[i].fd != -1) {
02291                 tab[j] = tab[i];
02292                 ports[j] = ports[i];
02293                 ssl[j] = ssl[i];
02294                 ++j;
02295             }
02296         }
02297         n = j;
02298     }
02299     
02300     /* make sure we close all ports */
02301     for (i = 0; i < n; ++i) {
02302         (void) close(tab[i].fd);
02303         port_remove(ports[i]);
02304     }
02305 
02306     server_thread_id = -1;
02307 }
02308 
02309 
02310 static void start_server_thread(void)
02311 {
02312     if (!server_thread_is_running) {
02313     /* 
02314      * To be really certain, we must repeat the test, but use the
02315      * lock first. If the test failed, however, we _know_ we've
02316      * already initialized. This strategy of double testing avoids
02317      * using the lock more than a few times at startup.
02318      */
02319     mutex_lock(server_thread_lock);
02320     if (!server_thread_is_running) {
02321         server_fdset = fdset_create_real(HTTP_SERVER_TIMEOUT);
02322         server_thread_id = gwthread_create(server_thread, NULL);
02323         server_thread_is_running = 1;
02324     }
02325     mutex_unlock(server_thread_lock);
02326     }
02327 }
02328 
02329 
02330 int http_open_port_if(int port, int ssl, Octstr *interface)
02331 {
02332     struct server *p;
02333 
02334     if (ssl) 
02335         info(0, "HTTP: Opening SSL server at port %d.", port);
02336     else 
02337         info(0, "HTTP: Opening server at port %d.", port);
02338     p = gw_malloc(sizeof(*p));
02339     p->port = port;
02340     p->ssl = ssl;
02341     p->fd = make_server_socket(port, (interface ? octstr_get_cstr(interface) : NULL));
02342     if (p->fd == -1) {
02343     gw_free(p);
02344         return -1;
02345     }
02346 
02347     port_add(port);
02348     gwlist_produce(new_server_sockets, p);
02349     keep_servers_open = 1;
02350     start_server_thread();
02351     gwthread_wakeup(server_thread_id);
02352 
02353     return 0;
02354 }
02355 
02356 
02357 int http_open_port(int port, int ssl)
02358 {
02359     return http_open_port_if(port, ssl, NULL);
02360 }
02361 
02362 
02363 void http_close_port(int port)
02364 {
02365     int *p;
02366     
02367     p = gw_malloc(sizeof(*p));
02368     *p = port;
02369     gwlist_produce(closed_server_sockets, p);
02370     gwthread_wakeup(server_thread_id);
02371 }
02372 
02373 
02374 void http_close_all_ports(void)
02375 {
02376     if (server_thread_id != -1) {
02377         keep_servers_open = 0;
02378         gwthread_wakeup(server_thread_id);
02379         gwthread_join_every(server_thread);
02380         server_thread_is_running = 0;
02381         fdset_destroy(server_fdset);
02382         server_fdset = NULL;
02383     }
02384 }
02385 
02386 
02387 /*
02388  * Parse CGI variables from the path given in a GET. Return a list
02389  * of HTTPCGIvar pointers. Modify the url so that the variables are
02390  * removed.
02391  */
02392 static List *parse_cgivars(Octstr *url)
02393 {
02394     HTTPCGIVar *v;
02395     List *list;
02396     int query, et, equals;
02397     Octstr *arg, *args;
02398 
02399     query = octstr_search_char(url, '?', 0);
02400     if (query == -1)
02401         return gwlist_create();
02402 
02403     args = octstr_copy(url, query + 1, octstr_len(url));
02404     octstr_truncate(url, query);
02405 
02406     list = gwlist_create();
02407 
02408     while (octstr_len(args) > 0) {
02409         et = octstr_search_char(args, '&', 0);
02410         if (et == -1)
02411             et = octstr_len(args);
02412         arg = octstr_copy(args, 0, et);
02413         octstr_delete(args, 0, et + 1);
02414 
02415         equals = octstr_search_char(arg, '=', 0);
02416         if (equals == -1)
02417             equals = octstr_len(arg);
02418 
02419         v = gw_malloc(sizeof(HTTPCGIVar));
02420         v->name = octstr_copy(arg, 0, equals);
02421         v->value = octstr_copy(arg, equals + 1, octstr_len(arg));
02422         octstr_url_decode(v->name);
02423         octstr_url_decode(v->value);
02424 
02425         octstr_destroy(arg);
02426 
02427         gwlist_append(list, v);
02428     }
02429     octstr_destroy(args);
02430 
02431     return list;
02432 }
02433 
02434 
02435 HTTPClient *http_accept_request(int port, Octstr **client_ip, Octstr **url, 
02436                                 List **headers, Octstr **body, 
02437                 List **cgivars)
02438 {
02439     HTTPClient *client;
02440 
02441     do {
02442         client = port_get_request(port);
02443         if (client == NULL) {
02444             debug("gwlib.http", 0, "HTTP: No clients with requests, quitting.");
02445             return NULL;
02446         }
02447         /* check whether client connection still ok */
02448         conn_wait(client->conn, 0);
02449         if (conn_error(client->conn) || conn_eof(client->conn)) {
02450             client_destroy(client);
02451             client = NULL;
02452         }
02453     } while(client == NULL);
02454 
02455     *client_ip = octstr_duplicate(client->ip);
02456     *url = client->url;
02457     *headers = client->request->headers;
02458     *body = client->request->body;
02459     *cgivars = parse_cgivars(client->url);
02460 
02461     if (client->method != HTTP_METHOD_POST) {
02462     octstr_destroy(*body);
02463     *body = NULL;
02464     }
02465 
02466     client->persistent_conn = client_is_persistent(client->request->headers,
02467                            client->use_version_1_0);
02468     
02469     client->url = NULL;
02470     client->request->headers = NULL;
02471     client->request->body = NULL;
02472     entity_destroy(client->request);
02473     client->request = NULL;
02474 
02475     return client;
02476 }
02477 
02478 /*
02479  * The http_send_reply(...) uses this function to determinate the
02480  * reason pahrase for a status code.
02481  */
02482 static const char *http_reason_phrase(int status)
02483 {
02484     switch (status) {
02485     case HTTP_OK:
02486         return "OK";                        /* 200 */
02487     case HTTP_CREATED:                   
02488         return "Created";                   /* 201 */
02489     case HTTP_ACCEPTED:
02490         return "Accepted";                  /* 202 */
02491     case HTTP_NO_CONTENT:
02492         return "No Content";                /* 204 */
02493     case HTTP_RESET_CONTENT: 
02494         return "Reset Content";             /* 205 */
02495     case HTTP_MOVED_PERMANENTLY:
02496         return "Moved Permanently";         /* 301 */
02497     case HTTP_FOUND:
02498         return "Found";                     /* 302 */
02499     case HTTP_SEE_OTHER:
02500         return "See Other";                 /* 303 */
02501     case HTTP_NOT_MODIFIED:
02502         return "Not Modified";              /* 304 */
02503     case HTTP_TEMPORARY_REDIRECT:
02504         return "Temporary Redirect";        /* 307 */
02505     case HTTP_BAD_REQUEST:
02506         return "Bad Request";               /* 400 */
02507     case HTTP_UNAUTHORIZED:
02508         return "Unauthorized";              /* 401 */
02509     case HTTP_FORBIDDEN:
02510         return "Forbidden";                 /* 403 */
02511     case HTTP_NOT_FOUND:            
02512         return "Not Found";                 /* 404 */
02513     case HTTP_BAD_METHOD:
02514         return "Method Not Allowed";        /* 405 */
02515     case HTTP_NOT_ACCEPTABLE:
02516         return "Not Acceptable";            /* 406 */
02517     case HTTP_REQUEST_ENTITY_TOO_LARGE:
02518         return "Request Entity Too Large";  /* 413 */
02519     case HTTP_UNSUPPORTED_MEDIA_TYPE:
02520         return "Unsupported Media Type";    /* 415 */
02521     case HTTP_INTERNAL_SERVER_ERROR:
02522         return "Internal Server Error";     /* 500 */
02523     case HTTP_NOT_IMPLEMENTED:
02524         return "Not Implemented";           /* 501 */
02525     case HTTP_BAD_GATEWAY:
02526         return "Bad Gateway";               /* 502 */
02527     }
02528     return "Foo";
02529 }
02530 
02531 
02532 void http_send_reply(HTTPClient *client, int status, List *headers, 
02533                      Octstr *body)
02534 {
02535     Octstr *response;
02536     Octstr *date;
02537     long i;
02538     int ret;
02539 
02540     if (client->use_version_1_0)
02541         response = octstr_format("HTTP/1.0 %d %s\r\n", status, http_reason_phrase(status));
02542     else
02543         response = octstr_format("HTTP/1.1 %d %s\r\n", status, http_reason_phrase(status));
02544 
02545     /* identify ourselfs */
02546     octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION);
02547     
02548     /* let's inform the client of our time */
02549     date = date_format_http(time(NULL));
02550     octstr_format_append(response, "Date: %s\r\n", octstr_get_cstr(date));
02551     octstr_destroy(date);
02552     
02553     octstr_format_append(response, "Content-Length: %ld\r\n",
02554              octstr_len(body));
02555 
02556     /* 
02557      * RFC2616, sec. 8.1.2.1 says that if the server chooses to close the 
02558      * connection, it *should* send a coresponding header
02559      */
02560     if (!client->use_version_1_0 && !client->persistent_conn)
02561         octstr_format_append(response, "Connection: close\r\n");
02562 
02563     for (i = 0; i < gwlist_len(headers); ++i)
02564         octstr_format_append(response, "%S\r\n", gwlist_get(headers, i));
02565     octstr_format_append(response, "\r\n");
02566     
02567     if (body != NULL && client->method != HTTP_METHOD_HEAD)
02568         octstr_append(response, body);
02569     
02570     ret = conn_write(client->conn, response);
02571     octstr_destroy(response);
02572 
02573     /* obey return code of conn_write() */
02574     /* sending response was successful */
02575     if (ret == 0) { 
02576         /* HTTP/1.0 or 1.1, hence keep-alive or keep-alive */
02577         if (!client->persistent_conn) {
02578             client_destroy(client);     
02579         } else {
02580             /* XXX mark this HTTPClient in the keep-alive cleaner thread */
02581             client_reset(client);
02582             conn_register(client->conn, server_fdset, receive_request, client);
02583         }
02584     }
02585     /* queued for sending, we don't want to block */
02586     else if (ret == 1) {    
02587         client->state = sending_reply;
02588         conn_register(client->conn, server_fdset, receive_request, client);
02589     }
02590     /* error while sending response */
02591     else {     
02592         client_destroy(client);
02593     }
02594 }
02595 
02596 
02597 void http_close_client(HTTPClient *client)
02598 {
02599     client_destroy(client);
02600 }
02601 
02602 
02603 static void server_init(void)
02604 {
02605     new_server_sockets = gwlist_create();
02606     gwlist_add_producer(new_server_sockets);
02607     closed_server_sockets = gwlist_create();
02608     server_thread_lock = mutex_create();
02609 }
02610 
02611 
02612 static void destroy_struct_server(void *p)
02613 {
02614     struct server *pp;
02615     
02616     pp = p;
02617     (void) close(pp->fd);
02618     gw_free(pp);
02619 }
02620 
02621 
02622 static void destroy_int_pointer(void *p)
02623 {
02624     (void) close(*(int *) p);
02625     gw_free(p);
02626 }
02627 
02628 
02629 static void server_shutdown(void)
02630 {
02631     gwlist_remove_producer(new_server_sockets);
02632     if (server_thread_id != -1) {
02633         gwthread_wakeup(server_thread_id);
02634         gwthread_join_every(server_thread);
02635         server_thread_is_running = 0;
02636     }
02637     mutex_destroy(server_thread_lock);
02638     fdset_destroy(server_fdset);
02639     server_fdset = NULL;
02640     gwlist_destroy(new_server_sockets, destroy_struct_server);
02641     gwlist_destroy(closed_server_sockets, destroy_int_pointer);
02642 }
02643 
02644 
02645 /***********************************************************************
02646  * CGI variable manipulation.
02647  */
02648 
02649 
02650 void http_destroy_cgiargs(List *args)
02651 {
02652     HTTPCGIVar *v;
02653 
02654     gwlib_assert_init();
02655 
02656     if (args == NULL)
02657         return ;
02658 
02659     while ((v = gwlist_extract_first(args)) != NULL) {
02660         octstr_destroy(v->name);
02661         octstr_destroy(v->value);
02662         gw_free(v);
02663     }
02664     gwlist_destroy(args, NULL);
02665 }
02666 
02667 
02668 Octstr *http_cgi_variable(List *list, char *name)
02669 {
02670     int i;
02671     HTTPCGIVar *v;
02672 
02673     gwlib_assert_init();
02674     gw_assert(list != NULL);
02675     gw_assert(name != NULL);
02676 
02677     for (i = 0; i < gwlist_len(list); ++i) {
02678         v = gwlist_get(list, i);
02679         if (octstr_str_compare(v->name, name) == 0)
02680             return v->value;
02681     }
02682     return NULL;
02683 }
02684 
02685 
02686 /***********************************************************************
02687  * Header manipulation.
02688  */
02689 
02690 
02691 static int header_is_called(Octstr *header, char *name)
02692 {
02693     long colon;
02694 
02695     colon = octstr_search_char(header, ':', 0);
02696     if (colon == -1)
02697         return 0;
02698     if ((long) strlen(name) != colon)
02699         return 0;
02700     return strncasecmp(octstr_get_cstr(header), name, colon) == 0;
02701 }
02702 
02703 
02704 List *http_create_empty_headers(void)
02705 {
02706     gwlib_assert_init();
02707     return gwlist_create();
02708 }
02709 
02710 
02711 void http_destroy_headers(List *headers)
02712 {
02713     gwlib_assert_init();
02714     gwlist_destroy(headers, octstr_destroy_item);
02715 }
02716 
02717 
02718 void http_header_add(List *headers, char *name, char *contents)
02719 {
02720     gwlib_assert_init();
02721     gw_assert(headers != NULL);
02722     gw_assert(name != NULL);
02723     gw_assert(contents != NULL);
02724 
02725     gwlist_append(headers, octstr_format("%s: %s", name, contents));
02726 }
02727 
02728 
02729 /*
02730  * Given an headers list and a position, returns its header name and value,
02731  * or (X-Unknown, header) if it doesn't exist or if it's malformed - missing 
02732  * ":" for example
02733  */
02734 void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
02735 {
02736     Octstr *os;
02737     long colon;
02738 
02739     gwlib_assert_init();
02740     gw_assert(i >= 0);
02741     gw_assert(name != NULL);
02742     gw_assert(value != NULL);
02743 
02744     os = gwlist_get(headers, i);
02745     if (os == NULL)
02746         colon = -1;
02747     else
02748         colon = octstr_search_char(os, ':', 0);
02749     if (colon == -1) {
02750         error(0, "HTTP: Header does not contain a colon. BAD.");
02751         *name = octstr_create("X-Unknown");
02752         *value = octstr_duplicate(os);
02753     } else {
02754         *name = octstr_copy(os, 0, colon);
02755         *value = octstr_copy(os, colon + 1, octstr_len(os));
02756         octstr_strip_blanks(*value);
02757     }
02758 }
02759 
02760 /*
02761  * Given an headers list and a name, returns its value or NULL if it 
02762  * doesn't exist
02763  */
02764 Octstr *http_header_value(List *headers, Octstr *name)
02765 {
02766     Octstr *value;
02767     long i;
02768     Octstr *os;
02769     long colon;
02770     Octstr *current_name;
02771     
02772     gwlib_assert_init();
02773     gw_assert(name);
02774     
02775     value = NULL;
02776     i = 0;
02777     while (i < gwlist_len(headers)) {
02778         os = gwlist_get(headers, i);
02779         if (os == NULL)
02780             colon = -1;
02781         else
02782             colon = octstr_search_char(os, ':', 0);
02783         if (colon == -1) {
02784             return NULL;      
02785         } else {
02786             current_name = octstr_copy(os, 0, colon);
02787         }
02788         if (octstr_case_compare(current_name, name) == 0) {
02789             value = octstr_copy(os, colon + 1, octstr_len(os));
02790             octstr_strip_blanks(value);
02791             octstr_destroy(current_name);
02792             return value;
02793         }
02794         octstr_destroy(current_name);
02795         ++i;
02796     }
02797     
02798     return NULL;
02799 }
02800 
02801 List *http_header_duplicate(List *headers)
02802 {
02803     List *new;
02804     long i, len;
02805 
02806     gwlib_assert_init();
02807 
02808     if (headers == NULL)
02809         return NULL;
02810 
02811     new = http_create_empty_headers();
02812     len = gwlist_len(headers);
02813     for (i = 0; i < len; ++i)
02814         gwlist_append(new, octstr_duplicate(gwlist_get(headers, i)));
02815     return new;
02816 }
02817 
02818 
02819 #define MAX_HEADER_LENGTH 256
02820 /*
02821  * Aggregate header in one (or more) lines with several parameters separated
02822  * by commas, instead of one header per parameter
02823  */
02824 void http_header_pack(List *headers)
02825 {
02826     Octstr *name, *value;
02827     Octstr *name2, *value2;
02828     long i, j;
02829 
02830     gwlib_assert_init();
02831     gw_assert(headers != NULL);
02832 
02833     /*
02834      * For each header, search forward headers for similar ones and if possible, 
02835      * add it to current header and delete it
02836      */
02837     for(i = 0; i < gwlist_len(headers); i++) {
02838         http_header_get(headers, i, &name, &value);
02839     /* debug("http_header_pack", 0, "HTTP_HEADER_PACK: Processing header %d. [%s: %s]", 
02840            i, octstr_get_cstr(name), octstr_get_cstr(value)); */
02841 
02842         for(j=i+1; j < gwlist_len(headers); j++) {
02843             http_header_get(headers, j, &name2, &value2);
02844 
02845             if(octstr_case_compare(name, name2) == 0) {
02846                 if(octstr_len(value) + 2 + octstr_len(value2) > MAX_HEADER_LENGTH) {
02847             octstr_destroy(name2);
02848             octstr_destroy(value2);
02849                     break;
02850                 } else {
02851             Octstr *header;
02852 
02853             /* Delete old header */
02854             header = gwlist_get(headers, i);
02855             octstr_destroy(header);
02856                     gwlist_delete(headers, i, 1);
02857 
02858             /* Adds comma and new value to old header value */
02859                     octstr_append(value, octstr_imm(", "));
02860                     octstr_append(value, value2);
02861             /* Creates a new header */
02862             header = octstr_create("");
02863                     octstr_append(header, name);
02864                     octstr_append(header, octstr_imm(": "));
02865                     octstr_append(header, value);
02866                     gwlist_insert(headers, i, header);
02867 
02868             /* Delete this header */
02869             header = gwlist_get(headers, j);
02870             octstr_destroy(header);
02871                     gwlist_delete(headers, j, 1);
02872                     j--;
02873                 }
02874             }
02875         octstr_destroy(name2);
02876         octstr_destroy(value2);
02877         }
02878     octstr_destroy(name);
02879     octstr_destroy(value);
02880     }
02881 }
02882 
02883 
02884 void http_append_headers(List *to, List *from)
02885 {
02886     Octstr *header;
02887     long i;
02888 
02889     gwlib_assert_init();
02890     gw_assert(to != NULL);
02891     gw_assert(from != NULL);
02892 
02893     for (i = 0; i < gwlist_len(from); ++i) {
02894         header = gwlist_get(from, i);
02895         gwlist_append(to, octstr_duplicate(header));
02896     }
02897 }
02898 
02899 
02900 void http_header_combine(List *old_headers, List *new_headers)
02901 {
02902     long i;
02903     Octstr *name;
02904     Octstr *value;
02905 
02906     /*
02907      * Avoid doing this scan if old_headers is empty anyway.
02908      */
02909     if (gwlist_len(old_headers) > 0) {
02910         for (i = 0; i < gwlist_len(new_headers); i++) {
02911         http_header_get(new_headers, i, &name, &value);
02912         http_header_remove_all(old_headers, octstr_get_cstr(name));
02913             octstr_destroy(name);
02914             octstr_destroy(value);
02915         }
02916     }
02917 
02918     http_append_headers(old_headers, new_headers);
02919 }
02920 
02921 
02922 Octstr *http_header_find_first_real(List *headers, char *name, const char *file, long line,
02923                                     const char *func)
02924 {
02925     long i, name_len;
02926     Octstr *h, *value;
02927 
02928     gwlib_assert_init();
02929     gw_assert(headers != NULL);
02930     gw_assert(name != NULL);
02931 
02932     name_len = strlen(name);
02933 
02934     for (i = 0; i < gwlist_len(headers); ++i) {
02935         h = gwlist_get(headers, i);
02936         if (header_is_called(h, name)) {
02937             value = octstr_copy_real(h, name_len + 1, octstr_len(h),
02938                                      file, line, func);
02939         octstr_strip_blanks(value);
02940         return value;
02941     }
02942     }
02943     return NULL;
02944 }
02945 
02946 
02947 List *http_header_find_all(List *headers, char *name)
02948 {
02949     List *list;
02950     long i;
02951     Octstr *h;
02952 
02953     gwlib_assert_init();
02954     gw_assert(headers != NULL);
02955     gw_assert(name != NULL);
02956 
02957     list = gwlist_create();
02958     for (i = 0; i < gwlist_len(headers); ++i) {
02959         h = gwlist_get(headers, i);
02960         if (header_is_called(h, name))
02961             gwlist_append(list, octstr_duplicate(h));
02962     }
02963     return list;
02964 }
02965 
02966 
02967 long http_header_remove_all(List *headers, char *name)
02968 {
02969     long i;
02970     Octstr *h;
02971     long count;
02972 
02973     gwlib_assert_init();
02974     gw_assert(headers != NULL);
02975     gw_assert(name != NULL);
02976 
02977     i = 0;
02978     count = 0;
02979     while (i < gwlist_len(headers)) {
02980     h = gwlist_get(headers, i);
02981     if (header_is_called(h, name)) {
02982         gwlist_delete(headers, i, 1);
02983         octstr_destroy(h);
02984         count++;
02985     } else
02986         i++;
02987     }
02988 
02989     return count;
02990 }
02991 
02992 
02993 void http_remove_hop_headers(List *headers)
02994 {
02995     Octstr *h;
02996     List *connection_headers;
02997 
02998     gwlib_assert_init();
02999     gw_assert(headers != NULL);
03000 
03001     /*
03002      * The hop-by-hop headers are a standard list, plus those named
03003      * in the Connection header(s).
03004      */
03005 
03006     connection_headers = http_header_find_all(headers, "Connection");
03007     while ((h = gwlist_consume(connection_headers))) {
03008     List *hop_headers;
03009     Octstr *e;
03010 
03011     octstr_delete(h, 0, strlen("Connection:"));
03012     hop_headers = http_header_split_value(h);
03013     octstr_destroy(h);
03014 
03015     while ((e = gwlist_consume(hop_headers))) {
03016         http_header_remove_all(headers, octstr_get_cstr(e));
03017         octstr_destroy(e);
03018     }
03019 
03020     gwlist_destroy(hop_headers, NULL);
03021     }
03022     gwlist_destroy(connection_headers, NULL);
03023    
03024     http_header_remove_all(headers, "Connection");
03025     http_header_remove_all(headers, "Keep-Alive");
03026     http_header_remove_all(headers, "Proxy-Authenticate");
03027     http_header_remove_all(headers, "Proxy-Authorization");
03028     http_header_remove_all(headers, "TE");
03029     http_header_remove_all(headers, "Trailers");
03030     http_header_remove_all(headers, "Transfer-Encoding");
03031     http_header_remove_all(headers, "Upgrade");
03032 }
03033 
03034 
03035 void http_header_mark_transformation(List *headers,
03036                                      Octstr *new_body, Octstr *new_type)
03037 {
03038     Octstr *new_length = NULL;
03039 
03040     /* Remove all headers that no longer apply to the new body. */
03041     http_header_remove_all(headers, "Content-Length");
03042     http_header_remove_all(headers, "Content-MD5");
03043     http_header_remove_all(headers, "Content-Type");
03044 
03045     /* Add headers that we need to describe the new body. */
03046     new_length = octstr_format("%ld", octstr_len(new_body));
03047     http_header_add(headers, "Content-Length", octstr_get_cstr(new_length));
03048     if(octstr_len(new_type))
03049     http_header_add(headers, "Content-Type", octstr_get_cstr(new_type));
03050 
03051     /* Perhaps we should add Warning: 214 "Transformation applied" too? */
03052 
03053     octstr_destroy(new_length);
03054 }
03055 
03056 
03057 void http_header_get_content_type(List *headers, Octstr **type,
03058                                   Octstr **charset)
03059 {
03060     Octstr *h;
03061     long semicolon, equals, len;
03062 
03063     gwlib_assert_init();
03064     gw_assert(headers != NULL);
03065     gw_assert(type != NULL);
03066     gw_assert(charset != NULL);
03067 
03068     h = http_header_find_first(headers, "Content-Type");
03069     if (h == NULL) {
03070         *type = octstr_create("application/octet-stream");
03071         *charset = octstr_create("");
03072     } else {
03073         octstr_strip_blanks(h);
03074         semicolon = octstr_search_char(h, ';', 0);
03075         if (semicolon == -1) {
03076             *type = h;
03077             *charset = octstr_create("");
03078         } else {
03079             *charset = octstr_duplicate(h);
03080             octstr_delete(*charset, 0, semicolon + 1);
03081             octstr_strip_blanks(*charset);
03082             equals = octstr_search_char(*charset, '=', 0);
03083             if (equals == -1)
03084                 octstr_truncate(*charset, 0);
03085             else {
03086                 octstr_delete(*charset, 0, equals + 1);
03087                 if (octstr_get_char(*charset, 0) == '"')
03088                     octstr_delete(*charset, 0, 1);
03089                 len = octstr_len(*charset);
03090                 if (octstr_get_char(*charset, len - 1) == '"')
03091                     octstr_truncate(*charset, len - 1);
03092             }
03093 
03094             octstr_truncate(h, semicolon);
03095             octstr_strip_blanks(h);
03096             *type = h;
03097         }
03098 
03099         /* 
03100          * According to HTTP/1.1 (RFC 2616, section 3.7.1) we have to ensure
03101          * to return charset 'iso-8859-1' in case of no given encoding and
03102          * content-type is a 'text' subtype. 
03103          */
03104         if (octstr_len(*charset) == 0 && 
03105             octstr_ncompare(*type, octstr_imm("text"), 4) == 0)
03106             octstr_append_cstr(*charset, "ISO-8859-1");
03107     }
03108 }
03109 
03110 
03111 static void http_header_add_element(List *list, Octstr *value,
03112                     long start, long end)
03113 {
03114     Octstr *element;
03115 
03116     element = octstr_copy(value, start, end - start);
03117     octstr_strip_blanks(element);
03118     if (octstr_len(element) == 0)
03119     octstr_destroy(element);
03120     else
03121         gwlist_append(list, element);
03122 }
03123 
03124 
03125 long http_header_quoted_string_len(Octstr *header, long start)
03126 {
03127     long len;
03128     long pos;
03129     int c;
03130 
03131     if (octstr_get_char(header, start) != '"')
03132     return -1;
03133 
03134     len = octstr_len(header);
03135     for (pos = start + 1; pos < len; pos++) {
03136     c = octstr_get_char(header, pos);
03137     if (c == '\\')    /* quoted-pair */
03138         pos++;
03139     else if (c == '"')
03140         return pos - start + 1;
03141     }
03142 
03143     warning(0, "Header contains unterminated quoted-string:");
03144     warning(0, "%s", octstr_get_cstr(header));
03145     return len - start;
03146 }
03147 
03148 
03149 List *http_header_split_value(Octstr *value)
03150 {
03151     long start;  /* start of current element */
03152     long pos;
03153     long len;
03154     List *result;
03155     int c;
03156 
03157     /*
03158      * According to RFC2616 section 4.2, a field-value is either *TEXT
03159      * (the caller is responsible for not feeding us one of those) or
03160      * combinations of token, separators, and quoted-string.  We're
03161      * looking for commas which are separators, and have to skip
03162      * commas in quoted-strings.
03163      */
03164  
03165     result = gwlist_create();
03166     len = octstr_len(value);
03167     start = 0;
03168     for (pos = 0; pos < len; pos++) {
03169     c = octstr_get_char(value, pos);
03170     if (c == ',') {
03171         http_header_add_element(result, value, start, pos);
03172         start = pos + 1;
03173     } else if (c == '"') {
03174             pos += http_header_quoted_string_len(value, pos);
03175         pos--; /* compensate for the loop's pos++ */
03176         }
03177     }
03178     http_header_add_element(result, value, start, len);
03179     return result;
03180 }
03181 
03182 
03183 List *http_header_split_auth_value(Octstr *value)
03184 {
03185     List *result;
03186     Octstr *auth_scheme;
03187     Octstr *element;
03188     long i;
03189 
03190     /*
03191      * According to RFC2617, both "challenge" and "credentials"
03192      * consist of an auth-scheme followed by a list of auth-param.
03193      * Since we have to parse a list of challenges or credentials,
03194      * we have to look for auth-scheme to signal the start of
03195      * a new element.  (We can't just split on commas because
03196      * they are also used to separate the auth-params.)
03197      *
03198      * An auth-scheme is a single token, while an auth-param is
03199      * always a key=value pair.  So we can recognize an auth-scheme
03200      * as a token that is not followed by a '=' sign.
03201      *
03202      * Simple approach: First split at all commas, then recombine
03203      * the elements that belong to the same challenge or credential.
03204      * This is somewhat expensive but saves programmer thinking time.
03205      *
03206      * Richard Braakman
03207      */
03208  
03209     result = http_header_split_value(value);
03210     if (gwlist_len(result) == 0)
03211         return result;
03212 
03213     auth_scheme = gwlist_get(result, 0);
03214     i = 1;
03215     while (i < gwlist_len(result)) {
03216         int c;
03217         long pos;
03218 
03219         element = gwlist_get(result, i);
03220 
03221         /*
03222          * If the element starts with: token '='
03223          * then it's just an auth_param; append it to the current
03224          * auth_scheme.  If it starts with: token token '='
03225          * then it's the start of a new auth scheme.
03226          *
03227          * To make the scan easier, we consider anything other
03228          * than whitespace or '=' to be part of a token.
03229          */
03230 
03231         /* Skip first token */
03232         for (pos = 0; pos < octstr_len(element); pos++) {
03233             c = octstr_get_char(element, pos);
03234             if (isspace(c) || c == '=')
03235                 break;
03236         }
03237 
03238         /* Skip whitespace, if any */
03239         while (isspace(octstr_get_char(element, pos)))
03240             pos++;
03241 
03242         if (octstr_get_char(element, pos) == '=') {
03243             octstr_append_char(auth_scheme, ';');
03244             octstr_append(auth_scheme, element);
03245             gwlist_delete(result, i, 1);
03246             octstr_destroy(element);
03247         } else {
03248             char semicolon = ';';
03249             octstr_insert_data(element, pos, &semicolon, 1);
03250             auth_scheme = element;
03251             i++;
03252         }
03253     }
03254 
03255     return result;
03256 }
03257 
03258 
03259 void http_header_dump(List *headers)
03260 {
03261     long i;
03262 
03263     gwlib_assert_init();
03264 
03265     debug("gwlib.http", 0, "Dumping HTTP headers:");
03266     for (i = 0; headers != NULL && i < gwlist_len(headers); ++i)
03267         octstr_dump(gwlist_get(headers, i), 1);
03268     debug("gwlib.http", 0, "End of dump.");
03269 }
03270 
03271 
03272 void http_cgivar_dump(List *cgiargs)
03273 {
03274     HTTPCGIVar *v;
03275     long i, len;
03276 
03277     gwlib_assert_init();
03278 
03279     len = gwlist_len(cgiargs);
03280 
03281     debug("gwlib.http", 0, "Dumping %ld cgi variables:", len);
03282     for (i = 0; i < len; i++) {
03283         v = gwlist_get(cgiargs, i);
03284         octstr_dump(v->name, 0);
03285         octstr_dump(v->value, 0);
03286     }
03287     debug("gwlib.http", 0, "End of dump.");
03288 }
03289 
03290 
03291 void http_cgivar_dump_into(List *cgiargs, Octstr *os)
03292 {
03293     HTTPCGIVar *v;
03294 
03295     if (os == NULL)
03296         return;
03297 
03298     gwlib_assert_init();
03299 
03300     while ((v = gwlist_extract_first(cgiargs)) != NULL)
03301         octstr_format_append(os, "&%S=%S", v->name, v->value);
03302 }
03303 
03304 
03305 static int http_something_accepted(List *headers, char *header_name,
03306                                    char *what)
03307 {
03308     int found;
03309     long i;
03310     List *accepts;
03311     Octstr *needle = octstr_create(what);
03312 
03313     gwlib_assert_init();
03314     gw_assert(headers != NULL);
03315     gw_assert(what != NULL);
03316 
03317     /* return all headers with this name */
03318     accepts = http_header_find_all(headers, header_name);
03319 
03320     found = 0;
03321     for (i = 0; !found && i < gwlist_len(accepts); ++i) {
03322         Octstr *header_value = gwlist_get(accepts, i);
03323         if (octstr_case_search(header_value, needle, 0) != -1)
03324             found = 1;
03325     }
03326     octstr_destroy(needle);
03327     http_destroy_headers(accepts);
03328     return found;
03329 }
03330 
03331 
03332 int http_type_accepted(List *headers, char *type)
03333 {
03334     return http_something_accepted(headers, "Accept", type);
03335 }
03336 
03337 
03338 int http_charset_accepted(List *headers, char *charset)
03339 {
03340     return http_something_accepted(headers, "Accept-Charset", charset);
03341 }
03342 
03343 
03344 void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
03345 {
03346     Octstr *os;
03347     
03348     if (password != NULL)
03349       os = octstr_format("%S:%S", username, password);
03350     else
03351       os = octstr_format("%S", username);
03352     octstr_binary_to_base64(os);
03353     octstr_strip_blanks(os);
03354     octstr_insert(os, octstr_imm("Basic "), 0);
03355     http_header_add(headers, "Authorization", octstr_get_cstr(os));
03356     octstr_destroy(os);
03357 }
03358 
03359 
03360 Octstr *http_get_header_parameter(Octstr *value, Octstr *parameter)
03361 {
03362     long pos, len, end;
03363     int c, found = 0;
03364     Octstr *result = NULL;
03365 
03366     len = octstr_len(value);
03367     /* Find the start of the first parameter. */
03368     for (pos = 0; pos < len; pos++) {
03369         c = octstr_get_char(value, pos);
03370         if (c == ';')
03371             break;
03372         else if (c == '"')
03373             pos += http_header_quoted_string_len(value, pos) - 1;
03374     }
03375 
03376     if (pos >= len)
03377         return NULL;   /* no parameters */
03378 
03379     for (pos++; pos > 0 && pos < len && found == 0; pos++) {
03380         Octstr *key = NULL;
03381         Octstr *val = NULL;
03382 
03383         end = octstr_search_char(value, '=', pos);
03384         if (end < 0)
03385             end = octstr_search_char(value, ';', pos);
03386         if (end < 0)
03387             end = octstr_len(value);
03388         key = octstr_copy(value, pos, end - pos);
03389         octstr_strip_blanks(key);
03390         pos = end;
03391 
03392         if (octstr_get_char(value, pos) == '=') {
03393             pos++;
03394             while (isspace(octstr_get_char(value, pos)))
03395                 pos++;
03396             if (octstr_get_char(value, pos) == '"')
03397                 end = pos + http_header_quoted_string_len(value, pos);
03398             else
03399                 end = octstr_search_char(value, ';', pos);
03400             if (end < 0)
03401                 end = octstr_len(value);
03402             val = octstr_copy(value, pos, end - pos);
03403             octstr_strip_blanks(val);
03404             pos = end;
03405             pos = octstr_search_char(value, ';', pos);
03406         }
03407 
03408         /* is this the pair we look for? bail out then*/
03409         if (octstr_case_compare(key, parameter) == 0) {
03410             found++;        
03411             result = octstr_duplicate(val);
03412         }
03413 
03414         octstr_destroy(key);
03415         octstr_destroy(val);
03416     }
03417 
03418     return result;
03419 }
03420 
03421 
03422 /***********************************************************************
03423  * Module initialization and shutdown.
03424  */
03425 
03426 
03427 void http_init(void)
03428 {
03429     gw_assert(run_status == limbo);
03430 
03431 #ifdef HAVE_LIBSSL
03432     openssl_init_locks();
03433     conn_init_ssl();
03434 #endif /* HAVE_LIBSSL */
03435     proxy_init();
03436     client_init();
03437     conn_pool_init();
03438     port_init();
03439     server_init();
03440 #ifdef HAVE_LIBSSL
03441     server_ssl_init();
03442 #endif /* HAVE_LIBSSL */
03443     
03444     run_status = running;
03445 }
03446 
03447 
03448 void http_shutdown(void)
03449 {
03450     gwlib_assert_init();
03451     gw_assert(run_status == running);
03452 
03453     run_status = terminating;
03454 
03455     conn_pool_shutdown();
03456     client_shutdown();
03457     server_shutdown();
03458     port_shutdown();
03459     proxy_shutdown();
03460 #ifdef HAVE_LIBSSL
03461     openssl_shutdown_locks();
03462     conn_shutdown_ssl();
03463     server_shutdown_ssl();
03464 #endif /* HAVE_LIBSSL */
03465     run_status = limbo;
03466 }
03467 
03468 
03469 /*
03470  * This function relies on the HTTP_STATUS_* enum values being
03471  * chosen to fit this.
03472  */
03473 int http_status_class(int code)
03474 {
03475     int sclass;
03476 
03477     if (code < 100 || code >= 600)
03478         sclass = HTTP_STATUS_UNKNOWN;
03479     else
03480         sclass = code - (code % 100);
03481     return sclass;
03482 }
03483 
03484 
03485 int http_name2method(Octstr *method)
03486 {
03487     gw_assert(method != NULL);
03488 
03489     if (octstr_str_compare(method, "GET") == 0) {
03490         return HTTP_METHOD_GET;
03491     } 
03492     else if (octstr_str_compare(method, "POST") == 0) {
03493         return HTTP_METHOD_POST;
03494     } 
03495     else if (octstr_str_compare(method, "HEAD") == 0) {
03496         return HTTP_METHOD_HEAD;
03497     } 
03498 
03499     return -1;
03500 }
03501 
03502 
03503 char *http_method2name(int method)
03504 {
03505     gw_assert(method > 0 && method <= 3);
03506 
03507     return http_methods[method-1];
03508 }
03509 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.