Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
http.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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 {
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  */
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  */
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 
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);
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 
225 static void proxy_init(void)
226 {
227  proxy_mutex = mutex_create();
228  proxy_exceptions = gwlist_create();
229 }
230 
231 
232 static void proxy_shutdown(void)
233 {
235  mutex_destroy(proxy_mutex);
236  proxy_mutex = NULL;
237 }
238 
239 
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 
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 
275  gw_assert(hostname != NULL);
276  gw_assert(octstr_len(hostname) > 0);
277  gw_assert(port > 0);
278 
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 
305 {
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  */
332  /*
333  * Message must not have a body, even if the headers indicate one.
334  * (i.e. response to HEAD method).
335  */
337  /*
338  * Message will have a body if Content-Length or Transfer-Encoding
339  * headers are present (i.e. most request methods).
340  */
342  /*
343  * Message will have a body, possibly zero-length.
344  * (i.e. 200 OK responses to a GET method.)
345  */
347 };
348 
359 };
360 
361 typedef struct {
364  enum body_expectation expect_state;
365  enum entity_state state;
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  */
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) {
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 {
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 {
411  }
412  octstr_destroy(h);
413  return;
414  }
415 
416  if (ent->expect_state == expect_body)
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  */
430 {
431  HTTPEntity *ent;
432 
433  ent = gw_malloc(sizeof(*ent));
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 
445 static void entity_destroy(HTTPEntity *ent)
446 {
447  if (ent == NULL)
448  return;
449 
451  octstr_destroy(ent->body);
452  gw_free(ent);
453 }
454 
455 
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)
475  else {
477  ent->chunked_body_chunk_len = len;
478  }
479 }
480 
481 
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);
494  }
495 }
496 
497 
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);
509  }
510 }
511 
512 
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 
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 
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  */
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 
583  read_chunked_body_len(ent, conn);
584  break;
585 
587  read_chunked_body_data(ent, conn);
588  break;
589 
591  read_chunked_body_crlf(ent, conn);
592  break;
593 
595  read_chunked_body_trailer(ent, conn);
596  break;
597 
599  read_body_until_eof(ent, conn);
600  break;
601 
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 {
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 */
674  Octstr *request_body; /* NULL for GET or HEAD, non-NULL for POST */
675  enum {
680  transaction_done
681  } state;
682  long status;
684  HTTPEntity *response; /* Can only be NULL if status < 0 */
687  long port;
690  int ssl;
691  Octstr *username; /* For basic authentication */
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 
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 
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);
738  trans->request_headers = NULL;
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;
755 
756 
757 static void conn_pool_item_destroy(void *item)
758 {
759  gwlist_destroy(item, (void(*)(void*))conn_destroy);
760 }
761 
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 
769 static void conn_pool_shutdown(void)
770 {
771  dict_destroy(conn_pool);
772  mutex_destroy(conn_pool_lock);
773 }
774 
775 
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 
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
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 
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 
898 {
900 
901  caller = gwlist_create();
902  gwlist_add_producer(caller);
903  return caller;
904 }
905 
906 
908 {
910 }
911 
912 
914 {
915  gwlist_remove_producer(caller);
916 }
917 
918 
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 &&
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  */
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  */
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 
1027 static int response_expectation(int method, int status)
1028 {
1029  if (status == HTTP_NO_CONTENT ||
1030  status == HTTP_NOT_MODIFIED ||
1032  method == HTTP_METHOD_HEAD)
1033  return expect_no_body;
1034  else
1035  return expect_body;
1036 }
1037 
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 &&
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  */
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  */
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  */
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 
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 
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);
1335  gw_free(p);
1336 }
1337 
1338 
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  */
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) ?
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));
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) ?
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));
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.");
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 */
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 
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);
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  */
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)
1628  trans->password);
1629 
1630  if (proxy_used_for_host(trans->host, trans->url)) {
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  */
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 
1708 static void start_client_threads(void)
1709 {
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);
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);
1724  } else
1726  }
1727  mutex_unlock(client_thread_lock);
1728  }
1729 }
1730 
1731 void http_set_interface(const Octstr *our_host)
1732 {
1733  http_interface = octstr_duplicate(our_host);
1734 }
1735 
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 
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);
1768 }
1769 
1770 
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 
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 
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 
1833 static void client_shutdown(void)
1834 {
1835  gwlist_remove_producer(pending_requests);
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;
1859  enum {
1864  } state;
1865  int method; /* HTTP_METHOD_ value */
1869  unsigned long conn_time; /* store time for timeouting */
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;
1882 static int keep_servers_open = 0;
1883 /* List with all active HTTPClient's */
1885 
1886 
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 
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 
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 
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) {
1979  return 1;
1980  } else {
1982  return 0;
1983  }
1984  } else if (gwlist_search(values, octstr_imm("close"), octstr_item_case_match) != NULL) {
1986  return 0;
1987  }
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;
2005 };
2006 
2007 
2008 static Mutex *port_mutex = NULL;
2009 static Dict *port_collection = NULL;
2010 
2011 
2012 static int port_match(void *client, void *port)
2013 {
2014  return ((HTTPClient*)client)->port == *((int*)port);
2015 }
2016 
2017 
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 
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 
2035 static Octstr *port_key(int port)
2036 {
2037  return octstr_format("%d", port);
2038 }
2039 
2040 
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));
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 
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 
2084  while (counter_value(p->active_consumers) > 0)
2085  gwthread_sleep(0.1); /* Reasonable use of busy waiting. */
2086 
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 */
2109  gw_free(p);
2110 }
2111 
2112 
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  }
2129  mutex_unlock(port_mutex);
2130 }
2131 
2132 
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 {
2149  mutex_unlock(port_mutex); /* Placement of this unlock is tricky. */
2152  }
2153  return client;
2154 }
2155 
2156 
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 
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 
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) {
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 
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  */
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 
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 
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 
2466 void http_set_server_timeout(int port, long timeout)
2467 {
2468  port_set_timeout(port, timeout);
2469 }
2470 
2471 
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;
2492  gwthread_wakeup(server_thread_id);
2493 
2494  return 0;
2495 }
2496 
2497 
2498 int http_open_port(int port, int ssl)
2499 {
2500  return http_open_port_if(port, ssl, NULL);
2501 }
2502 
2503 
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 
2516 {
2517  if (server_thread_id != -1) {
2518  keep_servers_open = 0;
2519  gwthread_wakeup(server_thread_id);
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  */
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);
2563 
2564  octstr_destroy(arg);
2565 
2566  gwlist_append(list, v);
2567  }
2568  octstr_destroy(args);
2569 
2570  return list;
2571 }
2572 
2573 
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 
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  */
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 */
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 */
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 */
2657  return "Request Entity Too Large"; /* 413 */
2659  return "Unsupported Media Type"; /* 415 */
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 
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 
2736 {
2737  client_destroy(client);
2738 }
2739 
2741 {
2742  return client->method;
2743 }
2744 
2746 {
2747  return client->url;
2748 }
2749 
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 
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 
2769 static void destroy_int_pointer(void *p)
2770 {
2771  (void) close(*(int *) p);
2772  gw_free(p);
2773 }
2774 
2775 
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);
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 
2796 {
2797  HTTPCGIVar *v;
2798 
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 
2814 {
2815  int i;
2816  HTTPCGIVar *v;
2817 
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 
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 
2850 {
2852  return gwlist_create();
2853 }
2854 
2855 
2857 {
2860 }
2861 
2862 
2863 void http_header_add(List *headers, char *name, char *contents)
2864 {
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  */
2879 void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
2880 {
2881  Octstr *os;
2882  long colon;
2883 
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  */
2910 {
2911  Octstr *value;
2912  long i;
2913  Octstr *os;
2914  long colon;
2915  Octstr *current_name;
2916 
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 
2947 {
2948  List *new;
2949  long i, len;
2950 
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  */
2969 void http_header_pack(List *headers)
2970 {
2971  Octstr *name, *value;
2972  Octstr *name2, *value2;
2973  long i, j;
2974 
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 
3030 {
3031  Octstr *header;
3032  long i;
3033 
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 
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 
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 
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 
3093 {
3094  List *list;
3095  long i;
3096  Octstr *h;
3097 
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 
3112 long http_header_remove_all(List *headers, char *name)
3113 {
3114  long i;
3115  Octstr *h;
3116  long count;
3117 
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 
3139 {
3140  Octstr *h;
3141  List *connection_headers;
3142 
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))) {
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 
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 
3203  Octstr **charset)
3204 {
3205  Octstr *h;
3206  long semicolon, equals, len;
3207 
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 {
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);
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 
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 
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 
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 
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 
3404 void http_header_dump(List *headers)
3405 {
3406  long i;
3407 
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 
3417 void http_cgivar_dump(List *cgiargs)
3418 {
3419  HTTPCGIVar *v;
3420  long i, len;
3421 
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 
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 
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 
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 
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 
3480 int http_type_accepted(List *headers, char *type)
3481 {
3482  return http_something_accepted(headers, "Accept", type);
3483 }
3484 
3485 
3486 int http_charset_accepted(List *headers, char *charset)
3487 {
3488  return http_something_accepted(headers, "Accept-Charset", charset);
3489 }
3490 
3491 
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);
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 
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 
3575 void http_init(void)
3576 {
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 
3596 void http_shutdown(void)
3597 {
3600 
3602 
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  */
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 
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 
3652 {
3653  gw_assert(method > 0 && method <= 3);
3654 
3655  return http_methods[method-1];
3656 }
3657 
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
static Connection * get_connection(HTTPServer *trans)
Definition: http.c:1552
static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn)
Definition: http.c:513
Octstr * conn_read_line(Connection *conn)
Definition: conn.c:1126
char * http_method2name(int method)
Definition: http.c:3651
#define HTTP_MAX_FOLLOW
Definition: http.c:653
void error(int err, const char *fmt,...)
Definition: log.c:612
static List * active_connections
Definition: http.c:1884
void info(int err, const char *fmt,...)
Definition: log.c:636
static List * pending_requests
Definition: http.c:633
static void port_set_timeout(int port, long timeout)
Definition: http.c:2157
static void parse2trans(HTTPURLParse *p, HTTPServer *t)
Definition: http.c:1528
Definition: http.c:1998
Octstr * value
Definition: http.h:213
List * http_header_find_all(List *headers, char *name)
Definition: http.c:3092
static void server_destroy(void *p)
Definition: http.c:730
void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
Definition: http.c:2879
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
Octstr * pass
Definition: http.h:244
size_t name_len
Definition: wslexer.c:156
static HTTPClient * port_get_request(int port)
Definition: http.c:2133
Octstr * http_header_find_first_real(List *headers, char *name, const char *file, long line, const char *func)
Definition: http.c:3067
void * request_id
Definition: http.c:669
static long server_thread_id
Definition: http.c:1879
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2863
static void read_chunked_body_len(HTTPEntity *ent, Connection *conn)
Definition: http.c:456
static Octstr * method_name
Definition: test_http.c:86
static void proxy_init(void)
Definition: http.c:225
long status
Definition: http.c:682
int ssl
void http_caller_signal_shutdown(HTTPCaller *caller)
Definition: http.c:913
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
void counter_destroy(Counter *counter)
Definition: counter.c:110
#define mutex_unlock(m)
Definition: thread.h:136
void gwlist_append(List *list, void *item)
Definition: list.c:179
void http_close_client(HTTPClient *client)
Definition: http.c:2735
void http_set_server_timeout(int port, long timeout)
Definition: http.c:2466
List * http_header_split_auth_value(Octstr *value)
Definition: http.c:3328
static Mutex * port_mutex
Definition: http.c:2008
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
static void server_init(void)
Definition: http.c:2750
void gwlist_produce(List *list, void *item)
Definition: list.c:411
static Octstr * get_redirection_location(HTTPServer *trans)
Definition: http.c:919
long gwlist_len(List *list)
Definition: list.c:166
int conn_is_connected(Connection *conn)
Definition: conn.c:517
Connection * conn
Definition: http.c:1857
static Connection * conn_pool_get(Octstr *host, int port, int ssl, Octstr *certkeyfile, Octstr *our_host)
Definition: http.c:783
static void client(int port)
Definition: test_udp.c:77
Octstr * octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line, const char *func)
Definition: octstr.c:349
static HTTPCaller * caller
Definition: smsbox.c:429
#define mutex_create()
Definition: thread.h:96
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void http_header_combine(List *old_headers, List *new_headers)
Definition: http.c:3045
int octstr_url_decode(Octstr *ostr)
Definition: octstr.c:1744
Connection * conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host)
Definition: conn.c:493
int port
Definition: http.c:2000
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
int method
Definition: http.c:670
int code
Definition: smsc_cimd2.c:346
Octstr * fragment
Definition: http.h:247
Octstr * query
Definition: http.h:246
long chunked_body_chunk_len
Definition: http.c:366
void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
Definition: http.c:3492
int follow_remaining
Definition: http.c:688
int type
Definition: smsc_cimd2.c:215
Octstr * uri
Definition: http.c:672
static Octstr * host
Definition: fakesmsc.c:121
void octstr_binary_to_base64(Octstr *ostr)
Definition: octstr.c:540
static Octstr * port_key(int port)
Definition: http.c:2035
FDSet * server_fdset
Definition: http.c:2004
void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset)
Definition: http.c:3202
static int client_is_persistent(List *headers, int use_version_1_0)
Definition: http.c:1967
Connection * conn
Definition: http.c:685
static Octstr * http_interface
Definition: http.c:123
int ssl
Definition: http.c:2001
static volatile sig_atomic_t client_threads_are_running
Definition: http.c:640
unsigned long counter_decrease(Counter *counter)
Definition: counter.c:155
int http_name2method(Octstr *method)
Definition: http.c:3633
List * request_headers
Definition: http.c:673
long http_header_quoted_string_len(Octstr *header, long start)
Definition: http.c:3270
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
static int proxy_ssl
Definition: http.c:202
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
int fd
Definition: http.c:1999
int conn_eof(Connection *conn)
Definition: conn.c:697
int gwthread_poll(struct pollfd *fds, long numfds, double timeout)
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1344
int use_version_1_0
Definition: http.c:1867
static Dict * conn_pool
Definition: http.c:753
Octstr * certkeyfile
Definition: http.c:689
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
void gwthread_join_every(gwthread_func_t *func)
Octstr * http_request_url(HTTPClient *client)
Definition: http.c:2745
short events
Definition: gwpoll.h:86
unsigned long port
Definition: http.h:242
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
Octstr * charset
Definition: test_ota.c:68
void http_header_mark_transformation(List *headers, Octstr *new_body, Octstr *new_type)
Definition: http.c:3180
FILE * file
Definition: log.c:133
static void client_init(void)
Definition: http.c:1825
static struct pid_list * found
static Octstr * our_host
Definition: radius_acct.c:86
Octstr * ip
Definition: http.c:1858
static List * new_server_sockets
Definition: http.c:1880
unsigned char * username
Definition: test_cimd2.c:99
static void client_destroy(void *client)
Definition: http.c:1917
Octstr * http_cgi_variable(List *list, char *name)
Definition: http.c:2813
static int parse_request_line(int *method, Octstr **url, int *use_version_1_0, Octstr *line)
Definition: http.c:2194
Definition: http.c:115
List * gwlist_search_all(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:508
static void read_chunked_body_data(HTTPEntity *ent, Connection *conn)
Definition: http.c:482
static void port_remove(int port)
Definition: http.c:2065
void http_destroy_headers(List *headers)
Definition: http.c:2856
static Octstr * build_response(List *headers, Octstr *body)
Definition: http.c:1284
Octstr * host
Definition: http.h:241
static regex_t * proxy_exceptions_regex
Definition: http.c:206
void gwlist_unlock(List *list)
Definition: list.c:354
static int port
Definition: fakesmsc.c:120
static void handle_transaction(Connection *conn, void *data)
Definition: http.c:1038
static Octstr * from
Definition: mtbatch.c:95
#define POLLIN
Definition: gwpoll.h:91
void http_urlparse_destroy(HTTPURLParse *p)
Definition: http.c:1323
static int client_read_status(HTTPServer *trans)
Definition: http.c:982
void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow, void *id, Octstr *certkeyfile)
Definition: http.c:1745
void http_destroy_cgiargs(List *args)
Definition: http.c:2795
Octstr * body
Definition: http.c:363
void http_append_headers(List *to, List *from)
Definition: http.c:3029
static const char * http_reason_phrase(int status)
Definition: http.c:2621
unsigned char * password
Definition: test_cimd2.c:100
void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body)
Definition: http.c:2671
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static Mutex * client_thread_lock
Definition: http.c:639
static void read_body_until_eof(HTTPEntity *ent, Connection *conn)
Definition: http.c:525
static void conn_pool_init(void)
Definition: http.c:762
Definition: http.h:142
long expected_body_len
Definition: http.c:367
int conn_write(Connection *conn, Octstr *data)
Definition: conn.c:1043
int conn_get_connect_result(Connection *conn)
Definition: conn.c:522
int http_method(HTTPClient *client)
Definition: http.c:2740
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
void * dict_remove(Dict *dict, Octstr *key)
Definition: dict.c:307
static FDSet * port_get_fdset(int port)
Definition: http.c:2174
Counter * counter_create(void)
Definition: counter.c:94
Octstr * name
Definition: http.h:212
void http_close_proxy(void)
Definition: http.c:304
static void client_reset(HTTPClient *p)
Definition: http.c:1952
static void port_init(void)
Definition: http.c:2018
void * gwlist_extract_first(List *list)
Definition: list.c:305
static void server_shutdown(void)
Definition: http.c:2776
int method
Definition: http.c:1865
static HTTPClient * client_create(int port, Connection *conn, Octstr *ip)
Definition: http.c:1887
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
static enum @59 run_status
int conn_get_id(Connection *conn)
Definition: conn.c:1478
static int entity_read(HTTPEntity *ent, Connection *conn)
Definition: http.c:560
#define conn_register(conn, fdset, callback, data)
Definition: conn.h:215
void * dict_get(Dict *dict, Octstr *key)
Definition: dict.c:286
HTTPClient * http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars)
Definition: http.c:2574
void http_close_port(int port)
Definition: http.c:2504
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
void parse_dump(HTTPURLParse *p)
Definition: http.c:1339
void gwlist_remove_producer(List *list)
Definition: list.c:401
enum body_expectation expect_state
Definition: http.c:364
Octstr * url
Definition: http.c:671
Counter * active_consumers
Definition: http.c:2003
List * headers
Definition: http.c:362
Octstr * username
Definition: http.c:691
void conn_destroy(Connection *conn)
Definition: conn.c:619
List * http_create_empty_headers(void)
Definition: http.c:2849
Octstr * request_body
Definition: http.c:674
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:950
static int send_request(HTTPServer *trans)
Definition: http.c:1596
void http_header_pack(List *headers)
Definition: http.c:2969
static void deduce_body_state(HTTPEntity *ent)
Definition: http.c:375
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
Octstr * url
Definition: http.h:239
long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1100
static int proxy_port
Definition: http.c:201
int http_status_class(int code)
Definition: http.c:3621
#define http_header_find_first(headers, name)
Definition: http.h:592
List * http_header_split_value(Octstr *value)
Definition: http.c:3294
int conn_register_real(Connection *conn, FDSet *fdset, conn_callback_t callback, void *data, conn_callback_data_destroyer_t *data_destroyer)
Definition: conn.c:794
#define MAX_HEADER_LENGTH
Definition: http.c:2964
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
static List * parse_cgivars(Octstr *url)
Definition: http.c:2531
Octstr * http_get_header_parameter(Octstr *value, Octstr *parameter)
Definition: http.c:3508
char * name
Definition: smsc_cimd2.c:212
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:901
static void recover_absolute_uri(HTTPServer *trans, Octstr *loc)
Definition: http.c:941
int make_server_socket(int port, const char *interface_name)
Definition: socket.c:93
void warning(int err, const char *fmt,...)
Definition: log.c:624
void http_cgivar_dump_into(List *cgiargs, Octstr *os)
Definition: http.c:3436
long conn_outbuf_len(Connection *conn)
Definition: conn.c:675
List * octstr_split_words(const Octstr *ostr)
Definition: octstr.c:1600
static List * closed_server_sockets
Definition: http.c:1881
Definition: gwpoll.h:84
static int http_something_accepted(List *headers, char *header_name, char *what)
Definition: http.c:3453
Octstr * url
Definition: http.c:1866
Octstr * hostname
Definition: fakewap.c:232
List * clients_with_requests
Definition: http.c:2002
void * http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url, List **headers, Octstr **body, int blocking)
Definition: http.c:1771
void http_remove_hop_headers(List *headers)
Definition: http.c:3138
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static int parse_http_version(Octstr *version)
Definition: http.c:168
void http_set_interface(const Octstr *our_host)
Definition: http.c:1731
static Octstr * proxy_username
Definition: http.c:203
#define gwthread_create(func, arg)
Definition: gwthread.h:90
static int method
Definition: test_http.c:76
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
static Mutex * proxy_mutex
Definition: http.c:199
unsigned long counter_value(Counter *counter)
Definition: counter.c:145
int octstr_item_case_match(void *item, void *pattern)
Definition: octstr.c:1665
gw_assert(wtls_machine->packet_to_send!=NULL)
int persistent_conn
Definition: http.c:1868
void gwthread_sleep(double seconds)
void mutex_destroy(Mutex *mutex)
Definition: thread.c:97
static void proxy_add_authentication(List *headers)
Definition: http.c:209
static void port_put_request(HTTPClient *client)
Definition: http.c:2113
enum HTTPServer::@60 state
static Octstr * proxy_hostname
Definition: http.c:200
Octstr * path
Definition: http.h:245
int http_open_port(int port, int ssl)
Definition: http.c:2498
#define HTTP_SERVER_MAX_ACTIVE_CONNECTIONS
Definition: http.c:96
static Octstr * colon
Definition: smsc_smasi.c:218
void fdset_destroy(FDSet *set)
Definition: fdset.c:398
void gwlist_insert(List *list, long pos, void *item)
Definition: list.c:214
Definition: http.c:114
static char * http_methods[]
Definition: http.c:660
void gwlist_lock(List *list)
Definition: list.c:347
static List * proxy_exceptions
Definition: http.c:205
#define http_receive_result(caller, status, final_url, headers, body)
Definition: http.h:383
static void entity_destroy(HTTPEntity *ent)
Definition: http.c:445
static int keep_servers_open
Definition: http.c:1882
int http_open_port_if(int port, int ssl, Octstr *interface)
Definition: http.c:2472
body_expectation
Definition: http.c:331
static void destroy_int_pointer(void *p)
Definition: http.c:2769
void http_close_all_ports(void)
Definition: http.c:2515
Octstr * http_header_value(List *headers, Octstr *name)
Definition: http.c:2909
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static void receive_request(Connection *conn, void *data)
Definition: http.c:2240
void dict_destroy(Dict *dict)
Definition: dict.c:215
void conn_unregister(Connection *conn)
Definition: conn.c:850
void http_init(void)
Definition: http.c:3575
HTTPEntity * response
Definition: http.c:684
int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url, List **reply_headers, Octstr **reply_body)
Definition: http.c:1806
Definition: octstr.c:118
int fd
Definition: gwpoll.h:85
int conn_wait(Connection *conn, double seconds)
Definition: conn.c:896
void * gwlist_consume(List *list)
Definition: list.c:427
void http_cgivar_dump(List *cgiargs)
Definition: http.c:3417
static int http_client_timeout
Definition: http.c:91
static void write_request_thread(void *arg)
Definition: http.c:1666
void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions, Octstr *username, Octstr *password, Octstr *exceptions_regex)
Definition: http.c:268
static void conn_pool_item_destroy(void *item)
Definition: http.c:757
static void conn_pool_shutdown(void)
Definition: http.c:769
Octstr * host_ip(struct sockaddr_in addr)
Definition: socket.c:615
static int response_expectation(int method, int status)
Definition: http.c:1027
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static void destroy_struct_server(void *p)
Definition: http.c:2759
void() gwlib_assert_init(void)
Definition: gwlib.c:72
#define HTTP_SERVER_TIMEOUT
Definition: http.c:94
#define panic
Definition: log.h:87
static int read_some_headers(Connection *conn, List *headers)
Definition: http.c:131
static Dict * port_collection
Definition: http.c:2009
int port
Definition: http.c:1856
void gwthread_wakeup(long thread)
static Octstr * conn_pool_key(Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host)
Definition: http.c:776
int octstr_str_compare(const Octstr *ostr, const char *str)
Definition: octstr.c:971
static HTTPEntity * entity_create(enum body_expectation exp)
Definition: http.c:429
long http_header_remove_all(List *headers, char *name)
Definition: http.c:3112
int socklen_t
Definition: socket.h:73
int persistent
Definition: http.c:683
static void start_server_thread(void)
Definition: http.c:2447
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
HTTPCaller * http_caller_create(void)
Definition: http.c:897
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2505
int http_charset_accepted(List *headers, char *charset)
Definition: http.c:3486
List * http_header_duplicate(List *headers)
Definition: http.c:2946
enum HTTPClient::@61 state
static void port_shutdown(void)
Definition: http.c:2026
static FDSet * client_fdset
Definition: http.c:647
#define gwlist_create()
Definition: list.h:136
void octstr_truncate(Octstr *ostr, int new_len)
Definition: octstr.c:1325
static void server_thread(void *dummy)
Definition: http.c:2333
Octstr * date_format_http(unsigned long unixtime)
Definition: date.c:89
HTTPURLParse * parse_url(Octstr *url)
Definition: http.c:1368
Definition: fdset.c:70
Definition: thread.h:76
void http_caller_destroy(HTTPCaller *caller)
Definition: http.c:907
static int date(int hex)
Octstr * conn_read_fixed(Connection *conn, long length)
Definition: conn.c:1102
static void proxy_shutdown(void)
Definition: http.c:232
int conn_error(Connection *conn)
Definition: conn.c:708
static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn)
Definition: http.c:498
Octstr * user
Definition: http.h:243
static Mutex * server_thread_lock
Definition: http.c:1877
void fdset_set_timeout(FDSet *set, long timeout)
Definition: fdset.c:547
int http_type_accepted(List *headers, char *type)
Definition: http.c:3480
static HTTPServer * server_create(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow_remaining, Octstr *certkeyfile)
Definition: http.c:700
static void read_body_with_length(HTTPEntity *ent, Connection *conn)
Definition: http.c:540
static void client_shutdown(void)
Definition: http.c:1833
enum entity_state state
Definition: http.c:365
void gwlist_add_producer(List *list)
Definition: list.c:383
long port
Definition: http.c:687
static int response(List *push_headers, Octstr **username, Octstr **password)
void http_set_client_timeout(long timeout)
Definition: http.c:1736
HTTPURLParse * http_urlparse_create(void)
Definition: http.c:1304
static Octstr * url
Definition: test_xmlrpc.c:84
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
#define mutex_lock(m)
Definition: thread.h:130
FDSet * fdset_create_real(long timeout)
Definition: fdset.c:368
static void http_header_add_element(List *list, Octstr *value, long start, long end)
Definition: http.c:3256
static int header_is_called(Octstr *header, char *name)
Definition: http.c:2836
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
int ssl
Definition: http.c:690
static Octstr * build_request(char *method_name, Octstr *path_or_url, Octstr *host, long port, int ssl, List *headers, Octstr *request_body)
Definition: http.c:1235
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1638
entity_state
Definition: http.c:349
static Mutex * conn_pool_lock
Definition: http.c:754
Definition: list.c:102
void http_shutdown(void)
Definition: http.c:3596
HTTPCaller * caller
Definition: http.c:668
Octstr * host
Definition: http.c:686
unsigned long conn_time
Definition: http.c:1869
static int start
HTTPEntity * request
Definition: http.c:1870
void http_header_dump(List *headers)
Definition: http.c:3404
static int port_match(void *client, void *port)
Definition: http.c:2012
Octstr * password
Definition: http.c:692
static struct port * port_add(int port)
Definition: http.c:2041
Octstr * conn_read_everything(Connection *conn)
Definition: conn.c:1082
Connection * conn_wrap_fd(int fd, int ssl)
Definition: conn.c:558
static volatile sig_atomic_t server_thread_is_running
Definition: http.c:1878
Octstr * scheme
Definition: http.h:240
static int proxy_used_for_host(Octstr *host, Octstr *url)
Definition: http.c:240
static Octstr * proxy_password
Definition: http.c:204
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
static void start_client_threads(void)
Definition: http.c:1708
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.