00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
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
00088 #define DUMP_RESPONSE 1
00089
00090
00091 static int http_client_timeout = 240;
00092
00093
00094 #define HTTP_SERVER_TIMEOUT 60
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 enum { HTTP_PORT = 80,
00105 HTTPS_PORT = 443 };
00106
00107
00108
00109
00110
00111 static enum {
00112 limbo,
00113 running,
00114 terminating
00115 } run_status = limbo;
00116
00117
00118
00119
00120
00121 static Octstr *http_interface = NULL;
00122
00123
00124
00125
00126
00127
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
00164
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
00190
00191
00192
00193
00194
00195
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
00324
00325
00326
00327
00328
00329 enum body_expectation {
00330
00331
00332
00333
00334 expect_no_body,
00335
00336
00337
00338
00339 expect_body_if_indicated,
00340
00341
00342
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
00371
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;
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
00423
00424
00425
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
00556
00557
00558 static int entity_read(HTTPEntity *ent, Connection *conn)
00559 {
00560 int ret;
00561 enum entity_state old_state;
00562
00563
00564
00565
00566
00567
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
00617
00618
00619 return 1;
00620 }
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 static List *pending_requests = NULL;
00632
00633
00634
00635
00636
00637 static Mutex *client_thread_lock = NULL;
00638 static volatile sig_atomic_t client_threads_are_running = 0;
00639
00640
00641
00642
00643
00644
00645 static FDSet *client_fdset = NULL;
00646
00647
00648
00649
00650
00651 #define HTTP_MAX_FOLLOW 5
00652
00653
00654
00655
00656
00657
00658 static char *http_methods[] = {
00659 "GET", "POST", "HEAD"
00660 };
00661
00662
00663
00664
00665 typedef struct {
00666 HTTPCaller *caller;
00667 void *request_id;
00668 int method;
00669 Octstr *url;
00670 Octstr *uri;
00671 List *request_headers;
00672 Octstr *request_body;
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;
00683 Connection *conn;
00684 Octstr *host;
00685 long port;
00686 int follow_remaining;
00687 Octstr *certkeyfile;
00688 int ssl;
00689 Octstr *username;
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
00748
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
00798
00799
00800
00801 if (conn != NULL) {
00802 #ifdef USE_KEEPALIVE
00803
00804 conn_unregister(conn);
00805 #endif
00806
00807
00808
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
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
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
00856
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
00865
00866
00867
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
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
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
00933
00934
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
01028
01029
01030
01031 debug("gwlib.http",0,"Failed while reading status");
01032 goto error;
01033 } else if (ret == 0) {
01034
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
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
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
01076
01077
01078
01079
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
01110
01111
01112
01113
01114
01115
01116 if ((h = get_redirection_location(trans)) != NULL) {
01117
01118
01119
01120
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;
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
01147 gwlist_insert(pending_requests, 0, trans);
01148
01149 } else {
01150
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
01167
01168
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
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
01204
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
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
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
01322 if (octstr_len(url) == prefix_len) {
01323 error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
01324 return NULL;
01325 }
01326
01327
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
01336 p = http_urlparse_create();
01337 p->url = octstr_duplicate(url);
01338 p->scheme = octstr_duplicate(prefix);
01339
01340
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
01356
01357
01358
01359
01360
01361
01362
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
01371 }
01372
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
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
01391 }
01392
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
01402 } else {
01403 error(0, "Internal error in URL parsing logic.");
01404 http_urlparse_destroy(p);
01405 return NULL;
01406 }
01407
01408
01409
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
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
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
01437 p->host = octstr_copy(url, prefix_len,
01438 (query == -1 || slash != -1) ? host_len : query - prefix_len);
01439
01440
01441
01442
01443 parse_dump(p);
01444
01445 return p;
01446 }
01447
01448
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) {
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
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
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
01525
01526
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
01534
01535
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
01544
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
01584
01585
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
01603
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 {
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
01634
01635
01636
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
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
01682
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
01770
01771
01772
01773
01774
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;
01787 Octstr *url;
01788 int use_version_1_0;
01789 int persistent_conn;
01790 unsigned long conn_time;
01791 HTTPEntity *request;
01792 };
01793
01794
01795
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
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
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
01869
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
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
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
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);
01982 gwlist_destroy(p->clients_with_requests, client_destroy);
01983 counter_destroy(p->active_consumers);
01984 gw_free(p);
01985
01986
01987
01988
01989
01990
01991
01992
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
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);
02042 client = gwlist_consume(p->clients_with_requests);
02043 counter_decrease(p->active_consumers);
02044 }
02045 return client;
02046 }
02047
02048
02049
02050
02051
02052 #define MAX_SERVERS 32
02053
02054
02055
02056
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
02139 if (ret == -1) {
02140
02141
02142
02143
02144 client->persistent_conn = 0;
02145
02146 conn_unregister(conn);
02147 http_send_reply(client, HTTP_BAD_REQUEST, NULL, NULL);
02148 return;
02149 }
02150
02151
02152
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
02171 if (conn_error(conn))
02172 goto error;
02173 if (conn_outbuf_len(conn) > 0)
02174 return;
02175
02176 if (!client->persistent_conn) {
02177
02178
02179
02180
02181
02182 conn_unregister(conn);
02183 client_destroy(client);
02184 return;
02185 }
02186
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
02198
02199
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)
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
02260
02261
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
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
02315
02316
02317
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
02389
02390
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
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
02480
02481
02482 static const char *http_reason_phrase(int status)
02483 {
02484 switch (status) {
02485 case HTTP_OK:
02486 return "OK";
02487 case HTTP_CREATED:
02488 return "Created";
02489 case HTTP_ACCEPTED:
02490 return "Accepted";
02491 case HTTP_NO_CONTENT:
02492 return "No Content";
02493 case HTTP_RESET_CONTENT:
02494 return "Reset Content";
02495 case HTTP_MOVED_PERMANENTLY:
02496 return "Moved Permanently";
02497 case HTTP_FOUND:
02498 return "Found";
02499 case HTTP_SEE_OTHER:
02500 return "See Other";
02501 case HTTP_NOT_MODIFIED:
02502 return "Not Modified";
02503 case HTTP_TEMPORARY_REDIRECT:
02504 return "Temporary Redirect";
02505 case HTTP_BAD_REQUEST:
02506 return "Bad Request";
02507 case HTTP_UNAUTHORIZED:
02508 return "Unauthorized";
02509 case HTTP_FORBIDDEN:
02510 return "Forbidden";
02511 case HTTP_NOT_FOUND:
02512 return "Not Found";
02513 case HTTP_BAD_METHOD:
02514 return "Method Not Allowed";
02515 case HTTP_NOT_ACCEPTABLE:
02516 return "Not Acceptable";
02517 case HTTP_REQUEST_ENTITY_TOO_LARGE:
02518 return "Request Entity Too Large";
02519 case HTTP_UNSUPPORTED_MEDIA_TYPE:
02520 return "Unsupported Media Type";
02521 case HTTP_INTERNAL_SERVER_ERROR:
02522 return "Internal Server Error";
02523 case HTTP_NOT_IMPLEMENTED:
02524 return "Not Implemented";
02525 case HTTP_BAD_GATEWAY:
02526 return "Bad Gateway";
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
02546 octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION);
02547
02548
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
02558
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
02574
02575 if (ret == 0) {
02576
02577 if (!client->persistent_conn) {
02578 client_destroy(client);
02579 } else {
02580
02581 client_reset(client);
02582 conn_register(client->conn, server_fdset, receive_request, client);
02583 }
02584 }
02585
02586 else if (ret == 1) {
02587 client->state = sending_reply;
02588 conn_register(client->conn, server_fdset, receive_request, client);
02589 }
02590
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
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
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
02731
02732
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
02762
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
02822
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
02835
02836
02837 for(i = 0; i < gwlist_len(headers); i++) {
02838 http_header_get(headers, i, &name, &value);
02839
02840
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
02854 header = gwlist_get(headers, i);
02855 octstr_destroy(header);
02856 gwlist_delete(headers, i, 1);
02857
02858
02859 octstr_append(value, octstr_imm(", "));
02860 octstr_append(value, value2);
02861
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
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
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
03003
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
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
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
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
03101
03102
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 == '\\')
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;
03152 long pos;
03153 long len;
03154 List *result;
03155 int c;
03156
03157
03158
03159
03160
03161
03162
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--;
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
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
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
03223
03224
03225
03226
03227
03228
03229
03230
03231
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
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
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
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;
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
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
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
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
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
03465 run_status = limbo;
03466 }
03467
03468
03469
03470
03471
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.