1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * http.c - HTTP protocol server and client implementation
59 *
60 * Implements major parts of the Hypertext Transfer Protocol HTTP/1.1 (RFC 2616)
61 * See http://www.w3.org/Protocols/rfc2616/rfc2616.txt
62 *
63 * Lars Wirzenius
64 */
65
66 /* XXX re-implement socket pools, with idle connection killing to
67 save sockets */
68 /* XXX implement http_abort */
69 /* XXX give maximum input size */
70 /* XXX kill http_get_real */
71 /* XXX the proxy exceptions list should be a dict, I guess */
72 /* XXX set maximum number of concurrent connections to same host, total? */
73 /* XXX 100 status codes. */
74 /* XXX stop destroying persistent connections when a request is redirected */
75
76 #include <ctype.h>
77 #include <errno.h>
78 #include <unistd.h>
79 #include <string.h>
80 #include <signal.h>
81 #include <sys/types.h>
82 #include <sys/socket.h>
83
84 #include "gwlib.h"
85 #include "gwlib/regex.h"
86
87 /* comment this out if you don't want HTTP responses to be dumped */
88 #define DUMP_RESPONSE 1
89
90 /* define http client connections timeout in seconds (set to -1 for disable) */
91 static int http_client_timeout = 240;
92
93 /* define http server connections timeout in seconds (set to -1 for disable) */
94 #define HTTP_SERVER_TIMEOUT 60
95 /* max accepted clients */
96 #define HTTP_SERVER_MAX_ACTIVE_CONNECTIONS 500
97
98 /***********************************************************************
99 * Stuff used in several sub-modules.
100 */
101
102
103 /*
104 * Default port to connect to for HTTP connections.
105 */
106 enum { HTTP_PORT = 80,
107 HTTPS_PORT = 443 };
108
109
110 /*
111 * Status of this module.
112 */
113 static enum {
114 limbo,
115 running,
116 terminating
117 } run_status = limbo;
118
119
120 /*
121 * Which interface to use for outgoing HTTP requests.
122 */
123 static Octstr *http_interface = NULL;
124
125
126 /*
127 * Read some headers, i.e., until the first empty line (read and discard
128 * the empty line as well). Return -1 for error, 0 for all headers read,
129 * 1 for more headers to follow.
130 */
read_some_headers(Connection * conn,List * headers)131 static int read_some_headers(Connection *conn, List *headers)
132 {
133 Octstr *line, *prev;
134
135 if (gwlist_len(headers) == 0)
136 prev = NULL;
137 else
138 prev = gwlist_get(headers, gwlist_len(headers) - 1);
139
140 for (;;) {
141 line = conn_read_line(conn);
142 if (line == NULL) {
143 if (conn_eof(conn) || conn_error(conn))
144 return -1;
145 return 1;
146 }
147 if (octstr_len(line) == 0) {
148 octstr_destroy(line);
149 break;
150 }
151 if (isspace(octstr_get_char(line, 0)) && prev != NULL) {
152 octstr_append(prev, line);
153 octstr_destroy(line);
154 } else {
155 gwlist_append(headers, line);
156 prev = line;
157 }
158 }
159
160 return 0;
161 }
162
163
164 /*
165 * Check that the HTTP version string is valid. Return -1 for invalid,
166 * 0 for version 1.0, 1 for 1.x.
167 */
parse_http_version(Octstr * version)168 static int parse_http_version(Octstr *version)
169 {
170 Octstr *prefix;
171 long prefix_len;
172 int digit;
173
174 prefix = octstr_imm("HTTP/1.");
175 prefix_len = octstr_len(prefix);
176
177 if (octstr_ncompare(version, prefix, prefix_len) != 0)
178 return -1;
179 if (octstr_len(version) != prefix_len + 1)
180 return -1;
181 digit = octstr_get_char(version, prefix_len);
182 if (!isdigit(digit))
183 return -1;
184 if (digit == '0')
185 return 0;
186 return 1;
187 }
188
189
190 /***********************************************************************
191 * Proxy support.
192 */
193
194
195 /*
196 * Data and functions needed to support proxy operations. If proxy_hostname
197 * is NULL, no proxy is used.
198 */
199 static Mutex *proxy_mutex = NULL;
200 static Octstr *proxy_hostname = NULL;
201 static int proxy_port = 0;
202 static int proxy_ssl = 0;
203 static Octstr *proxy_username = NULL;
204 static Octstr *proxy_password = NULL;
205 static List *proxy_exceptions = NULL;
206 static regex_t *proxy_exceptions_regex = NULL;
207
208
proxy_add_authentication(List * headers)209 static void proxy_add_authentication(List *headers)
210 {
211 Octstr *os;
212
213 if (proxy_username == NULL || proxy_password == NULL)
214 return;
215
216 os = octstr_format("%S:%S", proxy_username, proxy_password);
217 octstr_binary_to_base64(os);
218 octstr_strip_blanks(os);
219 octstr_insert(os, octstr_imm("Basic "), 0);
220 http_header_add(headers, "Proxy-Authorization", octstr_get_cstr(os));
221 octstr_destroy(os);
222 }
223
224
proxy_init(void)225 static void proxy_init(void)
226 {
227 proxy_mutex = mutex_create();
228 proxy_exceptions = gwlist_create();
229 }
230
231
proxy_shutdown(void)232 static void proxy_shutdown(void)
233 {
234 http_close_proxy();
235 mutex_destroy(proxy_mutex);
236 proxy_mutex = NULL;
237 }
238
239
proxy_used_for_host(Octstr * host,Octstr * url)240 static int proxy_used_for_host(Octstr *host, Octstr *url)
241 {
242 int i;
243
244 mutex_lock(proxy_mutex);
245
246 if (proxy_hostname == NULL) {
247 mutex_unlock(proxy_mutex);
248 return 0;
249 }
250
251 for (i = 0; i < gwlist_len(proxy_exceptions); ++i) {
252 if (octstr_compare(host, gwlist_get(proxy_exceptions, i)) == 0) {
253 mutex_unlock(proxy_mutex);
254 return 0;
255 }
256 }
257
258 if (proxy_exceptions_regex != NULL && gw_regex_match_pre(proxy_exceptions_regex, url)) {
259 mutex_unlock(proxy_mutex);
260 return 0;
261 }
262
263 mutex_unlock(proxy_mutex);
264 return 1;
265 }
266
267
http_use_proxy(Octstr * hostname,int port,int ssl,List * exceptions,Octstr * username,Octstr * password,Octstr * exceptions_regex)268 void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions,
269 Octstr *username, Octstr *password, Octstr *exceptions_regex)
270 {
271 Octstr *e;
272 int i;
273
274 gw_assert(run_status == running);
275 gw_assert(hostname != NULL);
276 gw_assert(octstr_len(hostname) > 0);
277 gw_assert(port > 0);
278
279 http_close_proxy();
280 mutex_lock(proxy_mutex);
281
282 proxy_hostname = octstr_duplicate(hostname);
283 proxy_port = port;
284 proxy_ssl = ssl;
285 proxy_exceptions = gwlist_create();
286 for (i = 0; i < gwlist_len(exceptions); ++i) {
287 e = gwlist_get(exceptions, i);
288 debug("gwlib.http", 0, "HTTP: Proxy exception `%s'.", octstr_get_cstr(e));
289 gwlist_append(proxy_exceptions, octstr_duplicate(e));
290 }
291 if (exceptions_regex != NULL &&
292 (proxy_exceptions_regex = gw_regex_comp(exceptions_regex, REG_EXTENDED)) == NULL)
293 panic(0, "Could not compile pattern '%s'", octstr_get_cstr(exceptions_regex));
294 proxy_username = octstr_duplicate(username);
295 proxy_password = octstr_duplicate(password);
296 debug("gwlib.http", 0, "Using proxy <%s:%d> with %s scheme",
297 octstr_get_cstr(proxy_hostname), proxy_port,
298 (proxy_ssl ? "HTTPS" : "HTTP"));
299
300 mutex_unlock(proxy_mutex);
301 }
302
303
http_close_proxy(void)304 void http_close_proxy(void)
305 {
306 gw_assert(run_status == running || run_status == terminating);
307
308 mutex_lock(proxy_mutex);
309 proxy_port = 0;
310 octstr_destroy(proxy_hostname);
311 octstr_destroy(proxy_username);
312 octstr_destroy(proxy_password);
313 proxy_hostname = NULL;
314 proxy_username = NULL;
315 proxy_password = NULL;
316 gwlist_destroy(proxy_exceptions, octstr_destroy_item);
317 gw_regex_destroy(proxy_exceptions_regex);
318 proxy_exceptions = NULL;
319 proxy_exceptions_regex = NULL;
320 mutex_unlock(proxy_mutex);
321 }
322
323
324 /***********************************************************************
325 * Common functions for reading request or result entities.
326 */
327
328 /*
329 * Value to pass to entity_create.
330 */
331 enum body_expectation {
332 /*
333 * Message must not have a body, even if the headers indicate one.
334 * (i.e. response to HEAD method).
335 */
336 expect_no_body,
337 /*
338 * Message will have a body if Content-Length or Transfer-Encoding
339 * headers are present (i.e. most request methods).
340 */
341 expect_body_if_indicated,
342 /*
343 * Message will have a body, possibly zero-length.
344 * (i.e. 200 OK responses to a GET method.)
345 */
346 expect_body
347 };
348
349 enum entity_state {
350 reading_headers,
351 reading_chunked_body_len,
352 reading_chunked_body_data,
353 reading_chunked_body_crlf,
354 reading_chunked_body_trailer,
355 reading_body_until_eof,
356 reading_body_with_length,
357 body_error,
358 entity_done
359 };
360
361 typedef struct {
362 List *headers;
363 Octstr *body;
364 enum body_expectation expect_state;
365 enum entity_state state;
366 long chunked_body_chunk_len;
367 long expected_body_len;
368 } HTTPEntity;
369
370
371 /*
372 * The rules for message bodies (length and presence) are defined
373 * in RFC2616 paragraph 4.3 and 4.4.
374 */
deduce_body_state(HTTPEntity * ent)375 static void deduce_body_state(HTTPEntity *ent)
376 {
377 Octstr *h = NULL;
378
379 if (ent->expect_state == expect_no_body) {
380 ent->state = entity_done;
381 return;
382 }
383
384 ent->state = body_error; /* safety net */
385
386 h = http_header_find_first(ent->headers, "Transfer-Encoding");
387 if (h != NULL) {
388 octstr_strip_blanks(h);
389 if (octstr_str_compare(h, "chunked") != 0) {
390 error(0, "HTTP: Unknown Transfer-Encoding <%s>",
391 octstr_get_cstr(h));
392 ent->state = body_error;
393 } else {
394 ent->state = reading_chunked_body_len;
395 }
396 octstr_destroy(h);
397 return;
398 }
399
400 h = http_header_find_first(ent->headers, "Content-Length");
401 if (h != NULL) {
402 if (octstr_parse_long(&ent->expected_body_len, h, 0, 10) == -1 ||
403 ent->expected_body_len < 0) {
404 error(0, "HTTP: Content-Length header wrong: <%s>",
405 octstr_get_cstr(h));
406 ent->state = body_error;
407 } else if (ent->expected_body_len == 0) {
408 ent->state = entity_done;
409 } else {
410 ent->state = reading_body_with_length;
411 }
412 octstr_destroy(h);
413 return;
414 }
415
416 if (ent->expect_state == expect_body)
417 ent->state = reading_body_until_eof;
418 else
419 ent->state = entity_done;
420 }
421
422
423 /*
424 * Create a HTTPEntity structure suitable for reading the expected
425 * result or request message and decoding the transferred entity (if any).
426 * See the definition of enum body_expectation for the possible values
427 * of exp.
428 */
entity_create(enum body_expectation exp)429 static HTTPEntity *entity_create(enum body_expectation exp)
430 {
431 HTTPEntity *ent;
432
433 ent = gw_malloc(sizeof(*ent));
434 ent->headers = http_create_empty_headers();
435 ent->body = octstr_create("");
436 ent->chunked_body_chunk_len = -1;
437 ent->expected_body_len = -1;
438 ent->state = reading_headers;
439 ent->expect_state = exp;
440
441 return ent;
442 }
443
444
entity_destroy(HTTPEntity * ent)445 static void entity_destroy(HTTPEntity *ent)
446 {
447 if (ent == NULL)
448 return;
449
450 http_destroy_headers(ent->headers);
451 octstr_destroy(ent->body);
452 gw_free(ent);
453 }
454
455
read_chunked_body_len(HTTPEntity * ent,Connection * conn)456 static void read_chunked_body_len(HTTPEntity *ent, Connection *conn)
457 {
458 Octstr *os;
459 long len;
460
461 os = conn_read_line(conn);
462 if (os == NULL) {
463 if (conn_error(conn) || conn_eof(conn))
464 ent->state = body_error;
465 return;
466 }
467 if (octstr_parse_long(&len, os, 0, 16) == -1) {
468 octstr_destroy(os);
469 ent->state = body_error;
470 return;
471 }
472 octstr_destroy(os);
473 if (len == 0)
474 ent->state = reading_chunked_body_trailer;
475 else {
476 ent->state = reading_chunked_body_data;
477 ent->chunked_body_chunk_len = len;
478 }
479 }
480
481
read_chunked_body_data(HTTPEntity * ent,Connection * conn)482 static void read_chunked_body_data(HTTPEntity *ent, Connection *conn)
483 {
484 Octstr *os;
485
486 os = conn_read_fixed(conn, ent->chunked_body_chunk_len);
487 if (os == NULL) {
488 if (conn_error(conn) || conn_eof(conn))
489 ent->state = body_error;
490 } else {
491 octstr_append(ent->body, os);
492 octstr_destroy(os);
493 ent->state = reading_chunked_body_crlf;
494 }
495 }
496
497
read_chunked_body_crlf(HTTPEntity * ent,Connection * conn)498 static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn)
499 {
500 Octstr *os;
501
502 os = conn_read_line(conn);
503 if (os == NULL) {
504 if (conn_error(conn) || conn_eof(conn))
505 ent->state = body_error;
506 } else {
507 octstr_destroy(os);
508 ent->state = reading_chunked_body_len;
509 }
510 }
511
512
read_chunked_body_trailer(HTTPEntity * ent,Connection * conn)513 static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn)
514 {
515 int ret;
516
517 ret = read_some_headers(conn, ent->headers);
518 if (ret == -1)
519 ent->state = body_error;
520 if (ret == 0)
521 ent->state = entity_done;
522 }
523
524
read_body_until_eof(HTTPEntity * ent,Connection * conn)525 static void read_body_until_eof(HTTPEntity *ent, Connection *conn)
526 {
527 Octstr *os;
528
529 while ((os = conn_read_everything(conn)) != NULL) {
530 octstr_append(ent->body, os);
531 octstr_destroy(os);
532 }
533 if (conn_error(conn))
534 ent->state = body_error;
535 if (conn_eof(conn))
536 ent->state = entity_done;
537 }
538
539
read_body_with_length(HTTPEntity * ent,Connection * conn)540 static void read_body_with_length(HTTPEntity *ent, Connection *conn)
541 {
542 Octstr *os;
543
544 os = conn_read_fixed(conn, ent->expected_body_len);
545 if (os == NULL) {
546 if (conn_error(conn) || conn_eof(conn))
547 ent->state = body_error;
548 return;
549 }
550 octstr_destroy(ent->body);
551 ent->body = os;
552 ent->state = entity_done;
553 }
554
555
556 /*
557 * Read headers and body (if any) from this connection. Return 0 if it's
558 * complete, 1 if we expect more input, and -1 if there is something wrong.
559 */
entity_read(HTTPEntity * ent,Connection * conn)560 static int entity_read(HTTPEntity *ent, Connection *conn)
561 {
562 int ret;
563 enum entity_state old_state;
564
565 /*
566 * In this loop, each state will process as much input as it needs
567 * and then switch to the next state, unless it's a final state in
568 * which case it returns directly, or unless it needs more input.
569 * So keep looping as long as the state changes.
570 */
571 do {
572 old_state = ent->state;
573 switch (ent->state) {
574 case reading_headers:
575 ret = read_some_headers(conn, ent->headers);
576 if (ret == 0)
577 deduce_body_state(ent);
578 if (ret < 0)
579 return -1;
580 break;
581
582 case reading_chunked_body_len:
583 read_chunked_body_len(ent, conn);
584 break;
585
586 case reading_chunked_body_data:
587 read_chunked_body_data(ent, conn);
588 break;
589
590 case reading_chunked_body_crlf:
591 read_chunked_body_crlf(ent, conn);
592 break;
593
594 case reading_chunked_body_trailer:
595 read_chunked_body_trailer(ent, conn);
596 break;
597
598 case reading_body_until_eof:
599 read_body_until_eof(ent, conn);
600 break;
601
602 case reading_body_with_length:
603 read_body_with_length(ent, conn);
604 break;
605
606 case body_error:
607 return -1;
608
609 case entity_done:
610 return 0;
611
612 default:
613 panic(0, "Internal error: Invalid HTTPEntity state.");
614 }
615 } while (ent->state != old_state);
616
617 /*
618 * If we got here, then the loop ended because a non-final state
619 * needed more input.
620 */
621 return 1;
622 }
623
624
625 /***********************************************************************
626 * HTTP client interface.
627 */
628
629 /*
630 * Internal lists of completely unhandled requests and requests for which
631 * a request has been sent but response has not yet been read.
632 */
633 static List *pending_requests = NULL;
634
635
636 /*
637 * Have background threads been started?
638 */
639 static Mutex *client_thread_lock = NULL;
640 static volatile sig_atomic_t client_threads_are_running = 0;
641
642
643 /*
644 * Set of all connections to all servers. Used with conn_register to
645 * do I/O on several connections with a single thread.
646 */
647 static FDSet *client_fdset = NULL;
648
649 /*
650 * Maximum number of HTTP redirections to follow. Making this infinite
651 * could cause infinite looping if the redirections loop.
652 */
653 #define HTTP_MAX_FOLLOW 5
654
655
656 /*
657 * The implemented HTTP method strings
658 * Order is sequenced by the enum in the header
659 */
660 static char *http_methods[] = {
661 "GET", "POST", "HEAD"
662 };
663
664 /*
665 * Information about a server we've connected to.
666 */
667 typedef struct {
668 HTTPCaller *caller;
669 void *request_id;
670 int method; /* uses enums from http.h for the HTTP methods */
671 Octstr *url; /* the full URL, including scheme, host, etc. */
672 Octstr *uri; /* the HTTP URI path only */
673 List *request_headers;
674 Octstr *request_body; /* NULL for GET or HEAD, non-NULL for POST */
675 enum {
676 connecting,
677 request_not_sent,
678 reading_status,
679 reading_entity,
680 transaction_done
681 } state;
682 long status;
683 int persistent;
684 HTTPEntity *response; /* Can only be NULL if status < 0 */
685 Connection *conn;
686 Octstr *host;
687 long port;
688 int follow_remaining;
689 Octstr *certkeyfile;
690 int ssl;
691 Octstr *username; /* For basic authentication */
692 Octstr *password;
693 } HTTPServer;
694
695
696 static int send_request(HTTPServer *trans);
697 static Octstr *build_response(List *headers, Octstr *body);
698 static int header_is_called(Octstr *header, char *name);
699
server_create(HTTPCaller * caller,int method,Octstr * url,List * headers,Octstr * body,int follow_remaining,Octstr * certkeyfile)700 static HTTPServer *server_create(HTTPCaller *caller, int method, Octstr *url,
701 List *headers, Octstr *body, int follow_remaining,
702 Octstr *certkeyfile)
703 {
704 HTTPServer *trans;
705
706 trans = gw_malloc(sizeof(*trans));
707 trans->caller = caller;
708 trans->request_id = NULL;
709 trans->method = method;
710 trans->url = octstr_duplicate(url);
711 trans->uri = NULL;
712 trans->request_headers = http_header_duplicate(headers);
713 trans->request_body = octstr_duplicate(body);
714 trans->state = request_not_sent;
715 trans->status = -1;
716 trans->persistent = 0;
717 trans->response = NULL;
718 trans->conn = NULL;
719 trans->host = NULL;
720 trans->port = 0;
721 trans->username = NULL;
722 trans->password = NULL;
723 trans->follow_remaining = follow_remaining;
724 trans->certkeyfile = octstr_duplicate(certkeyfile);
725 trans->ssl = 0;
726 return trans;
727 }
728
729
server_destroy(void * p)730 static void server_destroy(void *p)
731 {
732 HTTPServer *trans;
733
734 trans = p;
735 octstr_destroy(trans->url);
736 octstr_destroy(trans->uri);
737 http_destroy_headers(trans->request_headers);
738 trans->request_headers = NULL;
739 octstr_destroy(trans->request_body);
740 entity_destroy(trans->response);
741 octstr_destroy(trans->host);
742 octstr_destroy(trans->certkeyfile);
743 octstr_destroy(trans->username);
744 octstr_destroy(trans->password);
745 gw_free(trans);
746 }
747
748
749 /*
750 * Pool of open, but unused connections to servers or proxies. Key is
751 * "servername:port", value is List with Connection objects.
752 */
753 static Dict *conn_pool;
754 static Mutex *conn_pool_lock;
755
756
conn_pool_item_destroy(void * item)757 static void conn_pool_item_destroy(void *item)
758 {
759 gwlist_destroy(item, (void(*)(void*))conn_destroy);
760 }
761
conn_pool_init(void)762 static void conn_pool_init(void)
763 {
764 conn_pool = dict_create(1024, conn_pool_item_destroy);
765 conn_pool_lock = mutex_create();
766 }
767
768
conn_pool_shutdown(void)769 static void conn_pool_shutdown(void)
770 {
771 dict_destroy(conn_pool);
772 mutex_destroy(conn_pool_lock);
773 }
774
775
conn_pool_key(Octstr * host,int port,int ssl,Octstr * certfile,Octstr * our_host)776 static inline Octstr *conn_pool_key(Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host)
777 {
778 return octstr_format("%S:%d:%d:%S:%S", host, port, ssl?1:0, certfile?certfile:octstr_imm(""),
779 our_host?our_host:octstr_imm(""));
780 }
781
782
conn_pool_get(Octstr * host,int port,int ssl,Octstr * certkeyfile,Octstr * our_host)783 static Connection *conn_pool_get(Octstr *host, int port, int ssl, Octstr *certkeyfile,
784 Octstr *our_host)
785 {
786 Octstr *key;
787 List *list = NULL;
788 Connection *conn = NULL;
789 int retry;
790
791 do {
792 retry = 0;
793 key = conn_pool_key(host, port, ssl, certkeyfile, our_host);
794 mutex_lock(conn_pool_lock);
795 list = dict_get(conn_pool, key);
796 if (list != NULL)
797 conn = gwlist_extract_first(list);
798 mutex_unlock(conn_pool_lock);
799 /*
800 * Note: we don't hold conn_pool_lock when we check/destroy/unregister
801 * connection because otherwise we can deadlock! And it's even better
802 * not to delay other threads while we check connection.
803 */
804 if (conn != NULL) {
805 #ifdef USE_KEEPALIVE
806 /* unregister our server disconnect callback */
807 conn_unregister(conn);
808 #endif
809 /*
810 * Check whether the server has closed the connection while
811 * it has been in the pool.
812 */
813 conn_wait(conn, 0);
814 if (conn_eof(conn) || conn_error(conn)) {
815 debug("gwlib.http", 0, "HTTP:conn_pool_get: Server closed connection, destroying it <%s><%p><fd:%d>.",
816 octstr_get_cstr(key), conn, conn_get_id(conn));
817 conn_destroy(conn);
818 retry = 1;
819 conn = NULL;
820 }
821 }
822 octstr_destroy(key);
823 } while(retry == 1);
824
825 if (conn == NULL) {
826 #ifdef HAVE_LIBSSL
827 if (ssl)
828 conn = conn_open_ssl_nb(host, port, certkeyfile, our_host);
829 else
830 #endif /* HAVE_LIBSSL */
831 conn = conn_open_tcp_nb(host, port, our_host);
832 debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",
833 octstr_get_cstr(host), port, conn_get_id(conn));
834 } else {
835 debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).",
836 octstr_get_cstr(host), port, conn_get_id(conn));
837 }
838
839 return conn;
840 }
841
842 #ifdef USE_KEEPALIVE
check_pool_conn(Connection * conn,void * data)843 static void check_pool_conn(Connection *conn, void *data)
844 {
845 Octstr *key = data;
846
847 if (run_status != running) {
848 conn_unregister(conn);
849 return;
850 }
851 /* check if connection still ok */
852 if (conn_error(conn) || conn_eof(conn)) {
853 List *list;
854 mutex_lock(conn_pool_lock);
855 list = dict_get(conn_pool, key);
856 if (gwlist_delete_equal(list, conn) > 0) {
857 /*
858 * ok, connection was still within pool. So it's
859 * safe to destroy this connection.
860 */
861 debug("gwlib.http", 0, "HTTP: Server closed connection, destroying it <%s><%p><fd:%d>.",
862 octstr_get_cstr(key), conn, conn_get_id(conn));
863 conn_unregister(conn);
864 conn_destroy(conn);
865 }
866 /*
867 * it's perfectly valid if connection was not found in connection pool because
868 * in 'conn_pool_get' we first removed connection from pool with conn_pool_lock locked
869 * and then check connection for errors with conn_pool_lock unlocked. In the meantime
870 * fdset's poller may call us. So just ignore such "dummy" call.
871 */
872 mutex_unlock(conn_pool_lock);
873 }
874 }
875
876
conn_pool_put(Connection * conn,Octstr * host,int port,int ssl,Octstr * certfile,Octstr * our_host)877 static void conn_pool_put(Connection *conn, Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host)
878 {
879 Octstr *key;
880 List *list;
881
882 key = conn_pool_key(host, port, ssl, certfile, our_host);
883 mutex_lock(conn_pool_lock);
884 list = dict_get(conn_pool, key);
885 if (list == NULL) {
886 list = gwlist_create();
887 dict_put(conn_pool, key, list);
888 }
889 gwlist_append(list, conn);
890 /* register connection to get server disconnect */
891 conn_register_real(conn, client_fdset, check_pool_conn, key, octstr_destroy_item);
892 mutex_unlock(conn_pool_lock);
893 }
894 #endif
895
896
http_caller_create(void)897 HTTPCaller *http_caller_create(void)
898 {
899 HTTPCaller *caller;
900
901 caller = gwlist_create();
902 gwlist_add_producer(caller);
903 return caller;
904 }
905
906
http_caller_destroy(HTTPCaller * caller)907 void http_caller_destroy(HTTPCaller *caller)
908 {
909 gwlist_destroy(caller, server_destroy);
910 }
911
912
http_caller_signal_shutdown(HTTPCaller * caller)913 void http_caller_signal_shutdown(HTTPCaller *caller)
914 {
915 gwlist_remove_producer(caller);
916 }
917
918
get_redirection_location(HTTPServer * trans)919 static Octstr *get_redirection_location(HTTPServer *trans)
920 {
921 if (trans->status < 0 || trans->follow_remaining <= 0)
922 return NULL;
923 /* check for the redirection response codes */
924 if (trans->status != HTTP_MOVED_PERMANENTLY &&
925 trans->status != HTTP_FOUND && trans->status != HTTP_SEE_OTHER &&
926 trans->status != HTTP_TEMPORARY_REDIRECT)
927 return NULL;
928 if (trans->response == NULL)
929 return NULL;
930 return http_header_find_first(trans->response->headers, "Location");
931 }
932
933
934 /*
935 * Recovers a Location header value of format URI /xyz to an
936 * absoluteURI format according to the protocol rules.
937 * This simply implies that we re-create the prefixed scheme,
938 * user/passwd (if any), host and port string and prepend it
939 * to the location URI.
940 */
recover_absolute_uri(HTTPServer * trans,Octstr * loc)941 static void recover_absolute_uri(HTTPServer *trans, Octstr *loc)
942 {
943 Octstr *os;
944
945 gw_assert(loc != NULL && trans != NULL);
946
947 /* we'll only accept locations with a leading / */
948 if (octstr_get_char(loc, 0) == '/') {
949
950 /* scheme */
951 os = trans->ssl ? octstr_create("https://") :
952 octstr_create("http://");
953
954 /* credentials, if any */
955 if (trans->username && trans->password) {
956 octstr_append(os, trans->username);
957 octstr_append_char(os, ':');
958 octstr_append(os, trans->password);
959 octstr_append_char(os, '@');
960 }
961
962 /* host */
963 octstr_append(os, trans->host);
964
965 /* port, only added if literally not default. */
966 if (trans->port != 80 || trans->ssl) {
967 octstr_format_append(os, ":%ld", trans->port);
968 }
969
970 /* prepend the created octstr to the loc, and destroy then. */
971 octstr_insert(loc, os, 0);
972 octstr_destroy(os);
973 }
974 }
975
976
977 /*
978 * Read and parse the status response line from an HTTP server.
979 * Fill in trans->persistent and trans->status with the findings.
980 * Return -1 for error, 1 for status line not yet available, 0 for OK.
981 */
client_read_status(HTTPServer * trans)982 static int client_read_status(HTTPServer *trans)
983 {
984 Octstr *line, *version;
985 long space;
986 int ret;
987
988 line = conn_read_line(trans->conn);
989 if (line == NULL) {
990 if (conn_eof(trans->conn) || conn_error(trans->conn))
991 return -1;
992 return 1;
993 }
994
995 debug("gwlib.http", 0, "HTTP: Status line: <%s>", octstr_get_cstr(line));
996
997 space = octstr_search_char(line, ' ', 0);
998 if (space == -1)
999 goto error;
1000
1001 version = octstr_copy(line, 0, space);
1002 ret = parse_http_version(version);
1003 octstr_destroy(version);
1004 if (ret == -1)
1005 goto error;
1006 trans->persistent = ret;
1007
1008 octstr_delete(line, 0, space + 1);
1009 space = octstr_search_char(line, ' ', 0);
1010 if (space == -1)
1011 goto error;
1012 octstr_truncate(line, space);
1013
1014 if (octstr_parse_long(&trans->status, line, 0, 10) == -1)
1015 goto error;
1016
1017 octstr_destroy(line);
1018 return 0;
1019
1020 error:
1021 error(0, "HTTP: Malformed status line from HTTP server: <%s>",
1022 octstr_get_cstr(line));
1023 octstr_destroy(line);
1024 return -1;
1025 }
1026
response_expectation(int method,int status)1027 static int response_expectation(int method, int status)
1028 {
1029 if (status == HTTP_NO_CONTENT ||
1030 status == HTTP_NOT_MODIFIED ||
1031 http_status_class(status) == HTTP_STATUS_PROVISIONAL ||
1032 method == HTTP_METHOD_HEAD)
1033 return expect_no_body;
1034 else
1035 return expect_body;
1036 }
1037
handle_transaction(Connection * conn,void * data)1038 static void handle_transaction(Connection *conn, void *data)
1039 {
1040 HTTPServer *trans;
1041 int ret;
1042 Octstr *h;
1043 int rc;
1044
1045 trans = data;
1046
1047 if (run_status != running) {
1048 conn_unregister(conn);
1049 return;
1050 }
1051
1052 while (trans->state != transaction_done) {
1053 switch (trans->state) {
1054 case connecting:
1055 debug("gwlib.http", 0, "Get info about connecting socket");
1056 if (conn_get_connect_result(trans->conn) != 0) {
1057 debug("gwlib.http", 0, "Socket not connected");
1058 goto error;
1059 }
1060
1061 if ((rc = send_request(trans)) == 0) {
1062 trans->state = reading_status;
1063 } else {
1064 debug("gwlib.http", 0, "Failed while sending request");
1065 goto error;
1066 }
1067 break;
1068
1069 case reading_status:
1070 ret = client_read_status(trans);
1071 if (ret < 0) {
1072 /*
1073 * Couldn't read the status from the socket. This may mean
1074 * that the socket had been closed by the server after an
1075 * idle timeout.
1076 */
1077 debug("gwlib.http",0,"Failed while reading status");
1078 goto error;
1079 } else if (ret == 0) {
1080 /* Got the status, go read headers and body next. */
1081 trans->state = reading_entity;
1082 trans->response = entity_create(response_expectation(trans->method, trans->status));
1083 } else {
1084 return;
1085 }
1086 break;
1087
1088 case reading_entity:
1089 ret = entity_read(trans->response, conn);
1090 if (ret < 0) {
1091 debug("gwlib.http",0,"Failed reading entity");
1092 goto error;
1093 } else if (ret == 0 &&
1094 http_status_class(trans->status) == HTTP_STATUS_PROVISIONAL) {
1095 /* This was a provisional reply; get the real one now. */
1096 trans->state = reading_status;
1097 entity_destroy(trans->response);
1098 trans->response = NULL;
1099 } else if (ret == 0) {
1100 trans->state = transaction_done;
1101 #ifdef DUMP_RESPONSE
1102 /* Dump the response */
1103 debug("gwlib.http", 0, "HTTP: Received response:");
1104 h = build_response(trans->response->headers, trans->response->body);
1105 octstr_dump(h, 0);
1106 octstr_destroy(h);
1107 #endif
1108 } else {
1109 return;
1110 }
1111 break;
1112
1113 default:
1114 panic(0, "Internal error: Invalid HTTPServer state.");
1115 }
1116 }
1117
1118 conn_unregister(trans->conn);
1119
1120 /*
1121 * Take care of persistent connection handling.
1122 * At this point we have only obeyed if server responds in HTTP/1.0 or 1.1
1123 * and have assigned trans->persistent accordingly. This can be keept
1124 * for default usage, but if we have [Proxy-]Connection: keep-alive, then
1125 * we're still forcing persistancy of the connection.
1126 */
1127 h = http_header_find_first(trans->response->headers, "Connection");
1128 if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0)
1129 trans->persistent = 0;
1130 if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0)
1131 trans->persistent = 1;
1132 octstr_destroy(h);
1133 if (proxy_used_for_host(trans->host, trans->url)) {
1134 h = http_header_find_first(trans->response->headers, "Proxy-Connection");
1135 if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0)
1136 trans->persistent = 0;
1137 if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0)
1138 trans->persistent = 1;
1139 octstr_destroy(h);
1140 }
1141
1142 #ifdef USE_KEEPALIVE
1143 if (trans->persistent) {
1144 if (proxy_used_for_host(trans->host, trans->url))
1145 conn_pool_put(trans->conn, proxy_hostname, proxy_port, trans->ssl, trans->certkeyfile, http_interface);
1146 else
1147 conn_pool_put(trans->conn, trans->host, trans->port, trans->ssl, trans->certkeyfile, http_interface);
1148 } else
1149 #endif
1150 conn_destroy(trans->conn);
1151
1152 trans->conn = NULL;
1153
1154 /*
1155 * Check if the HTTP server told us to look somewhere else,
1156 * hence if we got one of the following response codes:
1157 * HTTP_MOVED_PERMANENTLY (301)
1158 * HTTP_FOUND (302)
1159 * HTTP_SEE_OTHER (303)
1160 * HTTP_TEMPORARY_REDIRECT (307)
1161 */
1162 if ((h = get_redirection_location(trans)) != NULL) {
1163
1164 /*
1165 * This is a redirected response, we have to follow.
1166 *
1167 * According to HTTP/1.1 (RFC 2616), section 14.30 any Location
1168 * header value should be 'absoluteURI', which is defined in
1169 * RFC 2616, section 3.2.1 General Syntax, and specifically in
1170 * RFC 2396, section 3 URI Syntactic Components as
1171 *
1172 * absoluteURI = scheme ":" ( hier_part | opaque_part )
1173 *
1174 * Some HTTP servers 'interpret' a leading UDI / as that kind
1175 * of absoluteURI, which is not correct, following the protocol in
1176 * detail. But we'll try to recover from that misleaded
1177 * interpreation and try to convert the partly absoluteURI to a
1178 * fully qualified absoluteURI.
1179 *
1180 * http_URL = "http:" "//" [ userid : password "@"] host
1181 * [ ":" port ] [ abs_path [ "?" query ]]
1182 *
1183 */
1184 octstr_strip_blanks(h);
1185 recover_absolute_uri(trans, h);
1186
1187 /*
1188 * Clean up all trans stuff for the next request we do.
1189 */
1190 octstr_destroy(trans->url);
1191 octstr_destroy(trans->host);
1192 trans->port = 0;
1193 octstr_destroy(trans->uri);
1194 octstr_destroy(trans->username);
1195 octstr_destroy(trans->password);
1196 trans->host = NULL;
1197 trans->port = 0;
1198 trans->uri = NULL;
1199 trans->username = NULL;
1200 trans->password = NULL;
1201 trans->ssl = 0;
1202 trans->url = h; /* apply new absolute URL to next request */
1203 trans->state = request_not_sent;
1204 trans->status = -1;
1205 entity_destroy(trans->response);
1206 trans->response = NULL;
1207 --trans->follow_remaining;
1208 conn_destroy(trans->conn);
1209 trans->conn = NULL;
1210
1211 /* re-inject request to the front of the queue */
1212 gwlist_insert(pending_requests, 0, trans);
1213
1214 } else {
1215 /* handle this response as usual */
1216 gwlist_produce(trans->caller, trans);
1217 }
1218 return;
1219
1220 error:
1221 conn_unregister(trans->conn);
1222 conn_destroy(trans->conn);
1223 trans->conn = NULL;
1224 error(0, "Couldn't fetch <%s>", octstr_get_cstr(trans->url));
1225 trans->status = -1;
1226 gwlist_produce(trans->caller, trans);
1227 }
1228
1229
1230 /*
1231 * Build a complete HTTP request given the host, port, path and headers.
1232 * Add Host: and Content-Length: headers (and others that may be necessary).
1233 * Return the request as an Octstr.
1234 */
build_request(char * method_name,Octstr * path_or_url,Octstr * host,long port,int ssl,List * headers,Octstr * request_body)1235 static Octstr *build_request(char *method_name, Octstr *path_or_url,
1236 Octstr *host, long port, int ssl, List *headers,
1237 Octstr *request_body)
1238 {
1239 /* XXX headers missing */
1240 Octstr *request;
1241 int i, host_found = 0;
1242
1243 request = octstr_format("%s %S HTTP/1.1\r\n",
1244 method_name, path_or_url);
1245
1246 #ifdef USE_KEEPALIVE
1247 octstr_append(request, octstr_imm("Connection: keep-alive\r\n"));
1248 #endif
1249
1250 for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
1251 /* check if Host already set in the headers */
1252 if (header_is_called(gwlist_get(headers, i), "Host"))
1253 host_found = 1;
1254 octstr_append(request, gwlist_get(headers, i));
1255 octstr_append(request, octstr_imm("\r\n"));
1256 }
1257
1258 if (!host_found) {
1259 octstr_format_append(request, "Host: %S", host);
1260 /*
1261 * In accordance with HTT/1.1 [RFC 2616], section 14.23 "Host"
1262 * we shall ONLY add the port number if it is not one of the
1263 * officially assigned port numbers. This means we need to obey
1264 * port 80 for non-SSL connections and port 443 for SSL-enabled.
1265 */
1266 if ((port != HTTP_PORT && !ssl) || (port != HTTPS_PORT && ssl))
1267 octstr_format_append(request, ":%ld", port);
1268 octstr_append(request, octstr_imm("\r\n"));
1269 }
1270
1271 octstr_append(request, octstr_imm("\r\n"));
1272
1273 if (request_body != NULL)
1274 octstr_append(request, request_body);
1275
1276 return request;
1277 }
1278
1279
1280 /*
1281 * Re-build the HTTP response given the headers and the body.
1282 * Return the response as an Octstr.
1283 */
build_response(List * headers,Octstr * body)1284 static Octstr *build_response(List *headers, Octstr *body)
1285 {
1286 Octstr *response;
1287 int i;
1288
1289 response = octstr_create("");
1290
1291 for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
1292 octstr_append(response, gwlist_get(headers, i));
1293 octstr_append(response, octstr_imm("\r\n"));
1294 }
1295 octstr_append(response, octstr_imm("\r\n"));
1296
1297 if (body != NULL)
1298 octstr_append(response, body);
1299
1300 return response;
1301 }
1302
1303
http_urlparse_create(void)1304 HTTPURLParse *http_urlparse_create(void)
1305 {
1306 HTTPURLParse *p;
1307
1308 p = gw_malloc(sizeof(HTTPURLParse));
1309 p->url = NULL;
1310 p->scheme = NULL;
1311 p->host = NULL;
1312 p->port = 0;
1313 p->user = NULL;
1314 p->pass = NULL;
1315 p->path = NULL;
1316 p->query = NULL;
1317 p->fragment = NULL;
1318
1319 return p;
1320 }
1321
1322
http_urlparse_destroy(HTTPURLParse * p)1323 void http_urlparse_destroy(HTTPURLParse *p)
1324 {
1325 gw_assert(p != NULL);
1326
1327 octstr_destroy(p->url);
1328 octstr_destroy(p->scheme);
1329 octstr_destroy(p->host);
1330 octstr_destroy(p->user);
1331 octstr_destroy(p->pass);
1332 octstr_destroy(p->path);
1333 octstr_destroy(p->query);
1334 octstr_destroy(p->fragment);
1335 gw_free(p);
1336 }
1337
1338
parse_dump(HTTPURLParse * p)1339 void parse_dump(HTTPURLParse *p)
1340 {
1341 if (p == NULL)
1342 return;
1343 debug("http.parse_url",0,"Parsing URL `%s':", octstr_get_cstr(p->url));
1344 debug("http.parse_url",0," Scheme: %s", octstr_get_cstr(p->scheme));
1345 debug("http.parse_url",0," Host: %s", octstr_get_cstr(p->host));
1346 debug("http.parse_url",0," Port: %ld", p->port);
1347 debug("http.parse_url",0," Username: %s", octstr_get_cstr(p->user));
1348 debug("http.parse_url",0," Password: %s", octstr_get_cstr(p->pass));
1349 debug("http.parse_url",0," Path: %s", octstr_get_cstr(p->path));
1350 debug("http.parse_url",0," Query: %s", octstr_get_cstr(p->query));
1351 debug("http.parse_url",0," Fragment: %s", octstr_get_cstr(p->fragment));
1352 }
1353
1354
1355 /*
1356 * Parse the URL to get all components, which are: scheme, hostname,
1357 * port, username, password, path (URI), query (the CGI parameter list),
1358 * fragment (#).
1359 *
1360 * On success return the HTTPURLParse structure, otherwise NULL if the URL
1361 * seems malformed.
1362 *
1363 * We assume HTTP URLs of the form specified in "3.2.2 http URL" in
1364 * RFC 2616:
1365 *
1366 * http_URL = "http:" "//" [ userid : password "@"] host [ ":" port ] [ abs_path [ "?" query ]]
1367 */
parse_url(Octstr * url)1368 HTTPURLParse *parse_url(Octstr *url)
1369 {
1370 HTTPURLParse *p;
1371 Octstr *prefix, *prefix_https;
1372 long prefix_len;
1373 int host_len, colon, slash, at, auth_sep, query;
1374 host_len = colon = slash = at = auth_sep = query = 0;
1375
1376 prefix = octstr_imm("http://");
1377 prefix_https = octstr_imm("https://");
1378 prefix_len = octstr_len(prefix);
1379
1380 if (octstr_case_search(url, prefix, 0) != 0) {
1381 if (octstr_case_search(url, prefix_https, 0) == 0) {
1382 #ifdef HAVE_LIBSSL
1383 debug("gwlib.http", 0, "HTTPS URL; Using SSL for the connection");
1384 prefix = prefix_https;
1385 prefix_len = octstr_len(prefix_https);
1386 #else
1387 error(0, "Attempt to use HTTPS <%s> but SSL not compiled in",
1388 octstr_get_cstr(url));
1389 return NULL;
1390 #endif
1391 } else {
1392 error(0, "URL <%s> doesn't start with `%s' nor `%s'",
1393 octstr_get_cstr(url), octstr_get_cstr(prefix),
1394 octstr_get_cstr(prefix_https));
1395 return NULL;
1396 }
1397 }
1398
1399 /* an URL should be more (at least one charset) then the scheme itself */
1400 if (octstr_len(url) == prefix_len) {
1401 error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
1402 return NULL;
1403 }
1404
1405 /* check if colon and slashes are within scheme */
1406 colon = octstr_search_char(url, ':', prefix_len);
1407 slash = octstr_search_char(url, '/', prefix_len);
1408 if (colon == prefix_len || slash == prefix_len) {
1409 error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
1410 return NULL;
1411 }
1412
1413 /* create struct and add values succesively while parsing */
1414 p = http_urlparse_create();
1415 p->url = octstr_duplicate(url);
1416 p->scheme = octstr_duplicate(prefix);
1417
1418 /* try to parse authentication separator */
1419 at = octstr_search_char(url, '@', prefix_len);
1420 if (at != -1) {
1421 if ((slash == -1 || ( slash != -1 && at < slash))) {
1422 auth_sep = octstr_search_char(url, ':', prefix_len);
1423 if (auth_sep != -1 && (auth_sep < at)) {
1424 octstr_set_char(url, auth_sep, '@');
1425 colon = octstr_search_char(url, ':', prefix_len);
1426 }
1427 } else {
1428 at = -1;
1429 }
1430 }
1431
1432 /*
1433 * We have to watch out here for 4 cases:
1434 * a) hostname, no port or path
1435 * b) hostname, port, no path
1436 * c) hostname, path, no port
1437 * d) hostname, port and path
1438 */
1439
1440 /* we only have the hostname, no port or path. */
1441 if (slash == -1 && colon == -1) {
1442 host_len = octstr_len(url) - prefix_len;
1443 #ifdef HAVE_LIBSSL
1444 p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ?
1445 HTTPS_PORT : HTTP_PORT;
1446 #else
1447 p->port = HTTP_PORT;
1448 #endif /* HAVE_LIBSSL */
1449 }
1450 /* we have a port, but no path. */
1451 else if (slash == -1) {
1452 host_len = colon - prefix_len;
1453 if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
1454 error(0, "URL <%s> has malformed port number.",
1455 octstr_get_cstr(url));
1456 http_urlparse_destroy(p);
1457 return NULL;
1458 }
1459 }
1460 /* we have a path, but no port. */
1461 else if (colon == -1 || colon > slash) {
1462 host_len = slash - prefix_len;
1463 #ifdef HAVE_LIBSSL
1464 p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ?
1465 HTTPS_PORT : HTTP_PORT;
1466 #else
1467 p->port = HTTP_PORT;
1468 #endif /* HAVE_LIBSSL */
1469 }
1470 /* we have both, path and port. */
1471 else if (colon < slash) {
1472 host_len = colon - prefix_len;
1473 if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
1474 error(0, "URL <%s> has malformed port number.",
1475 octstr_get_cstr(url));
1476 http_urlparse_destroy(p);
1477 return NULL;
1478 }
1479 /* none of the above, so there is something wrong here */
1480 } else {
1481 error(0, "Internal error in URL parsing logic.");
1482 http_urlparse_destroy(p);
1483 return NULL;
1484 }
1485
1486 /* there was an authenticator separator, so try to parse
1487 * the username and password credentials */
1488 if (at != -1) {
1489 int at2;
1490
1491 at2 = octstr_search_char(url, '@', prefix_len);
1492 p->user = octstr_copy(url, prefix_len, at2 - prefix_len);
1493 p->pass = (at2 != at) ? octstr_copy(url, at2 + 1, at - at2 - 1) : NULL;
1494
1495 if (auth_sep != -1)
1496 octstr_set_char(url, auth_sep, ':');
1497
1498 host_len = host_len - at + prefix_len - 1;
1499 prefix_len = at + 1;
1500 }
1501
1502 /* query (CGI vars) */
1503 query = octstr_search_char(url, '?', (slash == -1) ? prefix_len : slash);
1504 if (query != -1) {
1505 p->query = octstr_copy(url, query + 1, octstr_len(url));
1506 if (colon == -1)
1507 host_len = slash != -1 ? slash - prefix_len : query - prefix_len;
1508 }
1509
1510 /* path */
1511 p->path = (slash == -1) ?
1512 octstr_create("/") : ((query != -1) && (query > slash) ?
1513 octstr_copy(url, slash, query - slash) :
1514 octstr_copy(url, slash, octstr_len(url) - slash));
1515
1516 /* hostname */
1517 p->host = octstr_copy(url, prefix_len, host_len);
1518
1519 /* XXX add fragment too */
1520
1521 /* dump components */
1522 parse_dump(p);
1523
1524 return p;
1525 }
1526
1527 /* copy all relevant parsed data to the server info struct */
parse2trans(HTTPURLParse * p,HTTPServer * t)1528 static void parse2trans(HTTPURLParse *p, HTTPServer *t)
1529 {
1530 if (p == NULL || t == NULL)
1531 return;
1532
1533 if (p->user && !t->username)
1534 t->username = octstr_duplicate(p->user);
1535 if (p->pass && !t->password)
1536 t->password = octstr_duplicate(p->pass);
1537 if (p->host && !t->host)
1538 t->host = octstr_duplicate(p->host);
1539 if (p->port && !t->port)
1540 t->port = p->port;
1541 if (p->path && !t->uri) {
1542 t->uri = octstr_duplicate(p->path);
1543 if (p->query) { /* add the query too */
1544 octstr_append_char(t->uri, '?');
1545 octstr_append(t->uri, p->query);
1546 }
1547 }
1548 t->ssl = (p->scheme && (octstr_compare(p->scheme, octstr_imm("https://")) == 0)
1549 && !t->ssl) ? 1 : 0;
1550 }
1551
get_connection(HTTPServer * trans)1552 static Connection *get_connection(HTTPServer *trans)
1553 {
1554 Connection *conn = NULL;
1555 Octstr *host;
1556 HTTPURLParse *p;
1557 int port, ssl;
1558
1559 /* if the parsing has not yet been done, then do it now */
1560 if (!trans->host && trans->port == 0 && trans->url != NULL) {
1561 if ((p = parse_url(trans->url)) != NULL) {
1562 parse2trans(p, trans);
1563 http_urlparse_destroy(p);
1564 } else {
1565 goto error;
1566 }
1567 }
1568
1569 if (proxy_used_for_host(trans->host, trans->url)) {
1570 host = proxy_hostname;
1571 port = proxy_port;
1572 ssl = proxy_ssl;
1573 } else {
1574 host = trans->host;
1575 port = trans->port;
1576 ssl = trans->ssl;
1577 }
1578
1579 conn = conn_pool_get(host, port, ssl, trans->certkeyfile,
1580 http_interface);
1581 if (conn == NULL)
1582 goto error;
1583
1584 return conn;
1585
1586 error:
1587 conn_destroy(conn);
1588 error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
1589 return NULL;
1590 }
1591
1592
1593 /*
1594 * Build and send the HTTP request. Return 0 for success or -1 for error.
1595 */
send_request(HTTPServer * trans)1596 static int send_request(HTTPServer *trans)
1597 {
1598 char buf[128];
1599 Octstr *request = NULL;
1600
1601 if (trans->method == HTTP_METHOD_POST) {
1602 /*
1603 * Add a Content-Length header. Override an existing one, if
1604 * necessary. We must have an accurate one in order to use the
1605 * connection for more than a single request.
1606 */
1607 http_header_remove_all(trans->request_headers, "Content-Length");
1608 snprintf(buf, sizeof(buf), "%ld", octstr_len(trans->request_body));
1609 http_header_add(trans->request_headers, "Content-Length", buf);
1610 }
1611 /*
1612 * ok, this has to be an GET or HEAD request method then,
1613 * if it contains a body, then this is not HTTP conform, so at
1614 * least warn the user
1615 */
1616 else if (trans->request_body != NULL) {
1617 warning(0, "HTTP: GET or HEAD method request contains body:");
1618 octstr_dump(trans->request_body, 0);
1619 }
1620
1621 /*
1622 * we have to assume all values in trans are already set
1623 * by parse_url() before calling this.
1624 */
1625
1626 if (trans->username != NULL)
1627 http_add_basic_auth(trans->request_headers, trans->username,
1628 trans->password);
1629
1630 if (proxy_used_for_host(trans->host, trans->url)) {
1631 proxy_add_authentication(trans->request_headers);
1632 request = build_request(http_method2name(trans->method), trans->url,
1633 trans->host, trans->port, trans->ssl,
1634 trans->request_headers,
1635 trans->request_body);
1636 } else {
1637 request = build_request(http_method2name(trans->method), trans->uri,
1638 trans->host, trans->port, trans->ssl,
1639 trans->request_headers,
1640 trans->request_body);
1641 }
1642
1643 debug("gwlib.http", 0, "HTTP: Sending request:");
1644 octstr_dump(request, 0);
1645 if (conn_write(trans->conn, request) == -1)
1646 goto error;
1647
1648 octstr_destroy(request);
1649
1650 return 0;
1651
1652 error:
1653 conn_destroy(trans->conn);
1654 trans->conn = NULL;
1655 octstr_destroy(request);
1656 error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
1657 return -1;
1658 }
1659
1660
1661 /*
1662 * This thread starts the transaction: it connects to the server and sends
1663 * the request. It then sends the transaction to the read_response_thread
1664 * via started_requests_queue.
1665 */
write_request_thread(void * arg)1666 static void write_request_thread(void *arg)
1667 {
1668 HTTPServer *trans;
1669 int rc;
1670
1671 while (run_status == running) {
1672 trans = gwlist_consume(pending_requests);
1673 if (trans == NULL)
1674 break;
1675
1676 gw_assert(trans->state == request_not_sent);
1677
1678 debug("gwlib.http", 0, "Queue contains %ld pending requests.", gwlist_len(pending_requests));
1679
1680 /*
1681 * get the connection to use
1682 * also calls parse_url() to populate the trans values
1683 */
1684 trans->conn = get_connection(trans);
1685
1686 if (trans->conn == NULL)
1687 gwlist_produce(trans->caller, trans);
1688 else if (conn_is_connected(trans->conn) == 0) {
1689 debug("gwlib.http", 0, "Socket connected at once");
1690
1691 if ((rc = send_request(trans)) == 0) {
1692 trans->state = reading_status;
1693 conn_register(trans->conn, client_fdset, handle_transaction,
1694 trans);
1695 } else {
1696 gwlist_produce(trans->caller, trans);
1697 }
1698
1699 } else { /* Socket not connected, wait for connection */
1700 debug("gwlib.http", 0, "Socket connecting");
1701 trans->state = connecting;
1702 conn_register(trans->conn, client_fdset, handle_transaction, trans);
1703 }
1704 }
1705 }
1706
1707
start_client_threads(void)1708 static void start_client_threads(void)
1709 {
1710 if (!client_threads_are_running) {
1711 /*
1712 * To be really certain, we must repeat the test, but use the
1713 * lock first. If the test failed, however, we _know_ we've
1714 * already initialized. This strategy of double testing avoids
1715 * using the lock more than a few times at startup.
1716 */
1717 mutex_lock(client_thread_lock);
1718 if (!client_threads_are_running) {
1719 client_fdset = fdset_create_real(http_client_timeout);
1720 if (gwthread_create(write_request_thread, NULL) == -1) {
1721 error(0, "HTTP: Could not start client write_request thread.");
1722 fdset_destroy(client_fdset);
1723 client_threads_are_running = 0;
1724 } else
1725 client_threads_are_running = 1;
1726 }
1727 mutex_unlock(client_thread_lock);
1728 }
1729 }
1730
http_set_interface(const Octstr * our_host)1731 void http_set_interface(const Octstr *our_host)
1732 {
1733 http_interface = octstr_duplicate(our_host);
1734 }
1735
http_set_client_timeout(long timeout)1736 void http_set_client_timeout(long timeout)
1737 {
1738 http_client_timeout = timeout;
1739 if (client_fdset != NULL) {
1740 /* we are already initialized set timeout in fdset */
1741 fdset_set_timeout(client_fdset, http_client_timeout);
1742 }
1743 }
1744
http_start_request(HTTPCaller * caller,int method,Octstr * url,List * headers,Octstr * body,int follow,void * id,Octstr * certkeyfile)1745 void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers,
1746 Octstr *body, int follow, void *id, Octstr *certkeyfile)
1747 {
1748 HTTPServer *trans;
1749 int follow_remaining;
1750
1751 if (follow)
1752 follow_remaining = HTTP_MAX_FOLLOW;
1753 else
1754 follow_remaining = 0;
1755
1756 trans = server_create(caller, method, url, headers, body, follow_remaining,
1757 certkeyfile);
1758
1759 if (id == NULL)
1760 /* We don't leave this NULL so http_receive_result can use NULL
1761 * to signal no more requests */
1762 trans->request_id = http_start_request;
1763 else
1764 trans->request_id = id;
1765
1766 gwlist_produce(pending_requests, trans);
1767 start_client_threads();
1768 }
1769
1770
http_receive_result_real(HTTPCaller * caller,int * status,Octstr ** final_url,List ** headers,Octstr ** body,int blocking)1771 void *http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url,
1772 List **headers, Octstr **body, int blocking)
1773 {
1774 HTTPServer *trans;
1775 void *request_id;
1776
1777 if (blocking == 0)
1778 trans = gwlist_extract_first(caller);
1779 else
1780 trans = gwlist_consume(caller);
1781 if (trans == NULL)
1782 return NULL;
1783
1784 request_id = trans->request_id;
1785 *status = trans->status;
1786
1787 if (trans->status >= 0) {
1788 *final_url = trans->url;
1789 *headers = trans->response->headers;
1790 *body = trans->response->body;
1791
1792 trans->url = NULL;
1793 trans->response->headers = NULL;
1794 trans->response->body = NULL;
1795 } else {
1796 *final_url = NULL;
1797 *headers = NULL;
1798 *body = NULL;
1799 }
1800
1801 server_destroy(trans);
1802 return request_id;
1803 }
1804
1805
http_get_real(int method,Octstr * url,List * request_headers,Octstr ** final_url,List ** reply_headers,Octstr ** reply_body)1806 int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url,
1807 List **reply_headers, Octstr **reply_body)
1808 {
1809 HTTPCaller *caller;
1810 int status;
1811 void *ret;
1812
1813 caller = http_caller_create();
1814 http_start_request(caller, method, url, request_headers,
1815 NULL, 1, http_get_real, NULL);
1816 ret = http_receive_result(caller, &status, final_url,
1817 reply_headers, reply_body);
1818 http_caller_destroy(caller);
1819 if (ret == NULL)
1820 return -1;
1821 return status;
1822 }
1823
1824
client_init(void)1825 static void client_init(void)
1826 {
1827 pending_requests = gwlist_create();
1828 gwlist_add_producer(pending_requests);
1829 client_thread_lock = mutex_create();
1830 }
1831
1832
client_shutdown(void)1833 static void client_shutdown(void)
1834 {
1835 gwlist_remove_producer(pending_requests);
1836 gwthread_join_every(write_request_thread);
1837 client_threads_are_running = 0;
1838 gwlist_destroy(pending_requests, server_destroy);
1839 mutex_destroy(client_thread_lock);
1840 fdset_destroy(client_fdset);
1841 client_fdset = NULL;
1842 octstr_destroy(http_interface);
1843 http_interface = NULL;
1844 }
1845
1846
1847 /***********************************************************************
1848 * HTTP server interface.
1849 */
1850
1851
1852 /*
1853 * Information about a client that has connected to the server we implement.
1854 */
1855 struct HTTPClient {
1856 int port;
1857 Connection *conn;
1858 Octstr *ip;
1859 enum {
1860 reading_request_line,
1861 reading_request,
1862 request_is_being_handled,
1863 sending_reply
1864 } state;
1865 int method; /* HTTP_METHOD_ value */
1866 Octstr *url;
1867 int use_version_1_0;
1868 int persistent_conn;
1869 unsigned long conn_time; /* store time for timeouting */
1870 HTTPEntity *request;
1871 };
1872
1873
1874 /*
1875 * Variables related to server side implementation.
1876 */
1877 static Mutex *server_thread_lock = NULL;
1878 static volatile sig_atomic_t server_thread_is_running = 0;
1879 static long server_thread_id = -1;
1880 static List *new_server_sockets = NULL;
1881 static List *closed_server_sockets = NULL;
1882 static int keep_servers_open = 0;
1883 /* List with all active HTTPClient's */
1884 static List *active_connections;
1885
1886
client_create(int port,Connection * conn,Octstr * ip)1887 static HTTPClient *client_create(int port, Connection *conn, Octstr *ip)
1888 {
1889 HTTPClient *p;
1890
1891 #ifdef HAVE_LIBSSL
1892 if (conn_get_ssl(conn))
1893 debug("gwlib.http", 0, "HTTP: Creating SSL-enabled HTTPClient for `%s', using cipher '%s'.",
1894 octstr_get_cstr(ip), SSL_get_cipher_version(conn_get_ssl(conn)));
1895 else
1896 #endif
1897 debug("gwlib.http", 0, "HTTP: Creating HTTPClient for `%s'.", octstr_get_cstr(ip));
1898 p = gw_malloc(sizeof(*p));
1899 p->port = port;
1900 p->conn = conn;
1901 p->ip = ip;
1902 p->state = reading_request_line;
1903 p->url = NULL;
1904 p->use_version_1_0 = 0;
1905 p->persistent_conn = 1;
1906 p->conn_time = time(NULL);
1907 p->request = NULL;
1908 debug("gwlib.http", 0, "HTTP: Created HTTPClient area %p.", p);
1909
1910 /* add this client to active_connections */
1911 gwlist_produce(active_connections, p);
1912
1913 return p;
1914 }
1915
1916
client_destroy(void * client)1917 static void client_destroy(void *client)
1918 {
1919 HTTPClient *p;
1920 long a_len;
1921
1922 if (client == NULL)
1923 return;
1924
1925 p = client;
1926
1927 /* drop this client from active_connections list */
1928 gwlist_lock(active_connections);
1929 if (gwlist_delete_equal(active_connections, p) != 1)
1930 panic(0, "HTTP: Race condition in client_destroy(%p) detected!", client);
1931
1932 /* signal server thread that client slot is free */
1933 a_len = gwlist_len(active_connections);
1934 gwlist_unlock(active_connections);
1935
1936 if (a_len >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS - 1)
1937 gwthread_wakeup(server_thread_id);
1938
1939 debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p);
1940 gw_assert_allocated(p, __FILE__, __LINE__, __func__);
1941 debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.",
1942 octstr_get_cstr(p->ip));
1943
1944 conn_destroy(p->conn);
1945 octstr_destroy(p->ip);
1946 octstr_destroy(p->url);
1947 entity_destroy(p->request);
1948 gw_free(p);
1949 }
1950
1951
client_reset(HTTPClient * p)1952 static void client_reset(HTTPClient *p)
1953 {
1954 debug("gwlib.http", 0, "HTTP: Resetting HTTPClient for `%s'.",
1955 octstr_get_cstr(p->ip));
1956 p->state = reading_request_line;
1957 p->conn_time = time(NULL);
1958 gw_assert(p->request == NULL);
1959 }
1960
1961
1962 /*
1963 * Checks whether the client connection is meant to be persistent or not.
1964 * Returns 1 for true, 0 for false.
1965 */
1966
client_is_persistent(List * headers,int use_version_1_0)1967 static int client_is_persistent(List *headers, int use_version_1_0)
1968 {
1969 Octstr *h = http_header_find_first(headers, "Connection");
1970
1971 if (h == NULL) {
1972 return !use_version_1_0;
1973 } else {
1974 List *values = octstr_split(h, octstr_imm(","));
1975 octstr_destroy(h);
1976 if (!use_version_1_0) {
1977 if (gwlist_search(values, octstr_imm("keep-alive"), octstr_item_case_match) != NULL) {
1978 gwlist_destroy(values, octstr_destroy_item);
1979 return 1;
1980 } else {
1981 gwlist_destroy(values, octstr_destroy_item);
1982 return 0;
1983 }
1984 } else if (gwlist_search(values, octstr_imm("close"), octstr_item_case_match) != NULL) {
1985 gwlist_destroy(values, octstr_destroy_item);
1986 return 0;
1987 }
1988 gwlist_destroy(values, octstr_destroy_item);
1989 }
1990
1991 return 1;
1992 }
1993
1994
1995 /*
1996 * Port specific lists of clients with requests.
1997 */
1998 struct port {
1999 int fd;
2000 int port;
2001 int ssl;
2002 List *clients_with_requests;
2003 Counter *active_consumers;
2004 FDSet *server_fdset;
2005 };
2006
2007
2008 static Mutex *port_mutex = NULL;
2009 static Dict *port_collection = NULL;
2010
2011
port_match(void * client,void * port)2012 static int port_match(void *client, void *port)
2013 {
2014 return ((HTTPClient*)client)->port == *((int*)port);
2015 }
2016
2017
port_init(void)2018 static void port_init(void)
2019 {
2020 port_mutex = mutex_create();
2021 port_collection = dict_create(1024, NULL);
2022 /* create list with all active_connections */
2023 active_connections = gwlist_create();
2024 }
2025
port_shutdown(void)2026 static void port_shutdown(void)
2027 {
2028 mutex_destroy(port_mutex);
2029 dict_destroy(port_collection);
2030 /* destroy active_connections list */
2031 gwlist_destroy(active_connections, client_destroy);
2032 }
2033
2034
port_key(int port)2035 static Octstr *port_key(int port)
2036 {
2037 return octstr_format("%d", port);
2038 }
2039
2040
port_add(int port)2041 static struct port *port_add(int port)
2042 {
2043 Octstr *key;
2044 struct port *p;
2045
2046 key = port_key(port);
2047 mutex_lock(port_mutex);
2048 if ((p = dict_get(port_collection, key)) == NULL) {
2049 p = gw_malloc(sizeof(*p));
2050 p->clients_with_requests = gwlist_create();
2051 gwlist_add_producer(p->clients_with_requests);
2052 p->active_consumers = counter_create();
2053 p->server_fdset = fdset_create_real(HTTP_SERVER_TIMEOUT);
2054 dict_put(port_collection, key, p);
2055 } else {
2056 warning(0, "HTTP: port_add called for existing port (%d)", port);
2057 }
2058 mutex_unlock(port_mutex);
2059 octstr_destroy(key);
2060
2061 return p;
2062 }
2063
2064
port_remove(int port)2065 static void port_remove(int port)
2066 {
2067 Octstr *key;
2068 struct port *p;
2069 List *l;
2070 HTTPClient *client;
2071
2072 key = port_key(port);
2073 mutex_lock(port_mutex);
2074 p = dict_remove(port_collection, key);
2075 mutex_unlock(port_mutex);
2076 octstr_destroy(key);
2077
2078 if (p == NULL) {
2079 error(0, "HTTP: Could not find port (%d) in port_collection.", port);
2080 return;
2081 }
2082
2083 gwlist_remove_producer(p->clients_with_requests);
2084 while (counter_value(p->active_consumers) > 0)
2085 gwthread_sleep(0.1); /* Reasonable use of busy waiting. */
2086
2087 gwlist_destroy(p->clients_with_requests, client_destroy);
2088 counter_destroy(p->active_consumers);
2089
2090 /*
2091 * In order to avoid race conditions with FDSet thread, we
2092 * destroy Clients for this port in two steps:
2093 * 1) unregister from fdset with gwlist_lock held, so client_destroy
2094 * cannot destroy our client that we currently use
2095 * 2) without gwlist_lock held destroy every client, we can do this
2096 * because we only one thread that can use this client struct
2097 */
2098 gwlist_lock(active_connections);
2099 l = gwlist_search_all(active_connections, &port, port_match);
2100 while(l != NULL && (client = gwlist_extract_first(l)) != NULL)
2101 conn_unregister(client->conn);
2102 gwlist_unlock(active_connections);
2103 gwlist_destroy(l, NULL);
2104 while((client = gwlist_search(active_connections, &port, port_match)) != NULL)
2105 client_destroy(client);
2106
2107 /* now destroy fdset */
2108 fdset_destroy(p->server_fdset);
2109 gw_free(p);
2110 }
2111
2112
port_put_request(HTTPClient * client)2113 static void port_put_request(HTTPClient *client)
2114 {
2115 Octstr *key;
2116 struct port *p;
2117
2118 mutex_lock(port_mutex);
2119 key = port_key(client->port);
2120 p = dict_get(port_collection, key);
2121 octstr_destroy(key);
2122 if (p == NULL) {
2123 /* client was too slow and we closed port already */
2124 mutex_unlock(port_mutex);
2125 client_destroy(client);
2126 return;
2127 }
2128 gwlist_produce(p->clients_with_requests, client);
2129 mutex_unlock(port_mutex);
2130 }
2131
2132
port_get_request(int port)2133 static HTTPClient *port_get_request(int port)
2134 {
2135 Octstr *key;
2136 struct port *p;
2137 HTTPClient *client;
2138
2139 mutex_lock(port_mutex);
2140 key = port_key(port);
2141 p = dict_get(port_collection, key);
2142 octstr_destroy(key);
2143
2144 if (p == NULL) {
2145 client = NULL;
2146 mutex_unlock(port_mutex);
2147 } else {
2148 counter_increase(p->active_consumers);
2149 mutex_unlock(port_mutex); /* Placement of this unlock is tricky. */
2150 client = gwlist_consume(p->clients_with_requests);
2151 counter_decrease(p->active_consumers);
2152 }
2153 return client;
2154 }
2155
2156
port_set_timeout(int port,long timeout)2157 static void port_set_timeout(int port, long timeout)
2158 {
2159 Octstr *key;
2160 struct port *p;
2161
2162 mutex_lock(port_mutex);
2163 key = port_key(port);
2164 p = dict_get(port_collection, key);
2165 octstr_destroy(key);
2166
2167 if (p != NULL)
2168 fdset_set_timeout(p->server_fdset, timeout);
2169
2170 mutex_unlock(port_mutex);
2171 }
2172
2173
port_get_fdset(int port)2174 static FDSet *port_get_fdset(int port)
2175 {
2176 Octstr *key;
2177 struct port *p;
2178 FDSet *ret = NULL;
2179
2180 mutex_lock(port_mutex);
2181 key = port_key(port);
2182 p = dict_get(port_collection, key);
2183 octstr_destroy(key);
2184
2185 if (p != NULL)
2186 ret = p->server_fdset;
2187
2188 mutex_unlock(port_mutex);
2189
2190 return ret;
2191 }
2192
2193
parse_request_line(int * method,Octstr ** url,int * use_version_1_0,Octstr * line)2194 static int parse_request_line(int *method, Octstr **url,
2195 int *use_version_1_0, Octstr *line)
2196 {
2197 List *words;
2198 Octstr *version;
2199 Octstr *method_str;
2200 int ret;
2201
2202 words = octstr_split_words(line);
2203 if (gwlist_len(words) != 3) {
2204 gwlist_destroy(words, octstr_destroy_item);
2205 return -1;
2206 }
2207
2208 method_str = gwlist_get(words, 0);
2209 *url = gwlist_get(words, 1);
2210 version = gwlist_get(words, 2);
2211 gwlist_destroy(words, NULL);
2212
2213 if (octstr_compare(method_str, octstr_imm("GET")) == 0)
2214 *method = HTTP_METHOD_GET;
2215 else if (octstr_compare(method_str, octstr_imm("POST")) == 0)
2216 *method = HTTP_METHOD_POST;
2217 else if (octstr_compare(method_str, octstr_imm("HEAD")) == 0)
2218 *method = HTTP_METHOD_HEAD;
2219 else
2220 goto error;
2221
2222 ret = parse_http_version(version);
2223 if (ret < 0)
2224 goto error;
2225 *use_version_1_0 = !ret;
2226
2227 octstr_destroy(method_str);
2228 octstr_destroy(version);
2229 return 0;
2230
2231 error:
2232 octstr_destroy(method_str);
2233 octstr_destroy(*url);
2234 octstr_destroy(version);
2235 *url = NULL;
2236 return -1;
2237 }
2238
2239
receive_request(Connection * conn,void * data)2240 static void receive_request(Connection *conn, void *data)
2241 {
2242 HTTPClient *client;
2243 Octstr *line;
2244 int ret;
2245
2246 if (run_status != running) {
2247 conn_unregister(conn);
2248 return;
2249 }
2250
2251 client = data;
2252
2253 for (;;) {
2254 switch (client->state) {
2255 case reading_request_line:
2256 line = conn_read_line(conn);
2257 if (line == NULL) {
2258 if (conn_eof(conn) || conn_error(conn))
2259 goto error;
2260 return;
2261 }
2262 ret = parse_request_line(&client->method, &client->url,
2263 &client->use_version_1_0, line);
2264 octstr_destroy(line);
2265 /* client sent bad request? */
2266 if (ret == -1) {
2267 /*
2268 * mark client as not persistent in order to destroy connection
2269 * afterwards
2270 */
2271 client->persistent_conn = 0;
2272 /* unregister connection, http_send_reply handle this */
2273 conn_unregister(conn);
2274 http_send_reply(client, HTTP_BAD_REQUEST, NULL, NULL);
2275 return;
2276 }
2277 /*
2278 * RFC2616 (4.3) says we should read a message body if there
2279 * is one, even on GET requests.
2280 */
2281 client->request = entity_create(expect_body_if_indicated);
2282 client->state = reading_request;
2283 break;
2284
2285 case reading_request:
2286 ret = entity_read(client->request, conn);
2287 if (ret < 0)
2288 goto error;
2289 if (ret == 0) {
2290 client->state = request_is_being_handled;
2291 conn_unregister(conn);
2292 port_put_request(client);
2293 }
2294 return;
2295
2296 case sending_reply:
2297 /* Implicit conn_unregister() and _destroy */
2298 if (conn_error(conn))
2299 goto error;
2300 if (conn_outbuf_len(conn) > 0)
2301 return;
2302 /* Reply has been sent completely */
2303 if (!client->persistent_conn) {
2304 /*
2305 * in order to avoid race conditions while conn will be destroyed but
2306 * conn is still in use, we call conn_unregister explicit here because
2307 * conn_unregister call uses locks
2308 */
2309 conn_unregister(conn);
2310 client_destroy(client);
2311 return;
2312 }
2313 /* Start reading another request */
2314 client_reset(client);
2315 break;
2316
2317 default:
2318 panic(0, "Internal error: HTTPClient state is wrong.");
2319 }
2320 }
2321
2322 error:
2323 /*
2324 * in order to avoid race conditions while conn will be destroyed but
2325 * conn is still in use, we call conn_unregister explicit here because
2326 * conn_unregister call uses locks
2327 */
2328 conn_unregister(conn);
2329 client_destroy(client);
2330 }
2331
2332
server_thread(void * dummy)2333 static void server_thread(void *dummy)
2334 {
2335 struct pollfd *tab = NULL;
2336 struct port **ports = NULL;
2337 int tab_size = 0, n, i, fd, ret, max_clients_reached;
2338 struct sockaddr_in addr;
2339 socklen_t addrlen;
2340 HTTPClient *client;
2341 Connection *conn;
2342 int *portno;
2343
2344 n = max_clients_reached = 0;
2345 while (run_status == running && keep_servers_open) {
2346 while (n == 0 || gwlist_len(new_server_sockets) > 0) {
2347 struct port *p = gwlist_consume(new_server_sockets);
2348 if (p == NULL) {
2349 debug("gwlib.http", 0, "HTTP: No new servers. Quitting.");
2350 break;
2351 } else {
2352 debug ("gwlib.http", 0, "HTTP: Including port %d, fd %d for polling in server thread", p->port, p->fd);
2353 }
2354 if (tab_size <= n) {
2355 tab_size++;
2356 tab = gw_realloc(tab, tab_size * sizeof(*tab));
2357 ports = gw_realloc(ports, tab_size * sizeof(*ports));
2358 if (tab == NULL || ports == NULL) {
2359 tab_size--;
2360 port_remove(p->port);
2361 continue;
2362 }
2363 }
2364 tab[n].fd = p->fd;
2365 tab[n].events = POLLIN;
2366 ports[n] = p;
2367 n++;
2368 }
2369
2370 if (max_clients_reached && gwlist_len(active_connections) >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS) {
2371 /* TODO start cleanup of stale connections */
2372 /* wait for slots to become free */
2373 gwthread_sleep(1.0);
2374 } else if (!max_clients_reached && (ret = gwthread_poll(tab, n, -1.0)) == -1) {
2375 if (errno != EINTR) /* a signal was caught during poll() function */
2376 warning(errno, "HTTP: gwthread_poll failed.");
2377 continue;
2378 }
2379
2380 for (i = 0; i < n; ++i) {
2381 if (tab[i].revents & POLLIN) {
2382 /* check our limit */
2383 if (gwlist_len(active_connections) >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS) {
2384 max_clients_reached = 1;
2385 break;
2386 } else {
2387 max_clients_reached = 0;
2388 }
2389
2390 addrlen = sizeof(addr);
2391 fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen);
2392 if (fd == -1) {
2393 error(errno, "HTTP: Error accepting a client.");
2394 } else {
2395 Octstr *client_ip = host_ip(addr);
2396 /*
2397 * Be aware that conn_wrap_fd() will return NULL if SSL
2398 * handshake has failed, so we only client_create() if
2399 * there is an conn.
2400 */
2401 if ((conn = conn_wrap_fd(fd, ports[i]->ssl))) {
2402 client = client_create(ports[i]->port, conn, client_ip);
2403 conn_register(conn, ports[i]->server_fdset, receive_request, client);
2404 } else {
2405 error(0, "HTTP: unsuccessful SSL handshake for client `%s'",
2406 octstr_get_cstr(client_ip));
2407 octstr_destroy(client_ip);
2408 }
2409 }
2410 }
2411 }
2412
2413 while ((portno = gwlist_extract_first(closed_server_sockets)) != NULL) {
2414 for (i = 0; i < n; ++i) {
2415 if (ports[i]->port == *portno) {
2416 (void) close(tab[i].fd);
2417 tab[i].fd = -1;
2418 tab[i].events = 0;
2419 port_remove(ports[i]->port);
2420 ports[i] = NULL;
2421 n--;
2422
2423 /* now put the last entry on this place */
2424 tab[i].fd = tab[n].fd;
2425 tab[i].events = tab[n].events;
2426 tab[n].fd = -1;
2427 tab[n].events = 0;
2428 ports[i] = ports[n];
2429 }
2430 }
2431 gw_free(portno);
2432 }
2433 }
2434
2435 /* make sure we close all ports */
2436 for (i = 0; i < n; ++i) {
2437 (void) close(tab[i].fd);
2438 port_remove(ports[i]->port);
2439 }
2440 gw_free(tab);
2441 gw_free(ports);
2442
2443 server_thread_id = -1;
2444 }
2445
2446
start_server_thread(void)2447 static void start_server_thread(void)
2448 {
2449 if (!server_thread_is_running) {
2450 /*
2451 * To be really certain, we must repeat the test, but use the
2452 * lock first. If the test failed, however, we _know_ we've
2453 * already initialized. This strategy of double testing avoids
2454 * using the lock more than a few times at startup.
2455 */
2456 mutex_lock(server_thread_lock);
2457 if (!server_thread_is_running) {
2458 server_thread_id = gwthread_create(server_thread, NULL);
2459 server_thread_is_running = 1;
2460 }
2461 mutex_unlock(server_thread_lock);
2462 }
2463 }
2464
2465
http_set_server_timeout(int port,long timeout)2466 void http_set_server_timeout(int port, long timeout)
2467 {
2468 port_set_timeout(port, timeout);
2469 }
2470
2471
http_open_port_if(int port,int ssl,Octstr * interface)2472 int http_open_port_if(int port, int ssl, Octstr *interface)
2473 {
2474 struct port *p;
2475
2476 if (ssl)
2477 info(0, "HTTP: Opening SSL server at port %d.", port);
2478 else
2479 info(0, "HTTP: Opening server at port %d.", port);
2480 p = port_add(port);
2481 p->port = port;
2482 p->ssl = ssl;
2483 p->fd = make_server_socket(port, (interface ? octstr_get_cstr(interface) : NULL));
2484 if (p->fd == -1) {
2485 port_remove(port);
2486 return -1;
2487 }
2488
2489 gwlist_produce(new_server_sockets, p);
2490 keep_servers_open = 1;
2491 start_server_thread();
2492 gwthread_wakeup(server_thread_id);
2493
2494 return 0;
2495 }
2496
2497
http_open_port(int port,int ssl)2498 int http_open_port(int port, int ssl)
2499 {
2500 return http_open_port_if(port, ssl, NULL);
2501 }
2502
2503
http_close_port(int port)2504 void http_close_port(int port)
2505 {
2506 int *p;
2507
2508 p = gw_malloc(sizeof(*p));
2509 *p = port;
2510 gwlist_produce(closed_server_sockets, p);
2511 gwthread_wakeup(server_thread_id);
2512 }
2513
2514
http_close_all_ports(void)2515 void http_close_all_ports(void)
2516 {
2517 if (server_thread_id != -1) {
2518 keep_servers_open = 0;
2519 gwthread_wakeup(server_thread_id);
2520 gwthread_join_every(server_thread);
2521 server_thread_is_running = 0;
2522 }
2523 }
2524
2525
2526 /*
2527 * Parse CGI variables from the path given in a GET. Return a list
2528 * of HTTPCGIvar pointers. Modify the url so that the variables are
2529 * removed.
2530 */
parse_cgivars(Octstr * url)2531 static List *parse_cgivars(Octstr *url)
2532 {
2533 HTTPCGIVar *v;
2534 List *list;
2535 int query, et, equals;
2536 Octstr *arg, *args;
2537
2538 query = octstr_search_char(url, '?', 0);
2539 if (query == -1)
2540 return gwlist_create();
2541
2542 args = octstr_copy(url, query + 1, octstr_len(url));
2543 octstr_truncate(url, query);
2544
2545 list = gwlist_create();
2546
2547 while (octstr_len(args) > 0) {
2548 et = octstr_search_char(args, '&', 0);
2549 if (et == -1)
2550 et = octstr_len(args);
2551 arg = octstr_copy(args, 0, et);
2552 octstr_delete(args, 0, et + 1);
2553
2554 equals = octstr_search_char(arg, '=', 0);
2555 if (equals == -1)
2556 equals = octstr_len(arg);
2557
2558 v = gw_malloc(sizeof(HTTPCGIVar));
2559 v->name = octstr_copy(arg, 0, equals);
2560 v->value = octstr_copy(arg, equals + 1, octstr_len(arg));
2561 octstr_url_decode(v->name);
2562 octstr_url_decode(v->value);
2563
2564 octstr_destroy(arg);
2565
2566 gwlist_append(list, v);
2567 }
2568 octstr_destroy(args);
2569
2570 return list;
2571 }
2572
2573
http_accept_request(int port,Octstr ** client_ip,Octstr ** url,List ** headers,Octstr ** body,List ** cgivars)2574 HTTPClient *http_accept_request(int port, Octstr **client_ip, Octstr **url,
2575 List **headers, Octstr **body,
2576 List **cgivars)
2577 {
2578 HTTPClient *client;
2579
2580 do {
2581 client = port_get_request(port);
2582 if (client == NULL) {
2583 debug("gwlib.http", 0, "HTTP: No clients with requests, quitting.");
2584 return NULL;
2585 }
2586 /* check whether client connection still ok */
2587 conn_wait(client->conn, 0);
2588 if (conn_error(client->conn) || conn_eof(client->conn)) {
2589 client_destroy(client);
2590 client = NULL;
2591 }
2592 } while(client == NULL);
2593
2594 *client_ip = octstr_duplicate(client->ip);
2595 *url = client->url;
2596 *headers = client->request->headers;
2597 *body = client->request->body;
2598 *cgivars = parse_cgivars(client->url);
2599
2600 if (client->method != HTTP_METHOD_POST) {
2601 octstr_destroy(*body);
2602 *body = NULL;
2603 }
2604
2605 client->persistent_conn = client_is_persistent(client->request->headers,
2606 client->use_version_1_0);
2607
2608 client->url = NULL;
2609 client->request->headers = NULL;
2610 client->request->body = NULL;
2611 entity_destroy(client->request);
2612 client->request = NULL;
2613
2614 return client;
2615 }
2616
2617 /*
2618 * The http_send_reply(...) uses this function to determinate the
2619 * reason pahrase for a status code.
2620 */
http_reason_phrase(int status)2621 static const char *http_reason_phrase(int status)
2622 {
2623 switch (status) {
2624 case HTTP_OK:
2625 return "OK"; /* 200 */
2626 case HTTP_CREATED:
2627 return "Created"; /* 201 */
2628 case HTTP_ACCEPTED:
2629 return "Accepted"; /* 202 */
2630 case HTTP_NO_CONTENT:
2631 return "No Content"; /* 204 */
2632 case HTTP_RESET_CONTENT:
2633 return "Reset Content"; /* 205 */
2634 case HTTP_MOVED_PERMANENTLY:
2635 return "Moved Permanently"; /* 301 */
2636 case HTTP_FOUND:
2637 return "Found"; /* 302 */
2638 case HTTP_SEE_OTHER:
2639 return "See Other"; /* 303 */
2640 case HTTP_NOT_MODIFIED:
2641 return "Not Modified"; /* 304 */
2642 case HTTP_TEMPORARY_REDIRECT:
2643 return "Temporary Redirect"; /* 307 */
2644 case HTTP_BAD_REQUEST:
2645 return "Bad Request"; /* 400 */
2646 case HTTP_UNAUTHORIZED:
2647 return "Unauthorized"; /* 401 */
2648 case HTTP_FORBIDDEN:
2649 return "Forbidden"; /* 403 */
2650 case HTTP_NOT_FOUND:
2651 return "Not Found"; /* 404 */
2652 case HTTP_BAD_METHOD:
2653 return "Method Not Allowed"; /* 405 */
2654 case HTTP_NOT_ACCEPTABLE:
2655 return "Not Acceptable"; /* 406 */
2656 case HTTP_REQUEST_ENTITY_TOO_LARGE:
2657 return "Request Entity Too Large"; /* 413 */
2658 case HTTP_UNSUPPORTED_MEDIA_TYPE:
2659 return "Unsupported Media Type"; /* 415 */
2660 case HTTP_INTERNAL_SERVER_ERROR:
2661 return "Internal Server Error"; /* 500 */
2662 case HTTP_NOT_IMPLEMENTED:
2663 return "Not Implemented"; /* 501 */
2664 case HTTP_BAD_GATEWAY:
2665 return "Bad Gateway"; /* 502 */
2666 }
2667 return "Foo";
2668 }
2669
2670
http_send_reply(HTTPClient * client,int status,List * headers,Octstr * body)2671 void http_send_reply(HTTPClient *client, int status, List *headers,
2672 Octstr *body)
2673 {
2674 Octstr *response;
2675 Octstr *date;
2676 long i;
2677 int ret;
2678
2679 if (client->use_version_1_0)
2680 response = octstr_format("HTTP/1.0 %d %s\r\n", status, http_reason_phrase(status));
2681 else
2682 response = octstr_format("HTTP/1.1 %d %s\r\n", status, http_reason_phrase(status));
2683
2684 /* identify ourselfs */
2685 octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION);
2686
2687 /* let's inform the client of our time */
2688 date = date_format_http(time(NULL));
2689 octstr_format_append(response, "Date: %s\r\n", octstr_get_cstr(date));
2690 octstr_destroy(date);
2691
2692 octstr_format_append(response, "Content-Length: %ld\r\n", octstr_len(body));
2693
2694 /*
2695 * RFC2616, sec. 8.1.2.1 says that if the server chooses to close the
2696 * connection, it *should* send a coresponding header
2697 */
2698 if (!client->use_version_1_0 && !client->persistent_conn)
2699 octstr_format_append(response, "Connection: close\r\n");
2700
2701 for (i = 0; i < gwlist_len(headers); ++i)
2702 octstr_format_append(response, "%S\r\n", gwlist_get(headers, i));
2703 octstr_format_append(response, "\r\n");
2704
2705 if (body != NULL && client->method != HTTP_METHOD_HEAD)
2706 octstr_append(response, body);
2707
2708 ret = conn_write(client->conn, response);
2709 octstr_destroy(response);
2710
2711 /* obey return code of conn_write() */
2712 /* sending response was successful */
2713 if (ret == 0) {
2714 /* HTTP/1.0 or 1.1, hence keep-alive or keep-alive */
2715 if (!client->persistent_conn) {
2716 client_destroy(client);
2717 } else {
2718 /* XXX mark this HTTPClient in the keep-alive cleaner thread */
2719 client_reset(client);
2720 conn_register(client->conn, port_get_fdset(client->port), receive_request, client);
2721 }
2722 }
2723 /* queued for sending, we don't want to block */
2724 else if (ret == 1) {
2725 client->state = sending_reply;
2726 conn_register(client->conn, port_get_fdset(client->port), receive_request, client);
2727 }
2728 /* error while sending response */
2729 else {
2730 client_destroy(client);
2731 }
2732 }
2733
2734
http_close_client(HTTPClient * client)2735 void http_close_client(HTTPClient *client)
2736 {
2737 client_destroy(client);
2738 }
2739
http_method(HTTPClient * client)2740 int http_method(HTTPClient *client)
2741 {
2742 return client->method;
2743 }
2744
http_request_url(HTTPClient * client)2745 Octstr *http_request_url(HTTPClient *client)
2746 {
2747 return client->url;
2748 }
2749
server_init(void)2750 static void server_init(void)
2751 {
2752 new_server_sockets = gwlist_create();
2753 gwlist_add_producer(new_server_sockets);
2754 closed_server_sockets = gwlist_create();
2755 server_thread_lock = mutex_create();
2756 }
2757
2758
destroy_struct_server(void * p)2759 static void destroy_struct_server(void *p)
2760 {
2761 struct port *pp;
2762
2763 pp = p;
2764 (void) close(pp->fd);
2765 port_remove(pp->port);
2766 }
2767
2768
destroy_int_pointer(void * p)2769 static void destroy_int_pointer(void *p)
2770 {
2771 (void) close(*(int *) p);
2772 gw_free(p);
2773 }
2774
2775
server_shutdown(void)2776 static void server_shutdown(void)
2777 {
2778 gwlist_remove_producer(new_server_sockets);
2779 if (server_thread_id != -1) {
2780 gwthread_wakeup(server_thread_id);
2781 gwthread_join_every(server_thread);
2782 server_thread_is_running = 0;
2783 }
2784 mutex_destroy(server_thread_lock);
2785 gwlist_destroy(new_server_sockets, destroy_struct_server);
2786 gwlist_destroy(closed_server_sockets, destroy_int_pointer);
2787 }
2788
2789
2790 /***********************************************************************
2791 * CGI variable manipulation.
2792 */
2793
2794
http_destroy_cgiargs(List * args)2795 void http_destroy_cgiargs(List *args)
2796 {
2797 HTTPCGIVar *v;
2798
2799 gwlib_assert_init();
2800
2801 if (args == NULL)
2802 return ;
2803
2804 while ((v = gwlist_extract_first(args)) != NULL) {
2805 octstr_destroy(v->name);
2806 octstr_destroy(v->value);
2807 gw_free(v);
2808 }
2809 gwlist_destroy(args, NULL);
2810 }
2811
2812
http_cgi_variable(List * list,char * name)2813 Octstr *http_cgi_variable(List *list, char *name)
2814 {
2815 int i;
2816 HTTPCGIVar *v;
2817
2818 gwlib_assert_init();
2819 gw_assert(list != NULL);
2820 gw_assert(name != NULL);
2821
2822 for (i = 0; i < gwlist_len(list); ++i) {
2823 v = gwlist_get(list, i);
2824 if (octstr_str_compare(v->name, name) == 0)
2825 return v->value;
2826 }
2827 return NULL;
2828 }
2829
2830
2831 /***********************************************************************
2832 * Header manipulation.
2833 */
2834
2835
header_is_called(Octstr * header,char * name)2836 static int header_is_called(Octstr *header, char *name)
2837 {
2838 long colon;
2839
2840 colon = octstr_search_char(header, ':', 0);
2841 if (colon == -1)
2842 return 0;
2843 if ((long) strlen(name) != colon)
2844 return 0;
2845 return strncasecmp(octstr_get_cstr(header), name, colon) == 0;
2846 }
2847
2848
http_create_empty_headers(void)2849 List *http_create_empty_headers(void)
2850 {
2851 gwlib_assert_init();
2852 return gwlist_create();
2853 }
2854
2855
http_destroy_headers(List * headers)2856 void http_destroy_headers(List *headers)
2857 {
2858 gwlib_assert_init();
2859 gwlist_destroy(headers, octstr_destroy_item);
2860 }
2861
2862
http_header_add(List * headers,char * name,char * contents)2863 void http_header_add(List *headers, char *name, char *contents)
2864 {
2865 gwlib_assert_init();
2866 gw_assert(headers != NULL);
2867 gw_assert(name != NULL);
2868 gw_assert(contents != NULL);
2869
2870 gwlist_append(headers, octstr_format("%s: %s", name, contents));
2871 }
2872
2873
2874 /*
2875 * Given an headers list and a position, returns its header name and value,
2876 * or (X-Unknown, header) if it doesn't exist or if it's malformed - missing
2877 * ":" for example
2878 */
http_header_get(List * headers,long i,Octstr ** name,Octstr ** value)2879 void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
2880 {
2881 Octstr *os;
2882 long colon;
2883
2884 gwlib_assert_init();
2885 gw_assert(i >= 0);
2886 gw_assert(name != NULL);
2887 gw_assert(value != NULL);
2888
2889 os = gwlist_get(headers, i);
2890 if (os == NULL)
2891 colon = -1;
2892 else
2893 colon = octstr_search_char(os, ':', 0);
2894 if (colon == -1) {
2895 error(0, "HTTP: Header does not contain a colon. BAD.");
2896 *name = octstr_create("X-Unknown");
2897 *value = octstr_duplicate(os);
2898 } else {
2899 *name = octstr_copy(os, 0, colon);
2900 *value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1);
2901 octstr_strip_blanks(*value);
2902 }
2903 }
2904
2905 /*
2906 * Given an headers list and a name, returns its value or NULL if it
2907 * doesn't exist
2908 */
http_header_value(List * headers,Octstr * name)2909 Octstr *http_header_value(List *headers, Octstr *name)
2910 {
2911 Octstr *value;
2912 long i;
2913 Octstr *os;
2914 long colon;
2915 Octstr *current_name;
2916
2917 gwlib_assert_init();
2918 gw_assert(name);
2919
2920 value = NULL;
2921 i = 0;
2922 while (i < gwlist_len(headers)) {
2923 os = gwlist_get(headers, i);
2924 if (os == NULL)
2925 colon = -1;
2926 else
2927 colon = octstr_search_char(os, ':', 0);
2928 if (colon == -1) {
2929 return NULL;
2930 } else {
2931 current_name = octstr_copy(os, 0, colon);
2932 }
2933 if (octstr_case_compare(current_name, name) == 0) {
2934 value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1);
2935 octstr_strip_blanks(value);
2936 octstr_destroy(current_name);
2937 return value;
2938 }
2939 octstr_destroy(current_name);
2940 ++i;
2941 }
2942
2943 return NULL;
2944 }
2945
http_header_duplicate(List * headers)2946 List *http_header_duplicate(List *headers)
2947 {
2948 List *new;
2949 long i, len;
2950
2951 gwlib_assert_init();
2952
2953 if (headers == NULL)
2954 return NULL;
2955
2956 new = http_create_empty_headers();
2957 len = gwlist_len(headers);
2958 for (i = 0; i < len; ++i)
2959 gwlist_append(new, octstr_duplicate(gwlist_get(headers, i)));
2960 return new;
2961 }
2962
2963
2964 #define MAX_HEADER_LENGTH 256
2965 /*
2966 * Aggregate header in one (or more) lines with several parameters separated
2967 * by commas, instead of one header per parameter
2968 */
http_header_pack(List * headers)2969 void http_header_pack(List *headers)
2970 {
2971 Octstr *name, *value;
2972 Octstr *name2, *value2;
2973 long i, j;
2974
2975 gwlib_assert_init();
2976 gw_assert(headers != NULL);
2977
2978 /*
2979 * For each header, search forward headers for similar ones and if possible,
2980 * add it to current header and delete it
2981 */
2982 for(i = 0; i < gwlist_len(headers); i++) {
2983 http_header_get(headers, i, &name, &value);
2984 /* debug("http_header_pack", 0, "HTTP_HEADER_PACK: Processing header %d. [%s: %s]",
2985 i, octstr_get_cstr(name), octstr_get_cstr(value)); */
2986
2987 for(j=i+1; j < gwlist_len(headers); j++) {
2988 http_header_get(headers, j, &name2, &value2);
2989
2990 if(octstr_case_compare(name, name2) == 0) {
2991 if(octstr_len(value) + 2 + octstr_len(value2) > MAX_HEADER_LENGTH) {
2992 octstr_destroy(name2);
2993 octstr_destroy(value2);
2994 break;
2995 } else {
2996 Octstr *header;
2997
2998 /* Delete old header */
2999 header = gwlist_get(headers, i);
3000 octstr_destroy(header);
3001 gwlist_delete(headers, i, 1);
3002
3003 /* Adds comma and new value to old header value */
3004 octstr_append(value, octstr_imm(", "));
3005 octstr_append(value, value2);
3006 /* Creates a new header */
3007 header = octstr_create("");
3008 octstr_append(header, name);
3009 octstr_append(header, octstr_imm(": "));
3010 octstr_append(header, value);
3011 gwlist_insert(headers, i, header);
3012
3013 /* Delete this header */
3014 header = gwlist_get(headers, j);
3015 octstr_destroy(header);
3016 gwlist_delete(headers, j, 1);
3017 j--;
3018 }
3019 }
3020 octstr_destroy(name2);
3021 octstr_destroy(value2);
3022 }
3023 octstr_destroy(name);
3024 octstr_destroy(value);
3025 }
3026 }
3027
3028
http_append_headers(List * to,List * from)3029 void http_append_headers(List *to, List *from)
3030 {
3031 Octstr *header;
3032 long i;
3033
3034 gwlib_assert_init();
3035 gw_assert(to != NULL);
3036 gw_assert(from != NULL);
3037
3038 for (i = 0; i < gwlist_len(from); ++i) {
3039 header = gwlist_get(from, i);
3040 gwlist_append(to, octstr_duplicate(header));
3041 }
3042 }
3043
3044
http_header_combine(List * old_headers,List * new_headers)3045 void http_header_combine(List *old_headers, List *new_headers)
3046 {
3047 long i;
3048 Octstr *name;
3049 Octstr *value;
3050
3051 /*
3052 * Avoid doing this scan if old_headers is empty anyway.
3053 */
3054 if (gwlist_len(old_headers) > 0) {
3055 for (i = 0; i < gwlist_len(new_headers); i++) {
3056 http_header_get(new_headers, i, &name, &value);
3057 http_header_remove_all(old_headers, octstr_get_cstr(name));
3058 octstr_destroy(name);
3059 octstr_destroy(value);
3060 }
3061 }
3062
3063 http_append_headers(old_headers, new_headers);
3064 }
3065
3066
http_header_find_first_real(List * headers,char * name,const char * file,long line,const char * func)3067 Octstr *http_header_find_first_real(List *headers, char *name, const char *file, long line,
3068 const char *func)
3069 {
3070 long i, name_len;
3071 Octstr *h, *value;
3072
3073 gwlib_assert_init();
3074 gw_assert(headers != NULL);
3075 gw_assert(name != NULL);
3076
3077 name_len = strlen(name);
3078
3079 for (i = 0; i < gwlist_len(headers); ++i) {
3080 h = gwlist_get(headers, i);
3081 if (header_is_called(h, name)) {
3082 value = octstr_copy_real(h, name_len + 1, octstr_len(h),
3083 file, line, func);
3084 octstr_strip_blanks(value);
3085 return value;
3086 }
3087 }
3088 return NULL;
3089 }
3090
3091
http_header_find_all(List * headers,char * name)3092 List *http_header_find_all(List *headers, char *name)
3093 {
3094 List *list;
3095 long i;
3096 Octstr *h;
3097
3098 gwlib_assert_init();
3099 gw_assert(headers != NULL);
3100 gw_assert(name != NULL);
3101
3102 list = gwlist_create();
3103 for (i = 0; i < gwlist_len(headers); ++i) {
3104 h = gwlist_get(headers, i);
3105 if (header_is_called(h, name))
3106 gwlist_append(list, octstr_duplicate(h));
3107 }
3108 return list;
3109 }
3110
3111
http_header_remove_all(List * headers,char * name)3112 long http_header_remove_all(List *headers, char *name)
3113 {
3114 long i;
3115 Octstr *h;
3116 long count;
3117
3118 gwlib_assert_init();
3119 gw_assert(headers != NULL);
3120 gw_assert(name != NULL);
3121
3122 i = 0;
3123 count = 0;
3124 while (i < gwlist_len(headers)) {
3125 h = gwlist_get(headers, i);
3126 if (header_is_called(h, name)) {
3127 gwlist_delete(headers, i, 1);
3128 octstr_destroy(h);
3129 count++;
3130 } else
3131 i++;
3132 }
3133
3134 return count;
3135 }
3136
3137
http_remove_hop_headers(List * headers)3138 void http_remove_hop_headers(List *headers)
3139 {
3140 Octstr *h;
3141 List *connection_headers;
3142
3143 gwlib_assert_init();
3144 gw_assert(headers != NULL);
3145
3146 /*
3147 * The hop-by-hop headers are a standard list, plus those named
3148 * in the Connection header(s).
3149 */
3150
3151 connection_headers = http_header_find_all(headers, "Connection");
3152 while ((h = gwlist_consume(connection_headers))) {
3153 List *hop_headers;
3154 Octstr *e;
3155
3156 octstr_delete(h, 0, strlen("Connection:"));
3157 hop_headers = http_header_split_value(h);
3158 octstr_destroy(h);
3159
3160 while ((e = gwlist_consume(hop_headers))) {
3161 http_header_remove_all(headers, octstr_get_cstr(e));
3162 octstr_destroy(e);
3163 }
3164
3165 gwlist_destroy(hop_headers, NULL);
3166 }
3167 gwlist_destroy(connection_headers, NULL);
3168
3169 http_header_remove_all(headers, "Connection");
3170 http_header_remove_all(headers, "Keep-Alive");
3171 http_header_remove_all(headers, "Proxy-Authenticate");
3172 http_header_remove_all(headers, "Proxy-Authorization");
3173 http_header_remove_all(headers, "TE");
3174 http_header_remove_all(headers, "Trailers");
3175 http_header_remove_all(headers, "Transfer-Encoding");
3176 http_header_remove_all(headers, "Upgrade");
3177 }
3178
3179
http_header_mark_transformation(List * headers,Octstr * new_body,Octstr * new_type)3180 void http_header_mark_transformation(List *headers,
3181 Octstr *new_body, Octstr *new_type)
3182 {
3183 Octstr *new_length = NULL;
3184
3185 /* Remove all headers that no longer apply to the new body. */
3186 http_header_remove_all(headers, "Content-Length");
3187 http_header_remove_all(headers, "Content-MD5");
3188 http_header_remove_all(headers, "Content-Type");
3189
3190 /* Add headers that we need to describe the new body. */
3191 new_length = octstr_format("%ld", octstr_len(new_body));
3192 http_header_add(headers, "Content-Length", octstr_get_cstr(new_length));
3193 if(octstr_len(new_type))
3194 http_header_add(headers, "Content-Type", octstr_get_cstr(new_type));
3195
3196 /* Perhaps we should add Warning: 214 "Transformation applied" too? */
3197
3198 octstr_destroy(new_length);
3199 }
3200
3201
http_header_get_content_type(List * headers,Octstr ** type,Octstr ** charset)3202 void http_header_get_content_type(List *headers, Octstr **type,
3203 Octstr **charset)
3204 {
3205 Octstr *h;
3206 long semicolon, equals, len;
3207
3208 gwlib_assert_init();
3209 gw_assert(headers != NULL);
3210 gw_assert(type != NULL);
3211 gw_assert(charset != NULL);
3212
3213 h = http_header_find_first(headers, "Content-Type");
3214 if (h == NULL) {
3215 *type = octstr_create("application/octet-stream");
3216 *charset = octstr_create("");
3217 } else {
3218 octstr_strip_blanks(h);
3219 semicolon = octstr_search_char(h, ';', 0);
3220 if (semicolon == -1) {
3221 *type = h;
3222 *charset = octstr_create("");
3223 } else {
3224 *charset = octstr_duplicate(h);
3225 octstr_delete(*charset, 0, semicolon + 1);
3226 octstr_strip_blanks(*charset);
3227 equals = octstr_search_char(*charset, '=', 0);
3228 if (equals == -1)
3229 octstr_truncate(*charset, 0);
3230 else {
3231 octstr_delete(*charset, 0, equals + 1);
3232 if (octstr_get_char(*charset, 0) == '"')
3233 octstr_delete(*charset, 0, 1);
3234 len = octstr_len(*charset);
3235 if (octstr_get_char(*charset, len - 1) == '"')
3236 octstr_truncate(*charset, len - 1);
3237 }
3238
3239 octstr_truncate(h, semicolon);
3240 octstr_strip_blanks(h);
3241 *type = h;
3242 }
3243
3244 /*
3245 * According to HTTP/1.1 (RFC 2616, section 3.7.1) we have to ensure
3246 * to return charset 'iso-8859-1' in case of no given encoding and
3247 * content-type is a 'text' subtype.
3248 */
3249 if (octstr_len(*charset) == 0 &&
3250 octstr_ncompare(*type, octstr_imm("text"), 4) == 0)
3251 octstr_append_cstr(*charset, "ISO-8859-1");
3252 }
3253 }
3254
3255
http_header_add_element(List * list,Octstr * value,long start,long end)3256 static void http_header_add_element(List *list, Octstr *value,
3257 long start, long end)
3258 {
3259 Octstr *element;
3260
3261 element = octstr_copy(value, start, end - start);
3262 octstr_strip_blanks(element);
3263 if (octstr_len(element) == 0)
3264 octstr_destroy(element);
3265 else
3266 gwlist_append(list, element);
3267 }
3268
3269
http_header_quoted_string_len(Octstr * header,long start)3270 long http_header_quoted_string_len(Octstr *header, long start)
3271 {
3272 long len;
3273 long pos;
3274 int c;
3275
3276 if (octstr_get_char(header, start) != '"')
3277 return -1;
3278
3279 len = octstr_len(header);
3280 for (pos = start + 1; pos < len; pos++) {
3281 c = octstr_get_char(header, pos);
3282 if (c == '\\') /* quoted-pair */
3283 pos++;
3284 else if (c == '"')
3285 return pos - start + 1;
3286 }
3287
3288 warning(0, "Header contains unterminated quoted-string:");
3289 warning(0, "%s", octstr_get_cstr(header));
3290 return len - start;
3291 }
3292
3293
http_header_split_value(Octstr * value)3294 List *http_header_split_value(Octstr *value)
3295 {
3296 long start; /* start of current element */
3297 long pos;
3298 long len;
3299 List *result;
3300 int c;
3301
3302 /*
3303 * According to RFC2616 section 4.2, a field-value is either *TEXT
3304 * (the caller is responsible for not feeding us one of those) or
3305 * combinations of token, separators, and quoted-string. We're
3306 * looking for commas which are separators, and have to skip
3307 * commas in quoted-strings.
3308 */
3309
3310 result = gwlist_create();
3311 len = octstr_len(value);
3312 start = 0;
3313 for (pos = 0; pos < len; pos++) {
3314 c = octstr_get_char(value, pos);
3315 if (c == ',') {
3316 http_header_add_element(result, value, start, pos);
3317 start = pos + 1;
3318 } else if (c == '"') {
3319 pos += http_header_quoted_string_len(value, pos);
3320 pos--; /* compensate for the loop's pos++ */
3321 }
3322 }
3323 http_header_add_element(result, value, start, len);
3324 return result;
3325 }
3326
3327
http_header_split_auth_value(Octstr * value)3328 List *http_header_split_auth_value(Octstr *value)
3329 {
3330 List *result;
3331 Octstr *auth_scheme;
3332 Octstr *element;
3333 long i;
3334
3335 /*
3336 * According to RFC2617, both "challenge" and "credentials"
3337 * consist of an auth-scheme followed by a list of auth-param.
3338 * Since we have to parse a list of challenges or credentials,
3339 * we have to look for auth-scheme to signal the start of
3340 * a new element. (We can't just split on commas because
3341 * they are also used to separate the auth-params.)
3342 *
3343 * An auth-scheme is a single token, while an auth-param is
3344 * always a key=value pair. So we can recognize an auth-scheme
3345 * as a token that is not followed by a '=' sign.
3346 *
3347 * Simple approach: First split at all commas, then recombine
3348 * the elements that belong to the same challenge or credential.
3349 * This is somewhat expensive but saves programmer thinking time.
3350 *
3351 * Richard Braakman
3352 */
3353
3354 result = http_header_split_value(value);
3355 if (gwlist_len(result) == 0)
3356 return result;
3357
3358 auth_scheme = gwlist_get(result, 0);
3359 i = 1;
3360 while (i < gwlist_len(result)) {
3361 int c;
3362 long pos;
3363
3364 element = gwlist_get(result, i);
3365
3366 /*
3367 * If the element starts with: token '='
3368 * then it's just an auth_param; append it to the current
3369 * auth_scheme. If it starts with: token token '='
3370 * then it's the start of a new auth scheme.
3371 *
3372 * To make the scan easier, we consider anything other
3373 * than whitespace or '=' to be part of a token.
3374 */
3375
3376 /* Skip first token */
3377 for (pos = 0; pos < octstr_len(element); pos++) {
3378 c = octstr_get_char(element, pos);
3379 if (isspace(c) || c == '=')
3380 break;
3381 }
3382
3383 /* Skip whitespace, if any */
3384 while (isspace(octstr_get_char(element, pos)))
3385 pos++;
3386
3387 if (octstr_get_char(element, pos) == '=') {
3388 octstr_append_char(auth_scheme, ';');
3389 octstr_append(auth_scheme, element);
3390 gwlist_delete(result, i, 1);
3391 octstr_destroy(element);
3392 } else {
3393 char semicolon = ';';
3394 octstr_insert_data(element, pos, &semicolon, 1);
3395 auth_scheme = element;
3396 i++;
3397 }
3398 }
3399
3400 return result;
3401 }
3402
3403
http_header_dump(List * headers)3404 void http_header_dump(List *headers)
3405 {
3406 long i;
3407
3408 gwlib_assert_init();
3409
3410 debug("gwlib.http", 0, "Dumping HTTP headers:");
3411 for (i = 0; headers != NULL && i < gwlist_len(headers); ++i)
3412 octstr_dump(gwlist_get(headers, i), 1);
3413 debug("gwlib.http", 0, "End of dump.");
3414 }
3415
3416
http_cgivar_dump(List * cgiargs)3417 void http_cgivar_dump(List *cgiargs)
3418 {
3419 HTTPCGIVar *v;
3420 long i, len;
3421
3422 gwlib_assert_init();
3423
3424 len = gwlist_len(cgiargs);
3425
3426 debug("gwlib.http", 0, "Dumping %ld cgi variables:", len);
3427 for (i = 0; i < len; i++) {
3428 v = gwlist_get(cgiargs, i);
3429 octstr_dump(v->name, 0);
3430 octstr_dump(v->value, 0);
3431 }
3432 debug("gwlib.http", 0, "End of dump.");
3433 }
3434
3435
http_cgivar_dump_into(List * cgiargs,Octstr * os)3436 void http_cgivar_dump_into(List *cgiargs, Octstr *os)
3437 {
3438 HTTPCGIVar *v;
3439 long i;
3440
3441 if (os == NULL)
3442 return;
3443
3444 gwlib_assert_init();
3445
3446 for (i = 0; i < gwlist_len(cgiargs); i++) {
3447 v = gwlist_get(cgiargs, i);
3448 octstr_format_append(os, "&%E=%E", v->name, v->value);
3449 }
3450 }
3451
3452
http_something_accepted(List * headers,char * header_name,char * what)3453 static int http_something_accepted(List *headers, char *header_name,
3454 char *what)
3455 {
3456 int found;
3457 long i;
3458 List *accepts;
3459 Octstr *needle = octstr_create(what);
3460
3461 gwlib_assert_init();
3462 gw_assert(headers != NULL);
3463 gw_assert(what != NULL);
3464
3465 /* return all headers with this name */
3466 accepts = http_header_find_all(headers, header_name);
3467
3468 found = 0;
3469 for (i = 0; !found && i < gwlist_len(accepts); ++i) {
3470 Octstr *header_value = gwlist_get(accepts, i);
3471 if (octstr_case_search(header_value, needle, 0) != -1)
3472 found = 1;
3473 }
3474 octstr_destroy(needle);
3475 http_destroy_headers(accepts);
3476 return found;
3477 }
3478
3479
http_type_accepted(List * headers,char * type)3480 int http_type_accepted(List *headers, char *type)
3481 {
3482 return http_something_accepted(headers, "Accept", type);
3483 }
3484
3485
http_charset_accepted(List * headers,char * charset)3486 int http_charset_accepted(List *headers, char *charset)
3487 {
3488 return http_something_accepted(headers, "Accept-Charset", charset);
3489 }
3490
3491
http_add_basic_auth(List * headers,Octstr * username,Octstr * password)3492 void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
3493 {
3494 Octstr *os;
3495
3496 if (password != NULL)
3497 os = octstr_format("%S:%S", username, password);
3498 else
3499 os = octstr_format("%S", username);
3500 octstr_binary_to_base64(os);
3501 octstr_strip_blanks(os);
3502 octstr_insert(os, octstr_imm("Basic "), 0);
3503 http_header_add(headers, "Authorization", octstr_get_cstr(os));
3504 octstr_destroy(os);
3505 }
3506
3507
http_get_header_parameter(Octstr * value,Octstr * parameter)3508 Octstr *http_get_header_parameter(Octstr *value, Octstr *parameter)
3509 {
3510 long pos, len, end;
3511 int c, found = 0;
3512 Octstr *result = NULL;
3513
3514 len = octstr_len(value);
3515 /* Find the start of the first parameter. */
3516 for (pos = 0; pos < len; pos++) {
3517 c = octstr_get_char(value, pos);
3518 if (c == ';')
3519 break;
3520 else if (c == '"')
3521 pos += http_header_quoted_string_len(value, pos) - 1;
3522 }
3523
3524 if (pos >= len)
3525 return NULL; /* no parameters */
3526
3527 for (pos++; pos > 0 && pos < len && found == 0; pos++) {
3528 Octstr *key = NULL;
3529 Octstr *val = NULL;
3530
3531 end = octstr_search_char(value, '=', pos);
3532 if (end < 0)
3533 end = octstr_search_char(value, ';', pos);
3534 if (end < 0)
3535 end = octstr_len(value);
3536 key = octstr_copy(value, pos, end - pos);
3537 octstr_strip_blanks(key);
3538 pos = end;
3539
3540 if (octstr_get_char(value, pos) == '=') {
3541 pos++;
3542 while (isspace(octstr_get_char(value, pos)))
3543 pos++;
3544 if (octstr_get_char(value, pos) == '"')
3545 end = pos + http_header_quoted_string_len(value, pos);
3546 else
3547 end = octstr_search_char(value, ';', pos);
3548 if (end < 0)
3549 end = octstr_len(value);
3550 val = octstr_copy(value, pos, end - pos);
3551 octstr_strip_blanks(val);
3552 pos = end;
3553 pos = octstr_search_char(value, ';', pos);
3554 }
3555
3556 /* is this the pair we look for? bail out then*/
3557 if (octstr_case_compare(key, parameter) == 0) {
3558 found++;
3559 result = octstr_duplicate(val);
3560 }
3561
3562 octstr_destroy(key);
3563 octstr_destroy(val);
3564 }
3565
3566 return result;
3567 }
3568
3569
3570 /***********************************************************************
3571 * Module initialization and shutdown.
3572 */
3573
3574
http_init(void)3575 void http_init(void)
3576 {
3577 gw_assert(run_status == limbo);
3578
3579 #ifdef HAVE_LIBSSL
3580 openssl_init_locks();
3581 conn_init_ssl();
3582 #endif /* HAVE_LIBSSL */
3583 proxy_init();
3584 client_init();
3585 conn_pool_init();
3586 port_init();
3587 server_init();
3588 #ifdef HAVE_LIBSSL
3589 server_ssl_init();
3590 #endif /* HAVE_LIBSSL */
3591
3592 run_status = running;
3593 }
3594
3595
http_shutdown(void)3596 void http_shutdown(void)
3597 {
3598 gwlib_assert_init();
3599 gw_assert(run_status == running);
3600
3601 run_status = terminating;
3602
3603 conn_pool_shutdown();
3604 client_shutdown();
3605 server_shutdown();
3606 port_shutdown();
3607 proxy_shutdown();
3608 #ifdef HAVE_LIBSSL
3609 openssl_shutdown_locks();
3610 conn_shutdown_ssl();
3611 server_shutdown_ssl();
3612 #endif /* HAVE_LIBSSL */
3613 run_status = limbo;
3614 }
3615
3616
3617 /*
3618 * This function relies on the HTTP_STATUS_* enum values being
3619 * chosen to fit this.
3620 */
http_status_class(int code)3621 int http_status_class(int code)
3622 {
3623 int sclass;
3624
3625 if (code < 100 || code >= 600)
3626 sclass = HTTP_STATUS_UNKNOWN;
3627 else
3628 sclass = code - (code % 100);
3629 return sclass;
3630 }
3631
3632
http_name2method(Octstr * method)3633 int http_name2method(Octstr *method)
3634 {
3635 gw_assert(method != NULL);
3636
3637 if (octstr_str_compare(method, "GET") == 0) {
3638 return HTTP_METHOD_GET;
3639 }
3640 else if (octstr_str_compare(method, "POST") == 0) {
3641 return HTTP_METHOD_POST;
3642 }
3643 else if (octstr_str_compare(method, "HEAD") == 0) {
3644 return HTTP_METHOD_HEAD;
3645 }
3646
3647 return -1;
3648 }
3649
3650
http_method2name(int method)3651 char *http_method2name(int method)
3652 {
3653 gw_assert(method > 0 && method <= 3);
3654
3655 return http_methods[method-1];
3656 }
3657
3658