Kannel: Open Source WAP and SMS gateway  svn-r5335
http.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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/gw-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 = 30;
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 
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 {
229 }
230 
231 
232 static void proxy_shutdown(void)
233 {
236  proxy_mutex = NULL;
237 }
238 
239 
241 {
242  int i;
243 
245 
246  if (proxy_hostname == NULL) {
248  return 0;
249  }
250 
251  for (i = 0; i < gwlist_len(proxy_exceptions); ++i) {
254  return 0;
255  }
256  }
257 
258  if (proxy_exceptions_regex != NULL && gw_regex_match_pre(proxy_exceptions_regex, url)) {
260  return 0;
261  }
262 
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);
277  gw_assert(port > 0);
278 
281 
283  proxy_port = port;
284  proxy_ssl = ssl;
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));
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));
296  debug("gwlib.http", 0, "Using proxy <%s:%d> with %s scheme",
298  (proxy_ssl ? "HTTPS" : "HTTP"));
299 
301 }
302 
303 
305 {
307 
309  proxy_port = 0;
313  proxy_hostname = NULL;
314  proxy_username = NULL;
315  proxy_password = NULL;
317  gw_regex_destroy(proxy_exceptions_regex);
318  proxy_exceptions = NULL;
319  proxy_exceptions_regex = NULL;
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", "PUT", "DELETE", "PATCH"
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 {
766 }
767 
768 
769 static void conn_pool_shutdown(void)
770 {
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(""),
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);
795  list = dict_get(conn_pool, key);
796  if (list != NULL)
797  conn = gwlist_extract_first(list);
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 */
832  debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).",
834  } else {
835  debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).",
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;
855  list = dict_get(conn_pool, key);
856  if (list != NULL && 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  */
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);
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);
893 }
894 #endif
895 
896 
898 {
900 
901  caller = gwlist_create();
903  return caller;
904 }
905 
906 
908 {
910 }
911 
912 
914 {
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 ||
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  gw_assert(trans->conn == conn);
1048 
1049  if (run_status != running) {
1050  conn_unregister(trans->conn);
1051  return;
1052  }
1053 
1054  while (trans->state != transaction_done) {
1055  switch (trans->state) {
1056  case connecting:
1057  debug("gwlib.http", 0, "Get info about connecting socket");
1058  if (conn_get_connect_result(trans->conn) != 0) {
1059  debug("gwlib.http", 0, "Socket not connected");
1060  goto error;
1061  }
1062 
1063  if ((rc = send_request(trans)) == 0) {
1064  trans->state = reading_status;
1065  } else {
1066  debug("gwlib.http", 0, "Failed while sending request");
1067  goto error;
1068  }
1069  break;
1070 
1071  case reading_status:
1072  ret = client_read_status(trans);
1073  if (ret < 0) {
1074  /*
1075  * Couldn't read the status from the socket. This may mean
1076  * that the socket had been closed by the server after an
1077  * idle timeout.
1078  */
1079  debug("gwlib.http",0,"Failed while reading status");
1080  goto error;
1081  } else if (ret == 0) {
1082  /* Got the status, go read headers and body next. */
1083  trans->state = reading_entity;
1084  trans->response = entity_create(response_expectation(trans->method, trans->status));
1085  } else {
1086  return;
1087  }
1088  break;
1089 
1090  case reading_entity:
1091  ret = entity_read(trans->response, trans->conn);
1092  if (ret < 0) {
1093  debug("gwlib.http",0,"Failed reading entity");
1094  goto error;
1095  } else if (ret == 0 &&
1097  /* This was a provisional reply; get the real one now. */
1098  trans->state = reading_status;
1099  entity_destroy(trans->response);
1100  trans->response = NULL;
1101  } else if (ret == 0) {
1102  trans->state = transaction_done;
1103 #ifdef DUMP_RESPONSE
1104  /* Dump the response */
1105  debug("gwlib.http", 0, "HTTP: Received response:");
1106  h = build_response(trans->response->headers, trans->response->body);
1107  octstr_dump(h, 0);
1108  octstr_destroy(h);
1109 #endif
1110  } else {
1111  return;
1112  }
1113  break;
1114 
1115  default:
1116  panic(0, "Internal error: Invalid HTTPServer state.");
1117  }
1118  }
1119 
1120  /*
1121  * Connection may have been destroyed within send_request,
1122  * so be more carefull here not to panic.
1123  */
1124  if (trans->conn)
1125  conn_unregister(trans->conn);
1126 
1127  /*
1128  * Take care of persistent connection handling.
1129  * At this point we have only obeyed if server responds in HTTP/1.0 or 1.1
1130  * and have assigned trans->persistent accordingly. This can be keept
1131  * for default usage, but if we have [Proxy-]Connection: keep-alive, then
1132  * we're still forcing persistancy of the connection.
1133  */
1134  h = http_header_find_first(trans->response->headers, "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  if (proxy_used_for_host(trans->host, trans->url)) {
1141  h = http_header_find_first(trans->response->headers, "Proxy-Connection");
1142  if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0)
1143  trans->persistent = 0;
1144  if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0)
1145  trans->persistent = 1;
1146  octstr_destroy(h);
1147  }
1148 
1149 #ifdef USE_KEEPALIVE
1150  if (trans->persistent) {
1151  if (proxy_used_for_host(trans->host, trans->url))
1152  conn_pool_put(trans->conn, proxy_hostname, proxy_port, trans->ssl, trans->certkeyfile, http_interface);
1153  else
1154  conn_pool_put(trans->conn, trans->host, trans->port, trans->ssl, trans->certkeyfile, http_interface);
1155  } else
1156 #endif
1157  conn_destroy(trans->conn);
1158 
1159  trans->conn = NULL;
1160 
1161  /*
1162  * Check if the HTTP server told us to look somewhere else,
1163  * hence if we got one of the following response codes:
1164  * HTTP_MOVED_PERMANENTLY (301)
1165  * HTTP_FOUND (302)
1166  * HTTP_SEE_OTHER (303)
1167  * HTTP_TEMPORARY_REDIRECT (307)
1168  */
1169  if ((h = get_redirection_location(trans)) != NULL) {
1170 
1171  /*
1172  * This is a redirected response, we have to follow.
1173  *
1174  * According to HTTP/1.1 (RFC 2616), section 14.30 any Location
1175  * header value should be 'absoluteURI', which is defined in
1176  * RFC 2616, section 3.2.1 General Syntax, and specifically in
1177  * RFC 2396, section 3 URI Syntactic Components as
1178  *
1179  * absoluteURI = scheme ":" ( hier_part | opaque_part )
1180  *
1181  * Some HTTP servers 'interpret' a leading UDI / as that kind
1182  * of absoluteURI, which is not correct, following the protocol in
1183  * detail. But we'll try to recover from that misleaded
1184  * interpreation and try to convert the partly absoluteURI to a
1185  * fully qualified absoluteURI.
1186  *
1187  * http_URL = "http:" "//" [ userid : password "@"] host
1188  * [ ":" port ] [ abs_path [ "?" query ]]
1189  *
1190  */
1192  recover_absolute_uri(trans, h);
1193 
1194  /*
1195  * Clean up all trans stuff for the next request we do.
1196  */
1197  octstr_destroy(trans->url);
1198  octstr_destroy(trans->host);
1199  trans->port = 0;
1200  octstr_destroy(trans->uri);
1201  octstr_destroy(trans->username);
1202  octstr_destroy(trans->password);
1203  trans->host = NULL;
1204  trans->port = 0;
1205  trans->uri = NULL;
1206  trans->username = NULL;
1207  trans->password = NULL;
1208  trans->ssl = 0;
1209  trans->url = h; /* apply new absolute URL to next request */
1210  trans->state = request_not_sent;
1211  trans->status = -1;
1212  entity_destroy(trans->response);
1213  trans->response = NULL;
1214  --trans->follow_remaining;
1215  conn_destroy(trans->conn);
1216  trans->conn = NULL;
1217 
1218  /* re-inject request to the front of the queue */
1219  gwlist_insert(pending_requests, 0, trans);
1220 
1221  } else {
1222  /* handle this response as usual */
1223  gwlist_produce(trans->caller, trans);
1224  }
1225  return;
1226 
1227 error:
1228  if (trans->conn != NULL) {
1229  conn_unregister(trans->conn);
1230  conn_destroy(trans->conn);
1231  trans->conn = NULL;
1232  }
1233  error(0, "Couldn't fetch <%s>", octstr_get_cstr(trans->url));
1234  trans->status = -1;
1235  gwlist_produce(trans->caller, trans);
1236 }
1237 
1238 
1239 /*
1240  * Build a complete HTTP request given the host, port, path and headers.
1241  * Add Host: and Content-Length: headers (and others that may be necessary).
1242  * Return the request as an Octstr.
1243  */
1244 static Octstr *build_request(char *method_name, Octstr *path_or_url,
1245  Octstr *host, long port, int ssl, List *headers,
1246  Octstr *request_body)
1247 {
1248  /* XXX headers missing */
1249  Octstr *request;
1250  int i, host_found = 0;
1251 
1252  request = octstr_format("%s %S HTTP/1.1\r\n",
1253  method_name, path_or_url);
1254 
1255 #ifdef USE_KEEPALIVE
1256  octstr_append(request, octstr_imm("Connection: keep-alive\r\n"));
1257 #endif
1258 
1259  for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
1260  /* check if Host already set in the headers */
1261  if (header_is_called(gwlist_get(headers, i), "Host"))
1262  host_found = 1;
1263  octstr_append(request, gwlist_get(headers, i));
1264  octstr_append(request, octstr_imm("\r\n"));
1265  }
1266 
1267  if (!host_found) {
1268  octstr_format_append(request, "Host: %S", host);
1269  /*
1270  * In accordance with HTT/1.1 [RFC 2616], section 14.23 "Host"
1271  * we shall ONLY add the port number if it is not one of the
1272  * officially assigned port numbers. This means we need to obey
1273  * port 80 for non-SSL connections and port 443 for SSL-enabled.
1274  */
1275  if ((port != HTTP_PORT && !ssl) || (port != HTTPS_PORT && ssl))
1276  octstr_format_append(request, ":%ld", port);
1277  octstr_append(request, octstr_imm("\r\n"));
1278  }
1279 
1280  octstr_append(request, octstr_imm("\r\n"));
1281 
1282  if (request_body != NULL)
1283  octstr_append(request, request_body);
1284 
1285  return request;
1286 }
1287 
1288 
1289 /*
1290  * Re-build the HTTP response given the headers and the body.
1291  * Return the response as an Octstr.
1292  */
1293 static Octstr *build_response(List *headers, Octstr *body)
1294 {
1295  Octstr *response;
1296  int i;
1297 
1298  response = octstr_create("");
1299 
1300  for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) {
1301  octstr_append(response, gwlist_get(headers, i));
1302  octstr_append(response, octstr_imm("\r\n"));
1303  }
1304  octstr_append(response, octstr_imm("\r\n"));
1305 
1306  if (body != NULL)
1307  octstr_append(response, body);
1308 
1309  return response;
1310 }
1311 
1312 
1314 {
1315  HTTPURLParse *p;
1316 
1317  p = gw_malloc(sizeof(HTTPURLParse));
1318  p->url = NULL;
1319  p->scheme = NULL;
1320  p->host = NULL;
1321  p->port = 0;
1322  p->user = NULL;
1323  p->pass = NULL;
1324  p->path = NULL;
1325  p->query = NULL;
1326  p->fragment = NULL;
1327 
1328  return p;
1329 }
1330 
1331 
1333 {
1334  gw_assert(p != NULL);
1335 
1336  octstr_destroy(p->url);
1337  octstr_destroy(p->scheme);
1338  octstr_destroy(p->host);
1339  octstr_destroy(p->user);
1340  octstr_destroy(p->pass);
1341  octstr_destroy(p->path);
1342  octstr_destroy(p->query);
1344  gw_free(p);
1345 }
1346 
1347 
1349 {
1350  if (p == NULL)
1351  return;
1352  debug("http.parse_url",0,"Parsing URL `%s':", octstr_get_cstr(p->url));
1353  debug("http.parse_url",0," Scheme: %s", octstr_get_cstr(p->scheme));
1354  debug("http.parse_url",0," Host: %s", octstr_get_cstr(p->host));
1355  debug("http.parse_url",0," Port: %ld", p->port);
1356  debug("http.parse_url",0," Username: %s", octstr_get_cstr(p->user));
1357  debug("http.parse_url",0," Password: %s", octstr_get_cstr(p->pass));
1358  debug("http.parse_url",0," Path: %s", octstr_get_cstr(p->path));
1359  debug("http.parse_url",0," Query: %s", octstr_get_cstr(p->query));
1360  debug("http.parse_url",0," Fragment: %s", octstr_get_cstr(p->fragment));
1361 }
1362 
1363 
1364 /*
1365  * Parse the URL to get all components, which are: scheme, hostname,
1366  * port, username, password, path (URI), query (the CGI parameter list),
1367  * fragment (#).
1368  *
1369  * On success return the HTTPURLParse structure, otherwise NULL if the URL
1370  * seems malformed.
1371  *
1372  * We assume HTTP URLs of the form specified in "3.2.2 http URL" in
1373  * RFC 2616:
1374  *
1375  * http_URL = "http:" "//" [ userid : password "@"] host [ ":" port ] [ abs_path [ "?" query ]]
1376  */
1378 {
1379  HTTPURLParse *p;
1380  Octstr *prefix, *prefix_https;
1381  long prefix_len;
1382  int host_len, colon, slash, at, auth_sep, query;
1383  host_len = colon = slash = at = auth_sep = query = 0;
1384 
1385  prefix = octstr_imm("http://");
1386  prefix_https = octstr_imm("https://");
1387  prefix_len = octstr_len(prefix);
1388 
1389  if (octstr_case_search(url, prefix, 0) != 0) {
1390  if (octstr_case_search(url, prefix_https, 0) == 0) {
1391 #ifdef HAVE_LIBSSL
1392  debug("gwlib.http", 0, "HTTPS URL; Using SSL for the connection");
1393  prefix = prefix_https;
1394  prefix_len = octstr_len(prefix_https);
1395 #else
1396  error(0, "Attempt to use HTTPS <%s> but SSL not compiled in",
1397  octstr_get_cstr(url));
1398  return NULL;
1399 #endif
1400  } else {
1401  error(0, "URL <%s> doesn't start with `%s' nor `%s'",
1403  octstr_get_cstr(prefix_https));
1404  return NULL;
1405  }
1406  }
1407 
1408  /* an URL should be more (at least one charset) then the scheme itself */
1409  if (octstr_len(url) == prefix_len) {
1410  error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
1411  return NULL;
1412  }
1413 
1414  /* check if colon and slashes are within scheme */
1415  colon = octstr_search_char(url, ':', prefix_len);
1416  slash = octstr_search_char(url, '/', prefix_len);
1417  if (colon == prefix_len || slash == prefix_len) {
1418  error(0, "URL <%s> is malformed.", octstr_get_cstr(url));
1419  return NULL;
1420  }
1421 
1422  /* create struct and add values succesively while parsing */
1423  p = http_urlparse_create();
1424  p->url = octstr_duplicate(url);
1425  p->scheme = octstr_duplicate(prefix);
1426 
1427  /* try to parse authentication separator */
1428  at = octstr_search_char(url, '@', prefix_len);
1429  if (at != -1) {
1430  if ((slash == -1 || ( slash != -1 && at < slash))) {
1431  auth_sep = octstr_search_char(url, ':', prefix_len);
1432  if (auth_sep != -1 && (auth_sep < at)) {
1433  octstr_set_char(url, auth_sep, '@');
1434  colon = octstr_search_char(url, ':', prefix_len);
1435  }
1436  } else {
1437  at = -1;
1438  }
1439  }
1440 
1441  /*
1442  * We have to watch out here for 4 cases:
1443  * a) hostname, no port or path
1444  * b) hostname, port, no path
1445  * c) hostname, path, no port
1446  * d) hostname, port and path
1447  */
1448 
1449  /* we only have the hostname, no port or path. */
1450  if (slash == -1 && colon == -1) {
1451  host_len = octstr_len(url) - prefix_len;
1452 #ifdef HAVE_LIBSSL
1453  p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ?
1455 #else
1456  p->port = HTTP_PORT;
1457 #endif /* HAVE_LIBSSL */
1458  }
1459  /* we have a port, but no path. */
1460  else if (slash == -1) {
1461  host_len = colon - prefix_len;
1462  if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
1463  error(0, "URL <%s> has malformed port number.",
1464  octstr_get_cstr(url));
1466  return NULL;
1467  }
1468  }
1469  /* we have a path, but no port. */
1470  else if (colon == -1 || colon > slash) {
1471  host_len = slash - prefix_len;
1472 #ifdef HAVE_LIBSSL
1473  p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ?
1475 #else
1476  p->port = HTTP_PORT;
1477 #endif /* HAVE_LIBSSL */
1478  }
1479  /* we have both, path and port. */
1480  else if (colon < slash) {
1481  host_len = colon - prefix_len;
1482  if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) {
1483  error(0, "URL <%s> has malformed port number.",
1484  octstr_get_cstr(url));
1486  return NULL;
1487  }
1488  /* none of the above, so there is something wrong here */
1489  } else {
1490  error(0, "Internal error in URL parsing logic.");
1492  return NULL;
1493  }
1494 
1495  /* there was an authenticator separator, so try to parse
1496  * the username and password credentials */
1497  if (at != -1) {
1498  int at2;
1499 
1500  at2 = octstr_search_char(url, '@', prefix_len);
1501  p->user = octstr_copy(url, prefix_len, at2 - prefix_len);
1502  p->pass = (at2 != at) ? octstr_copy(url, at2 + 1, at - at2 - 1) : NULL;
1503 
1504  /* url-decode user & pass */
1505  if (p->user != NULL)
1506  octstr_url_decode(p->user);
1507  if (p->pass != NULL)
1508  octstr_url_decode(p->pass);
1509 
1510  if (auth_sep != -1)
1511  octstr_set_char(url, auth_sep, ':');
1512 
1513  host_len = host_len - at + prefix_len - 1;
1514  prefix_len = at + 1;
1515  }
1516 
1517  /* query (CGI vars) */
1518  query = octstr_search_char(url, '?', (slash == -1) ? prefix_len : slash);
1519  if (query != -1) {
1520  p->query = octstr_copy(url, query + 1, octstr_len(url));
1521  if (colon == -1)
1522  host_len = slash != -1 ? slash - prefix_len : query - prefix_len;
1523  }
1524 
1525  /* path */
1526  p->path = (slash == -1) ?
1527  octstr_create("/") : ((query != -1) && (query > slash) ?
1528  octstr_copy(url, slash, query - slash) :
1529  octstr_copy(url, slash, octstr_len(url) - slash));
1530 
1531  /* hostname */
1532  p->host = octstr_copy(url, prefix_len, host_len);
1533 
1534  /* XXX add fragment too */
1535 
1536  /* dump components */
1537  parse_dump(p);
1538 
1539  return p;
1540 }
1541 
1542 /* copy all relevant parsed data to the server info struct */
1544 {
1545  if (p == NULL || t == NULL)
1546  return;
1547 
1548  if (p->user && !t->username)
1549  t->username = octstr_duplicate(p->user);
1550  if (p->pass && !t->password)
1551  t->password = octstr_duplicate(p->pass);
1552  if (p->host && !t->host)
1553  t->host = octstr_duplicate(p->host);
1554  if (p->port && !t->port)
1555  t->port = p->port;
1556  if (p->path && !t->uri) {
1557  t->uri = octstr_duplicate(p->path);
1558  if (p->query) { /* add the query too */
1559  octstr_append_char(t->uri, '?');
1560  octstr_append(t->uri, p->query);
1561  }
1562  }
1563  t->ssl = (p->scheme && (octstr_compare(p->scheme, octstr_imm("https://")) == 0)
1564  && !t->ssl) ? 1 : 0;
1565 }
1566 
1568 {
1569  Connection *conn = NULL;
1570  Octstr *host;
1571  HTTPURLParse *p;
1572  int port, ssl;
1573 
1574  /* if the parsing has not yet been done, then do it now */
1575  if (!trans->host && trans->port == 0 && trans->url != NULL) {
1576  if ((p = parse_url(trans->url)) != NULL) {
1577  parse2trans(p, trans);
1579  } else {
1580  goto error;
1581  }
1582  }
1583 
1584  if (proxy_used_for_host(trans->host, trans->url)) {
1585  host = proxy_hostname;
1586  port = proxy_port;
1587  ssl = proxy_ssl;
1588  } else {
1589  host = trans->host;
1590  port = trans->port;
1591  ssl = trans->ssl;
1592  }
1593 
1594  conn = conn_pool_get(host, port, ssl, trans->certkeyfile,
1595  http_interface);
1596  if (conn == NULL)
1597  goto error;
1598 
1599  return conn;
1600 
1601 error:
1602  conn_destroy(conn);
1603  error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
1604  return NULL;
1605 }
1606 
1607 
1608 /*
1609  * Build and send the HTTP request. Return 0 for success or -1 for error.
1610  */
1611 static int send_request(HTTPServer *trans)
1612 {
1613  char buf[128];
1614  Octstr *request = NULL;
1615 
1616  if (trans->method == HTTP_METHOD_POST || trans->method == HTTP_METHOD_PATCH || trans->method == HTTP_METHOD_PUT) {
1617  /*
1618  * Add a Content-Length header. Override an existing one, if
1619  * necessary. We must have an accurate one in order to use the
1620  * connection for more than a single request.
1621  */
1622  http_header_remove_all(trans->request_headers, "Content-Length");
1623  snprintf(buf, sizeof(buf), "%ld", octstr_len(trans->request_body));
1624  http_header_add(trans->request_headers, "Content-Length", buf);
1625  }
1626  /*
1627  * ok, this has to be an GET or HEAD request method then,
1628  * if it contains a body, then this is not HTTP conform, so at
1629  * least warn the user
1630  */
1631  else if (trans->request_body != NULL) {
1632  warning(0, "HTTP: GET or HEAD method request contains body:");
1633  octstr_dump(trans->request_body, 0);
1634  }
1635 
1636  /*
1637  * we have to assume all values in trans are already set
1638  * by parse_url() before calling this.
1639  */
1640 
1641  if (trans->username != NULL)
1643  trans->password);
1644 
1645  if (proxy_used_for_host(trans->host, trans->url)) {
1647  request = build_request(http_method2name(trans->method), trans->url,
1648  trans->host, trans->port, trans->ssl,
1649  trans->request_headers,
1650  trans->request_body);
1651  } else {
1652  request = build_request(http_method2name(trans->method), trans->uri,
1653  trans->host, trans->port, trans->ssl,
1654  trans->request_headers,
1655  trans->request_body);
1656  }
1657 
1658  debug("gwlib.http", 0, "HTTP: Sending request:");
1659  octstr_dump(request, 0);
1660  if (conn_write(trans->conn, request) == -1)
1661  goto error;
1662 
1663  octstr_destroy(request);
1664 
1665  return 0;
1666 
1667 error:
1668  conn_destroy(trans->conn);
1669  trans->conn = NULL;
1670  octstr_destroy(request);
1671  error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url));
1672  return -1;
1673 }
1674 
1675 
1676 /*
1677  * This thread starts the transaction: it connects to the server and sends
1678  * the request. It then sends the transaction to the read_response_thread
1679  * via started_requests_queue.
1680  */
1681 static void write_request_thread(void *arg)
1682 {
1683  HTTPServer *trans;
1684  int rc;
1685 
1686  while (run_status == running) {
1688  if (trans == NULL)
1689  break;
1690 
1691  gw_assert(trans->state == request_not_sent);
1692 
1693  debug("gwlib.http", 0, "Queue contains %ld pending requests.", gwlist_len(pending_requests));
1694 
1695  /*
1696  * get the connection to use
1697  * also calls parse_url() to populate the trans values
1698  */
1699  trans->conn = get_connection(trans);
1700 
1701  if (trans->conn == NULL)
1702  gwlist_produce(trans->caller, trans);
1703  else if (conn_is_connected(trans->conn) == 0) {
1704  debug("gwlib.http", 0, "Socket connected at once");
1705 
1706  if ((rc = send_request(trans)) == 0) {
1707  trans->state = reading_status;
1709  trans);
1710  } else {
1711  gwlist_produce(trans->caller, trans);
1712  }
1713 
1714  } else { /* Socket not connected, wait for connection */
1715  debug("gwlib.http", 0, "Socket connecting");
1716  trans->state = connecting;
1718  }
1719  }
1720 }
1721 
1722 
1723 static void start_client_threads(void)
1724 {
1726  /*
1727  * To be really certain, we must repeat the test, but use the
1728  * lock first. If the test failed, however, we _know_ we've
1729  * already initialized. This strategy of double testing avoids
1730  * using the lock more than a few times at startup.
1731  */
1735  if (gwthread_create(write_request_thread, NULL) == -1) {
1736  error(0, "HTTP: Could not start client write_request thread.");
1739  } else
1741  }
1743  }
1744 }
1745 
1747 {
1749 }
1750 
1751 void http_set_client_timeout(long timeout)
1752 {
1753  http_client_timeout = timeout;
1754  if (client_fdset != NULL) {
1755  /* we are already initialized set timeout in fdset */
1757  }
1758 }
1759 
1761  Octstr *body, int follow, void *id, Octstr *certkeyfile)
1762 {
1763  HTTPServer *trans;
1764  int follow_remaining;
1765 
1766  if (follow)
1767  follow_remaining = HTTP_MAX_FOLLOW;
1768  else
1769  follow_remaining = 0;
1770 
1771  trans = server_create(caller, method, url, headers, body, follow_remaining,
1772  certkeyfile);
1773 
1774  if (id == NULL)
1775  /* We don't leave this NULL so http_receive_result can use NULL
1776  * to signal no more requests */
1777  trans->request_id = http_start_request;
1778  else
1779  trans->request_id = id;
1780 
1783 }
1784 
1785 
1787  List **headers, Octstr **body, int blocking)
1788 {
1789  HTTPServer *trans;
1790  void *request_id;
1791 
1792  if (blocking == 0)
1793  trans = gwlist_extract_first(caller);
1794  else
1795  trans = gwlist_consume(caller);
1796  if (trans == NULL)
1797  return NULL;
1798 
1799  request_id = trans->request_id;
1800  *status = trans->status;
1801 
1802  if (trans->status >= 0) {
1803  *final_url = trans->url;
1804  *headers = trans->response->headers;
1805  *body = trans->response->body;
1806 
1807  trans->url = NULL;
1808  trans->response->headers = NULL;
1809  trans->response->body = NULL;
1810  } else {
1811  *final_url = NULL;
1812  *headers = NULL;
1813  *body = NULL;
1814  }
1815 
1816  server_destroy(trans);
1817  return request_id;
1818 }
1819 
1820 
1821 int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url,
1822  List **reply_headers, Octstr **reply_body)
1823 {
1824  HTTPCaller *caller;
1825  int status;
1826  void *ret;
1827 
1829  http_start_request(caller, method, url, request_headers,
1830  NULL, 1, http_get_real, NULL);
1831  ret = http_receive_result(caller, &status, final_url,
1832  reply_headers, reply_body);
1834  if (ret == NULL)
1835  return -1;
1836  return status;
1837 }
1838 
1839 
1840 static void client_init(void)
1841 {
1845 }
1846 
1847 
1848 static void client_shutdown(void)
1849 {
1856  client_fdset = NULL;
1858  http_interface = NULL;
1859 }
1860 
1861 
1862 /***********************************************************************
1863  * HTTP server interface.
1864  */
1865 
1866 
1867 /*
1868  * Information about a client that has connected to the server we implement.
1869  */
1870 struct HTTPClient {
1871  int port;
1874  enum {
1879  } state;
1880  int method; /* HTTP_METHOD_ value */
1884  unsigned long conn_time; /* store time for timeouting */
1886 };
1887 
1888 
1889 /*
1890  * Variables related to server side implementation.
1891  */
1892 static Mutex *server_thread_lock = NULL;
1893 static volatile sig_atomic_t server_thread_is_running = 0;
1894 static long server_thread_id = -1;
1895 static List *new_server_sockets = NULL;
1897 static int keep_servers_open = 0;
1898 /* List with all active HTTPClient's */
1900 
1901 
1903 {
1904  HTTPClient *p;
1905 
1906 #ifdef HAVE_LIBSSL
1907  if (conn_get_ssl(conn))
1908  debug("gwlib.http", 0, "HTTP: Creating SSL-enabled HTTPClient for `%s', using cipher '%s'.",
1909  octstr_get_cstr(ip), SSL_get_cipher_version(conn_get_ssl(conn)));
1910  else
1911 #endif
1912  debug("gwlib.http", 0, "HTTP: Creating HTTPClient for `%s'.", octstr_get_cstr(ip));
1913  p = gw_malloc(sizeof(*p));
1914  p->port = port;
1915  p->conn = conn;
1916  p->ip = ip;
1917  p->state = reading_request_line;
1918  p->url = NULL;
1919  p->use_version_1_0 = 0;
1920  p->persistent_conn = 1;
1921  p->conn_time = time(NULL);
1922  p->request = NULL;
1923  debug("gwlib.http", 0, "HTTP: Created HTTPClient area %p.", p);
1924 
1925  /* add this client to active_connections */
1927 
1928  return p;
1929 }
1930 
1931 
1932 static void client_destroy(void *client)
1933 {
1934  HTTPClient *p;
1935  long a_len;
1936 
1937  if (client == NULL)
1938  return;
1939 
1940  p = client;
1941 
1942  /* drop this client from active_connections list */
1945  panic(0, "HTTP: Race condition in client_destroy(%p) detected!", client);
1946 
1947  /* signal server thread that client slot is free */
1948  a_len = gwlist_len(active_connections);
1950 
1951  if (a_len >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS - 1)
1953 
1954  debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p);
1955  gw_assert_allocated(p, __FILE__, __LINE__, __func__);
1956  debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.",
1957  octstr_get_cstr(p->ip));
1958 
1959  conn_destroy(p->conn);
1960  octstr_destroy(p->ip);
1961  octstr_destroy(p->url);
1962  entity_destroy(p->request);
1963  gw_free(p);
1964 }
1965 
1966 
1967 static void client_reset(HTTPClient *p)
1968 {
1969  debug("gwlib.http", 0, "HTTP: Resetting HTTPClient for `%s'.",
1970  octstr_get_cstr(p->ip));
1971  p->state = reading_request_line;
1972  p->conn_time = time(NULL);
1973  gw_assert(p->request == NULL);
1974 }
1975 
1976 
1977 /*
1978  * Checks whether the client connection is meant to be persistent or not.
1979  * Returns 1 for true, 0 for false.
1980  * Reference: RFC2616, section 8.1.2.1 Negotiation
1981  */
1982 static int client_is_persistent(List *headers, int use_version_1_0)
1983 {
1984  Octstr *h = http_header_find_first(headers, "Connection");
1985 
1986  if (h == NULL) {
1987  /* assumes persistent for HTTP/1.1, not for HTTP/1.0 */
1988  return !use_version_1_0;
1989  } else {
1990  List *values = octstr_split(h, octstr_imm(","));
1991  int ret;
1992  octstr_destroy(h);
1993  if (gwlist_search(values, octstr_imm("keep-alive"), octstr_item_case_match) != NULL) {
1994  /* Keep-Alive was requested */
1995  ret = 1;
1996  } else if (gwlist_search(values, octstr_imm("close"), octstr_item_case_match) != NULL) {
1997  /* Close was requested */
1998  ret = 0;
1999  } else {
2000  /* Nothing was requested, so based on HTTP version */
2001  ret = (!use_version_1_0);
2002  }
2004  return ret;
2005  }
2006 
2007  return 1;
2008 }
2009 
2010 
2011 /*
2012  * Port specific lists of clients with requests.
2013  */
2014 struct port {
2015  int fd;
2016  int port;
2017  int ssl;
2021 };
2022 
2023 
2024 static Mutex *port_mutex = NULL;
2025 static Dict *port_collection = NULL;
2026 
2027 
2028 static int port_match(void *client, void *port)
2029 {
2030  return ((HTTPClient*)client)->port == *((int*)port);
2031 }
2032 
2033 
2034 static void port_init(void)
2035 {
2037  port_collection = dict_create(1024, NULL);
2038  /* create list with all active_connections */
2040 }
2041 
2042 static void port_shutdown(void)
2043 {
2046  /* destroy active_connections list */
2048 }
2049 
2050 
2051 static Octstr *port_key(int port)
2052 {
2053  return octstr_format("%d", port);
2054 }
2055 
2056 
2057 static struct port *port_add(int port)
2058 {
2059  Octstr *key;
2060  struct port *p;
2061 
2062  key = port_key(port);
2064  if ((p = dict_get(port_collection, key)) == NULL) {
2065  p = gw_malloc(sizeof(*p));
2070  dict_put(port_collection, key, p);
2071  } else {
2072  warning(0, "HTTP: port_add called for existing port (%d)", port);
2073  }
2075  octstr_destroy(key);
2076 
2077  return p;
2078 }
2079 
2080 
2081 static void port_remove(int port)
2082 {
2083  Octstr *key;
2084  struct port *p;
2085  List *l;
2086  HTTPClient *client;
2087 
2088  key = port_key(port);
2090  p = dict_remove(port_collection, key);
2092  octstr_destroy(key);
2093 
2094  if (p == NULL) {
2095  error(0, "HTTP: Could not find port (%d) in port_collection.", port);
2096  return;
2097  }
2098 
2100  while (counter_value(p->active_consumers) > 0)
2101  gwthread_sleep(0.1); /* Reasonable use of busy waiting. */
2102 
2105 
2106  /*
2107  * In order to avoid race conditions with FDSet thread, we
2108  * destroy Clients for this port in two steps:
2109  * 1) unregister from fdset with gwlist_lock held, so client_destroy
2110  * cannot destroy our client that we currently use
2111  * 2) without gwlist_lock held destroy every client, we can do this
2112  * because we only one thread that can use this client struct
2113  */
2116  while(l != NULL && (client = gwlist_extract_first(l)) != NULL)
2117  conn_unregister(client->conn);
2119  gwlist_destroy(l, NULL);
2120  while((client = gwlist_search(active_connections, &port, port_match)) != NULL)
2122 
2123  /* now destroy fdset */
2125  gw_free(p);
2126 }
2127 
2128 
2130 {
2131  Octstr *key;
2132  struct port *p;
2133 
2135  key = port_key(client->port);
2136  p = dict_get(port_collection, key);
2137  octstr_destroy(key);
2138  if (p == NULL) {
2139  /* client was too slow and we closed port already */
2142  return;
2143  }
2146 }
2147 
2148 
2150 {
2151  Octstr *key;
2152  struct port *p;
2153  HTTPClient *client;
2154 
2156  key = port_key(port);
2157  p = dict_get(port_collection, key);
2158  octstr_destroy(key);
2159 
2160  if (p == NULL) {
2161  client = NULL;
2163  } else {
2165  mutex_unlock(port_mutex); /* Placement of this unlock is tricky. */
2168  }
2169  return client;
2170 }
2171 
2172 
2173 static void port_set_timeout(int port, long timeout)
2174 {
2175  Octstr *key;
2176  struct port *p;
2177 
2179  key = port_key(port);
2180  p = dict_get(port_collection, key);
2181  octstr_destroy(key);
2182 
2183  if (p != NULL)
2184  fdset_set_timeout(p->server_fdset, timeout);
2185 
2187 }
2188 
2189 
2191 {
2192  Octstr *key;
2193  struct port *p;
2194  FDSet *ret = NULL;
2195 
2197  key = port_key(port);
2198  p = dict_get(port_collection, key);
2199  octstr_destroy(key);
2200 
2201  if (p != NULL)
2202  ret = p->server_fdset;
2203 
2205 
2206  return ret;
2207 }
2208 
2209 
2211  int *use_version_1_0, Octstr *line)
2212 {
2213  List *words;
2214  Octstr *version;
2215  Octstr *method_str;
2216  int ret;
2217 
2218  words = octstr_split_words(line);
2219  if (gwlist_len(words) != 3) {
2221  return -1;
2222  }
2223 
2224  method_str = gwlist_get(words, 0);
2225  *url = gwlist_get(words, 1);
2226  version = gwlist_get(words, 2);
2227  gwlist_destroy(words, NULL);
2228 
2229  *method = http_name2method(method_str);
2230  if (*method == -1)
2231  goto error;
2232 
2233  ret = parse_http_version(version);
2234  if (ret < 0)
2235  goto error;
2236  *use_version_1_0 = !ret;
2237 
2238  octstr_destroy(method_str);
2239  octstr_destroy(version);
2240  return 0;
2241 
2242 error:
2243  octstr_destroy(method_str);
2244  octstr_destroy(*url);
2245  octstr_destroy(version);
2246  *url = NULL;
2247  return -1;
2248 }
2249 
2250 
2251 static void receive_request(Connection *conn, void *data)
2252 {
2253  HTTPClient *client;
2254  Octstr *line;
2255  int ret;
2256 
2257  if (run_status != running) {
2258  conn_unregister(conn);
2259  return;
2260  }
2261 
2262  client = data;
2263 
2264  for (;;) {
2265  switch (client->state) {
2266  case reading_request_line:
2267  line = conn_read_line(conn);
2268  if (line == NULL) {
2269  if (conn_eof(conn) || conn_error(conn))
2270  goto error;
2271  return;
2272  }
2273  ret = parse_request_line(&client->method, &client->url,
2274  &client->use_version_1_0, line);
2275  octstr_destroy(line);
2276  /* client sent bad request? */
2277  if (ret == -1) {
2278  /*
2279  * mark client as not persistent in order to destroy connection
2280  * afterwards
2281  */
2282  client->persistent_conn = 0;
2283  /* unregister connection, http_send_reply handle this */
2284  conn_unregister(conn);
2285  http_send_reply(client, HTTP_BAD_REQUEST, NULL, NULL);
2286  return;
2287  }
2288  /*
2289  * RFC2616 (4.3) says we should read a message body if there
2290  * is one, even on GET requests.
2291  */
2293  client->state = reading_request;
2294  break;
2295 
2296  case reading_request:
2297  ret = entity_read(client->request, conn);
2298  if (ret < 0)
2299  goto error;
2300  if (ret == 0) {
2301  client->state = request_is_being_handled;
2302  conn_unregister(conn);
2304  }
2305  return;
2306 
2307  case sending_reply:
2308  /* Implicit conn_unregister() and _destroy */
2309  if (conn_error(conn))
2310  goto error;
2311  if (conn_outbuf_len(conn) > 0)
2312  return;
2313  /* Reply has been sent completely */
2314  if (!client->persistent_conn) {
2315  /*
2316  * in order to avoid race conditions while conn will be destroyed but
2317  * conn is still in use, we call conn_unregister explicit here because
2318  * conn_unregister call uses locks
2319  */
2320  conn_unregister(conn);
2322  return;
2323  }
2324  /* Start reading another request */
2326  break;
2327 
2328  default:
2329  panic(0, "Internal error: HTTPClient state is wrong.");
2330  }
2331  }
2332 
2333 error:
2334  /*
2335  * in order to avoid race conditions while conn will be destroyed but
2336  * conn is still in use, we call conn_unregister explicit here because
2337  * conn_unregister call uses locks
2338  */
2339  conn_unregister(conn);
2341 }
2342 
2343 
2344 static void server_thread(void *dummy)
2345 {
2346  struct pollfd *tab = NULL;
2347  struct port **ports = NULL;
2348  int tab_size = 0, n, i, fd, ret, max_clients_reached;
2349  struct sockaddr_in addr;
2350  socklen_t addrlen;
2351  HTTPClient *client;
2352  Connection *conn;
2353  int *portno;
2354 
2355  n = max_clients_reached = 0;
2356  while (run_status == running && keep_servers_open) {
2357  while (n == 0 || gwlist_len(new_server_sockets) > 0) {
2358  struct port *p = gwlist_consume(new_server_sockets);
2359  if (p == NULL) {
2360  debug("gwlib.http", 0, "HTTP: No new servers. Quitting.");
2361  break;
2362  } else {
2363  debug ("gwlib.http", 0, "HTTP: Including port %d, fd %d for polling in server thread", p->port, p->fd);
2364  }
2365  if (tab_size <= n) {
2366  tab_size++;
2367  tab = gw_realloc(tab, tab_size * sizeof(*tab));
2368  ports = gw_realloc(ports, tab_size * sizeof(*ports));
2369  if (tab == NULL || ports == NULL) {
2370  tab_size--;
2371  port_remove(p->port);
2372  continue;
2373  }
2374  }
2375  tab[n].fd = p->fd;
2376  tab[n].events = POLLIN;
2377  ports[n] = p;
2378  n++;
2379  }
2380 
2381  if (max_clients_reached && gwlist_len(active_connections) >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS) {
2382  /* TODO start cleanup of stale connections */
2383  /* wait for slots to become free */
2384  gwthread_sleep(1.0);
2385  } else if (!max_clients_reached && (ret = gwthread_poll(tab, n, -1.0)) == -1) {
2386  if (errno != EINTR) /* a signal was caught during poll() function */
2387  warning(errno, "HTTP: gwthread_poll failed.");
2388  continue;
2389  }
2390 
2391  for (i = 0; i < n; ++i) {
2392  if (tab[i].revents & POLLIN) {
2393  /* check our limit */
2395  max_clients_reached = 1;
2396  break;
2397  } else {
2398  max_clients_reached = 0;
2399  }
2400 
2401  addrlen = sizeof(addr);
2402  fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen);
2403  if (fd == -1) {
2404  error(errno, "HTTP: Error accepting a client.");
2405  } else {
2406  Octstr *client_ip = host_ip(addr);
2407  /*
2408  * Be aware that conn_wrap_fd() will return NULL if SSL
2409  * handshake has failed, so we only client_create() if
2410  * there is an conn.
2411  */
2412  if ((conn = conn_wrap_fd(fd, ports[i]->ssl))) {
2413  client = client_create(ports[i]->port, conn, client_ip);
2414  conn_register(conn, ports[i]->server_fdset, receive_request, client);
2415  } else {
2416  error(0, "HTTP: unsuccessful SSL handshake for client `%s'",
2417  octstr_get_cstr(client_ip));
2418  octstr_destroy(client_ip);
2419  }
2420  }
2421  }
2422  }
2423 
2424  while ((portno = gwlist_extract_first(closed_server_sockets)) != NULL) {
2425  for (i = 0; i < n; ++i) {
2426  if (ports[i]->port == *portno) {
2427  (void) close(tab[i].fd);
2428  tab[i].fd = -1;
2429  tab[i].events = 0;
2430  port_remove(ports[i]->port);
2431  ports[i] = NULL;
2432  n--;
2433 
2434  /* now put the last entry on this place */
2435  tab[i].fd = tab[n].fd;
2436  tab[i].events = tab[n].events;
2437  tab[n].fd = -1;
2438  tab[n].events = 0;
2439  ports[i] = ports[n];
2440  }
2441  }
2442  gw_free(portno);
2443  }
2444  }
2445 
2446  /* make sure we close all ports */
2447  for (i = 0; i < n; ++i) {
2448  (void) close(tab[i].fd);
2449  port_remove(ports[i]->port);
2450  }
2451  gw_free(tab);
2452  gw_free(ports);
2453 
2454  server_thread_id = -1;
2455 }
2456 
2457 
2458 static void start_server_thread(void)
2459 {
2460  if (!server_thread_is_running) {
2461  /*
2462  * To be really certain, we must repeat the test, but use the
2463  * lock first. If the test failed, however, we _know_ we've
2464  * already initialized. This strategy of double testing avoids
2465  * using the lock more than a few times at startup.
2466  */
2468  if (!server_thread_is_running) {
2471  }
2473  }
2474 }
2475 
2476 
2477 void http_set_server_timeout(int port, long timeout)
2478 {
2479  port_set_timeout(port, timeout);
2480 }
2481 
2482 
2483 int http_open_port_if(int port, int ssl, Octstr *interface)
2484 {
2485  struct port *p;
2486 
2487  if (ssl)
2488  info(0, "HTTP: Opening SSL server at port %d.", port);
2489  else
2490  info(0, "HTTP: Opening server at port %d.", port);
2491  p = port_add(port);
2492  p->port = port;
2493  p->ssl = ssl;
2494  p->fd = make_server_socket(port, (interface ? octstr_get_cstr(interface) : NULL));
2495  if (p->fd == -1) {
2496  port_remove(port);
2497  return -1;
2498  }
2499 
2501  keep_servers_open = 1;
2504 
2505  return 0;
2506 }
2507 
2508 
2509 int http_open_port(int port, int ssl)
2510 {
2511  return http_open_port_if(port, ssl, NULL);
2512 }
2513 
2514 
2516 {
2517  int *p;
2518 
2519  p = gw_malloc(sizeof(*p));
2520  *p = port;
2523 }
2524 
2525 
2527 {
2528  if (server_thread_id != -1) {
2529  keep_servers_open = 0;
2533  }
2534 }
2535 
2536 
2537 /*
2538  * Parse CGI variables in <pairs> (query string in url or request body)
2539  * Expected format: var1=value1&var2&var3=value3...
2540  * Append HTTPCGIvar pointers to supplied list
2541  */
2542 void parse_cgivars(List *cgivars, Octstr *pairs)
2543 {
2544  HTTPCGIVar *v;
2545  Octstr *pair;
2546  long ampersand, equal, start;
2547  long pairs_len = octstr_len(pairs);
2548 
2549  for (start = 0; start < pairs_len; start = ampersand + 1) {
2550  ampersand = octstr_search_char(pairs, '&', start);
2551  if (ampersand == -1)
2552  ampersand = pairs_len;
2553  pair = octstr_copy(pairs, start, ampersand - start);
2554 
2555  equal = octstr_search_char(pair, '=', 0);
2556  if (equal == -1)
2557  equal = octstr_len(pair);
2558 
2559  v = gw_malloc(sizeof(HTTPCGIVar));
2560  v->name = octstr_copy(pair, 0, equal);
2561  v->value = octstr_copy(pair, equal + 1, octstr_len(pair));
2562  octstr_url_decode(v->name);
2564  gwlist_append(cgivars, v);
2565 
2566  octstr_destroy(pair);
2567  }
2568 }
2569 
2570 
2572  List **headers, Octstr **body,
2573  List **cgivars)
2574 {
2575  HTTPClient *client;
2576  Octstr *query, *content_type, *charset;
2577  int question_mark;
2578 
2579  do {
2581  if (client == NULL) {
2582  debug("gwlib.http", 0, "HTTP: No clients with requests, quitting.");
2583  return NULL;
2584  }
2585  /* check whether client connection still ok */
2586  conn_wait(client->conn, 0);
2587  if (conn_error(client->conn) || conn_eof(client->conn)) {
2589  client = NULL;
2590  }
2591  } while(client == NULL);
2592 
2593  debug("gwlib.http", 0, "HTTP: Got %s request with url='%s' and body='%s'",
2594  http_method2name(client->method), octstr_get_cstr(client->url), octstr_get_cstr(client->request->body));
2595 
2596  *client_ip = octstr_duplicate(client->ip);
2597  *url = client->url;
2598  *headers = client->request->headers;
2599  *body = client->request->body;
2600  *cgivars = gwlist_create();
2601 
2602  /* is there a query string in the url? */
2603  question_mark = octstr_search_char(*url, '?', 0);
2604  if (question_mark >= 0) {
2605  /* parse the query string */
2606  query = octstr_copy(*url, question_mark + 1, octstr_len(*url));
2607  parse_cgivars(*cgivars, query);
2608  octstr_destroy(query);
2609 
2610  /* remove query string from url */
2611  octstr_truncate(*url, question_mark);
2612  }
2613 
2614  if (client->method == HTTP_METHOD_POST || client->method == HTTP_METHOD_PUT) {
2615  if (octstr_len(*body) > 0) {
2617  if (octstr_str_compare(content_type, "application/x-www-form-urlencoded") == 0) {
2618  /* parse the body */
2619  parse_cgivars(*cgivars, *body);
2620  }
2623  }
2624  } else {
2625  octstr_destroy(*body);
2626  *body = NULL;
2627  }
2628 
2629  client->persistent_conn = client_is_persistent(client->request->headers,
2630  client->use_version_1_0);
2631 
2632  client->url = NULL;
2633  client->request->headers = NULL;
2634  client->request->body = NULL;
2635  entity_destroy(client->request);
2636  client->request = NULL;
2637 
2638  return client;
2639 }
2640 
2641 /*
2642  * The http_send_reply(...) uses this function to determinate the
2643  * reason phrase for a status code.
2644  */
2645 static const char *http_reason_phrase(int status)
2646 {
2647  switch (status) {
2648  case HTTP_OK:
2649  return "OK"; /* 200 */
2650  case HTTP_CREATED:
2651  return "Created"; /* 201 */
2652  case HTTP_ACCEPTED:
2653  return "Accepted"; /* 202 */
2654  case HTTP_NO_CONTENT:
2655  return "No Content"; /* 204 */
2656  case HTTP_RESET_CONTENT:
2657  return "Reset Content"; /* 205 */
2659  return "Moved Permanently"; /* 301 */
2660  case HTTP_FOUND:
2661  return "Found"; /* 302 */
2662  case HTTP_SEE_OTHER:
2663  return "See Other"; /* 303 */
2664  case HTTP_NOT_MODIFIED:
2665  return "Not Modified"; /* 304 */
2667  return "Temporary Redirect"; /* 307 */
2668  case HTTP_BAD_REQUEST:
2669  return "Bad Request"; /* 400 */
2670  case HTTP_UNAUTHORIZED:
2671  return "Unauthorized"; /* 401 */
2672  case HTTP_FORBIDDEN:
2673  return "Forbidden"; /* 403 */
2674  case HTTP_NOT_FOUND:
2675  return "Not Found"; /* 404 */
2676  case HTTP_BAD_METHOD:
2677  return "Method Not Allowed"; /* 405 */
2678  case HTTP_NOT_ACCEPTABLE:
2679  return "Not Acceptable"; /* 406 */
2681  return "Request Entity Too Large"; /* 413 */
2683  return "Unsupported Media Type"; /* 415 */
2685  return "Internal Server Error"; /* 500 */
2686  case HTTP_NOT_IMPLEMENTED:
2687  return "Not Implemented"; /* 501 */
2688  case HTTP_BAD_GATEWAY:
2689  return "Bad Gateway"; /* 502 */
2690  }
2691  return "Foo";
2692 }
2693 
2694 
2696  Octstr *body)
2697 {
2698  Octstr *response;
2699  Octstr *date;
2700  long i;
2701  int ret;
2702 
2703  if (client->use_version_1_0)
2704  response = octstr_format("HTTP/1.0 %d %s\r\n", status, http_reason_phrase(status));
2705  else
2706  response = octstr_format("HTTP/1.1 %d %s\r\n", status, http_reason_phrase(status));
2707 
2708  /* identify ourselfs */
2709  octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION);
2710 
2711  /* let's inform the client of our time */
2712  date = date_format_http(time(NULL));
2715 
2716  octstr_format_append(response, "Content-Length: %ld\r\n", octstr_len(body));
2717 
2718  /* Indicate if we're keeping the connection or closing. */
2719  if (client->persistent_conn)
2720  octstr_format_append(response, "Connection: Keep-Alive\r\n");
2721  else
2722  octstr_format_append(response, "Connection: Close\r\n");
2723 
2724  for (i = 0; i < gwlist_len(headers); ++i)
2725  octstr_format_append(response, "%S\r\n", gwlist_get(headers, i));
2726  octstr_format_append(response, "\r\n");
2727 
2728  if (body != NULL && client->method != HTTP_METHOD_HEAD && client->method != HTTP_METHOD_DELETE)
2729  octstr_append(response, body);
2730 
2731  ret = conn_write(client->conn, response);
2733 
2734  /* obey return code of conn_write() */
2735  /* sending response was successful */
2736  if (ret == 0) {
2737  /* HTTP/1.0 or 1.1, hence keep-alive or keep-alive */
2738  if (!client->persistent_conn) {
2740  } else {
2741  /* XXX mark this HTTPClient in the keep-alive cleaner thread */
2744  }
2745  }
2746  /* queued for sending, we don't want to block */
2747  else if (ret == 1) {
2748  client->state = sending_reply;
2750  }
2751  /* error while sending response */
2752  else {
2754  }
2755 }
2756 
2757 
2759 {
2761 }
2762 
2764 {
2765  return client->method;
2766 }
2767 
2769 {
2770  return client->url;
2771 }
2772 
2773 static void server_init(void)
2774 {
2779 }
2780 
2781 
2782 static void destroy_struct_server(void *p)
2783 {
2784  struct port *pp;
2785 
2786  pp = p;
2787  (void) close(pp->fd);
2788  port_remove(pp->port);
2789 }
2790 
2791 
2792 static void destroy_int_pointer(void *p)
2793 {
2794  (void) close(*(int *) p);
2795  gw_free(p);
2796 }
2797 
2798 
2799 static void server_shutdown(void)
2800 {
2802  if (server_thread_id != -1) {
2806  }
2810 }
2811 
2812 
2813 /***********************************************************************
2814  * CGI variable manipulation.
2815  */
2816 
2817 
2819 {
2820  HTTPCGIVar *v;
2821 
2823 
2824  if (args == NULL)
2825  return ;
2826 
2827  while ((v = gwlist_extract_first(args)) != NULL) {
2828  octstr_destroy(v->name);
2829  octstr_destroy(v->value);
2830  gw_free(v);
2831  }
2832  gwlist_destroy(args, NULL);
2833 }
2834 
2835 
2837 {
2838  int i;
2839  HTTPCGIVar *v;
2840 
2842  gw_assert(list != NULL);
2843  gw_assert(name != NULL);
2844 
2845  for (i = 0; i < gwlist_len(list); ++i) {
2846  v = gwlist_get(list, i);
2847  if (octstr_str_compare(v->name, name) == 0)
2848  return v->value;
2849  }
2850  return NULL;
2851 }
2852 
2853 
2854 /***********************************************************************
2855  * Header manipulation.
2856  */
2857 
2858 
2859 static int header_is_called(Octstr *header, char *name)
2860 {
2861  long colon;
2862 
2863  colon = octstr_search_char(header, ':', 0);
2864  if (colon == -1)
2865  return 0;
2866  if ((long) strlen(name) != colon)
2867  return 0;
2868  return strncasecmp(octstr_get_cstr(header), name, colon) == 0;
2869 }
2870 
2871 
2873 {
2875  return gwlist_create();
2876 }
2877 
2878 
2880 {
2883 }
2884 
2885 
2886 void http_header_add(List *headers, char *name, char *contents)
2887 {
2889  gw_assert(headers != NULL);
2890  gw_assert(name != NULL);
2891  gw_assert(contents != NULL);
2892 
2893  gwlist_append(headers, octstr_format("%s: %s", name, contents));
2894 }
2895 
2896 
2897 /*
2898  * Given an headers list and a position, returns its header name and value,
2899  * or (X-Unknown, header) if it doesn't exist or if it's malformed - missing
2900  * ":" for example
2901  */
2902 void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
2903 {
2904  Octstr *os;
2905  long colon;
2906 
2908  gw_assert(i >= 0);
2909  gw_assert(name != NULL);
2910  gw_assert(value != NULL);
2911 
2912  os = gwlist_get(headers, i);
2913  if (os == NULL)
2914  colon = -1;
2915  else
2916  colon = octstr_search_char(os, ':', 0);
2917  if (colon == -1) {
2918  error(0, "HTTP: Header does not contain a colon. BAD.");
2919  *name = octstr_create("X-Unknown");
2920  *value = octstr_duplicate(os);
2921  } else {
2922  *name = octstr_copy(os, 0, colon);
2923  *value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1);
2924  octstr_strip_blanks(*value);
2925  }
2926 }
2927 
2928 /*
2929  * Given an headers list and a name, returns its value or NULL if it
2930  * doesn't exist
2931  */
2933 {
2934  Octstr *value;
2935  long i;
2936  Octstr *os;
2937  long colon;
2938  Octstr *current_name;
2939 
2941  gw_assert(name);
2942 
2943  value = NULL;
2944  i = 0;
2945  while (i < gwlist_len(headers)) {
2946  os = gwlist_get(headers, i);
2947  if (os == NULL)
2948  colon = -1;
2949  else
2950  colon = octstr_search_char(os, ':', 0);
2951  if (colon == -1) {
2952  return NULL;
2953  } else {
2954  current_name = octstr_copy(os, 0, colon);
2955  }
2956  if (octstr_case_compare(current_name, name) == 0) {
2957  value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1);
2958  octstr_strip_blanks(value);
2959  octstr_destroy(current_name);
2960  return value;
2961  }
2962  octstr_destroy(current_name);
2963  ++i;
2964  }
2965 
2966  return NULL;
2967 }
2968 
2970 {
2971  List *new;
2972  long i, len;
2973 
2975 
2976  if (headers == NULL)
2977  return NULL;
2978 
2979  new = http_create_empty_headers();
2980  len = gwlist_len(headers);
2981  for (i = 0; i < len; ++i)
2982  gwlist_append(new, octstr_duplicate(gwlist_get(headers, i)));
2983  return new;
2984 }
2985 
2986 
2987 #define MAX_HEADER_LENGTH 256
2988 /*
2989  * Aggregate header in one (or more) lines with several parameters separated
2990  * by commas, instead of one header per parameter
2991  */
2992 void http_header_pack(List *headers)
2993 {
2994  Octstr *name, *value;
2995  Octstr *name2, *value2;
2996  long i, j;
2997 
2999  gw_assert(headers != NULL);
3000 
3001  /*
3002  * For each header, search forward headers for similar ones and if possible,
3003  * add it to current header and delete it
3004  */
3005  for(i = 0; i < gwlist_len(headers); i++) {
3006  http_header_get(headers, i, &name, &value);
3007  /* debug("http_header_pack", 0, "HTTP_HEADER_PACK: Processing header %d. [%s: %s]",
3008  i, octstr_get_cstr(name), octstr_get_cstr(value)); */
3009 
3010  for(j=i+1; j < gwlist_len(headers); j++) {
3011  http_header_get(headers, j, &name2, &value2);
3012 
3013  if(octstr_case_compare(name, name2) == 0) {
3014  if(octstr_len(value) + 2 + octstr_len(value2) > MAX_HEADER_LENGTH) {
3015  octstr_destroy(name2);
3016  octstr_destroy(value2);
3017  break;
3018  } else {
3019  Octstr *header;
3020 
3021  /* Delete old header */
3022  header = gwlist_get(headers, i);
3023  octstr_destroy(header);
3024  gwlist_delete(headers, i, 1);
3025 
3026  /* Adds comma and new value to old header value */
3027  octstr_append(value, octstr_imm(", "));
3028  octstr_append(value, value2);
3029  /* Creates a new header */
3030  header = octstr_create("");
3031  octstr_append(header, name);
3032  octstr_append(header, octstr_imm(": "));
3033  octstr_append(header, value);
3034  gwlist_insert(headers, i, header);
3035 
3036  /* Delete this header */
3037  header = gwlist_get(headers, j);
3038  octstr_destroy(header);
3039  gwlist_delete(headers, j, 1);
3040  j--;
3041  }
3042  }
3043  octstr_destroy(name2);
3044  octstr_destroy(value2);
3045  }
3047  octstr_destroy(value);
3048  }
3049 }
3050 
3051 
3053 {
3054  Octstr *header;
3055  long i;
3056 
3058  gw_assert(to != NULL);
3059  gw_assert(from != NULL);
3060 
3061  for (i = 0; i < gwlist_len(from); ++i) {
3062  header = gwlist_get(from, i);
3063  gwlist_append(to, octstr_duplicate(header));
3064  }
3065 }
3066 
3067 
3068 void http_header_combine(List *old_headers, List *new_headers)
3069 {
3070  long i;
3071  Octstr *name;
3072  Octstr *value;
3073 
3074  /*
3075  * Avoid doing this scan if old_headers is empty anyway.
3076  */
3077  if (gwlist_len(old_headers) > 0) {
3078  for (i = 0; i < gwlist_len(new_headers); i++) {
3079  http_header_get(new_headers, i, &name, &value);
3082  octstr_destroy(value);
3083  }
3084  }
3085 
3086  http_append_headers(old_headers, new_headers);
3087 }
3088 
3089 
3090 Octstr *http_header_find_first_real(List *headers, char *name, const char *file, long line,
3091  const char *func)
3092 {
3093  long i, name_len;
3094  Octstr *h, *value;
3095 
3097  gw_assert(headers != NULL);
3098  gw_assert(name != NULL);
3099 
3100  name_len = strlen(name);
3101 
3102  for (i = 0; i < gwlist_len(headers); ++i) {
3103  h = gwlist_get(headers, i);
3104  if (header_is_called(h, name)) {
3105  value = octstr_copy_real(h, name_len + 1, octstr_len(h),
3106  file, line, func);
3107  octstr_strip_blanks(value);
3108  return value;
3109  }
3110  }
3111  return NULL;
3112 }
3113 
3114 
3116 {
3117  List *list;
3118  long i;
3119  Octstr *h;
3120 
3122  gw_assert(headers != NULL);
3123  gw_assert(name != NULL);
3124 
3125  list = gwlist_create();
3126  for (i = 0; i < gwlist_len(headers); ++i) {
3127  h = gwlist_get(headers, i);
3128  if (header_is_called(h, name))
3129  gwlist_append(list, octstr_duplicate(h));
3130  }
3131  return list;
3132 }
3133 
3134 
3135 long http_header_remove_all(List *headers, char *name)
3136 {
3137  long i;
3138  Octstr *h;
3139  long count;
3140 
3142  gw_assert(headers != NULL);
3143  gw_assert(name != NULL);
3144 
3145  i = 0;
3146  count = 0;
3147  while (i < gwlist_len(headers)) {
3148  h = gwlist_get(headers, i);
3149  if (header_is_called(h, name)) {
3150  gwlist_delete(headers, i, 1);
3151  octstr_destroy(h);
3152  count++;
3153  } else
3154  i++;
3155  }
3156 
3157  return count;
3158 }
3159 
3160 
3162 {
3163  Octstr *h;
3164  List *connection_headers;
3165 
3167  gw_assert(headers != NULL);
3168 
3169  /*
3170  * The hop-by-hop headers are a standard list, plus those named
3171  * in the Connection header(s).
3172  */
3173 
3174  connection_headers = http_header_find_all(headers, "Connection");
3175  while ((h = gwlist_consume(connection_headers))) {
3176  List *hop_headers;
3177  Octstr *e;
3178 
3179  octstr_delete(h, 0, strlen("Connection:"));
3180  hop_headers = http_header_split_value(h);
3181  octstr_destroy(h);
3182 
3183  while ((e = gwlist_consume(hop_headers))) {
3185  octstr_destroy(e);
3186  }
3187 
3188  gwlist_destroy(hop_headers, NULL);
3189  }
3190  gwlist_destroy(connection_headers, NULL);
3191 
3192  http_header_remove_all(headers, "Connection");
3193  http_header_remove_all(headers, "Keep-Alive");
3194  http_header_remove_all(headers, "Proxy-Authenticate");
3195  http_header_remove_all(headers, "Proxy-Authorization");
3196  http_header_remove_all(headers, "TE");
3197  http_header_remove_all(headers, "Trailers");
3198  http_header_remove_all(headers, "Transfer-Encoding");
3199  http_header_remove_all(headers, "Upgrade");
3200 }
3201 
3202 
3204  Octstr *new_body, Octstr *new_type)
3205 {
3206  Octstr *new_length = NULL;
3207 
3208  /* Remove all headers that no longer apply to the new body. */
3209  http_header_remove_all(headers, "Content-Length");
3210  http_header_remove_all(headers, "Content-MD5");
3211  http_header_remove_all(headers, "Content-Type");
3212 
3213  /* Add headers that we need to describe the new body. */
3214  new_length = octstr_format("%ld", octstr_len(new_body));
3215  http_header_add(headers, "Content-Length", octstr_get_cstr(new_length));
3216  if(octstr_len(new_type))
3217  http_header_add(headers, "Content-Type", octstr_get_cstr(new_type));
3218 
3219  /* Perhaps we should add Warning: 214 "Transformation applied" too? */
3220 
3221  octstr_destroy(new_length);
3222 }
3223 
3224 
3226  Octstr **charset)
3227 {
3228  Octstr *h;
3229  long semicolon, equals, len;
3230 
3232  gw_assert(headers != NULL);
3233  gw_assert(type != NULL);
3234  gw_assert(charset != NULL);
3235 
3236  h = http_header_find_first(headers, "Content-Type");
3237  if (h == NULL) {
3238  *type = octstr_create("application/octet-stream");
3239  *charset = octstr_create("");
3240  } else {
3242  semicolon = octstr_search_char(h, ';', 0);
3243  if (semicolon == -1) {
3244  *type = h;
3245  *charset = octstr_create("");
3246  } else {
3247  *charset = octstr_duplicate(h);
3248  octstr_delete(*charset, 0, semicolon + 1);
3250  equals = octstr_search_char(*charset, '=', 0);
3251  if (equals == -1)
3252  octstr_truncate(*charset, 0);
3253  else {
3254  octstr_delete(*charset, 0, equals + 1);
3255  if (octstr_get_char(*charset, 0) == '"')
3256  octstr_delete(*charset, 0, 1);
3257  len = octstr_len(*charset);
3258  if (octstr_get_char(*charset, len - 1) == '"')
3259  octstr_truncate(*charset, len - 1);
3260  }
3261 
3262  octstr_truncate(h, semicolon);
3264  *type = h;
3265  }
3266 
3267  /*
3268  * According to HTTP/1.1 (RFC 2616, section 3.7.1) we have to ensure
3269  * to return charset 'iso-8859-1' in case of no given encoding and
3270  * content-type is a 'text' subtype.
3271  */
3272  if (octstr_len(*charset) == 0 &&
3273  octstr_ncompare(*type, octstr_imm("text"), 4) == 0)
3274  octstr_append_cstr(*charset, "ISO-8859-1");
3275  }
3276 }
3277 
3278 
3279 static void http_header_add_element(List *list, Octstr *value,
3280  long start, long end)
3281 {
3282  Octstr *element;
3283 
3284  element = octstr_copy(value, start, end - start);
3286  if (octstr_len(element) == 0)
3288  else
3289  gwlist_append(list, element);
3290 }
3291 
3292 
3294 {
3295  long len;
3296  long pos;
3297  int c;
3298 
3299  if (octstr_get_char(header, start) != '"')
3300  return -1;
3301 
3302  len = octstr_len(header);
3303  for (pos = start + 1; pos < len; pos++) {
3304  c = octstr_get_char(header, pos);
3305  if (c == '\\') /* quoted-pair */
3306  pos++;
3307  else if (c == '"')
3308  return pos - start + 1;
3309  }
3310 
3311  warning(0, "Header contains unterminated quoted-string:");
3312  warning(0, "%s", octstr_get_cstr(header));
3313  return len - start;
3314 }
3315 
3316 
3318 {
3319  long start; /* start of current element */
3320  long pos;
3321  long len;
3322  List *result;
3323  int c;
3324 
3325  /*
3326  * According to RFC2616 section 4.2, a field-value is either *TEXT
3327  * (the caller is responsible for not feeding us one of those) or
3328  * combinations of token, separators, and quoted-string. We're
3329  * looking for commas which are separators, and have to skip
3330  * commas in quoted-strings.
3331  */
3332 
3333  result = gwlist_create();
3334  len = octstr_len(value);
3335  start = 0;
3336  for (pos = 0; pos < len; pos++) {
3337  c = octstr_get_char(value, pos);
3338  if (c == ',') {
3339  http_header_add_element(result, value, start, pos);
3340  start = pos + 1;
3341  } else if (c == '"') {
3342  pos += http_header_quoted_string_len(value, pos);
3343  pos--; /* compensate for the loop's pos++ */
3344  }
3345  }
3346  http_header_add_element(result, value, start, len);
3347  return result;
3348 }
3349 
3350 
3352 {
3353  List *result;
3354  Octstr *auth_scheme;
3355  Octstr *element;
3356  long i;
3357 
3358  /*
3359  * According to RFC2617, both "challenge" and "credentials"
3360  * consist of an auth-scheme followed by a list of auth-param.
3361  * Since we have to parse a list of challenges or credentials,
3362  * we have to look for auth-scheme to signal the start of
3363  * a new element. (We can't just split on commas because
3364  * they are also used to separate the auth-params.)
3365  *
3366  * An auth-scheme is a single token, while an auth-param is
3367  * always a key=value pair. So we can recognize an auth-scheme
3368  * as a token that is not followed by a '=' sign.
3369  *
3370  * Simple approach: First split at all commas, then recombine
3371  * the elements that belong to the same challenge or credential.
3372  * This is somewhat expensive but saves programmer thinking time.
3373  *
3374  * Richard Braakman
3375  */
3376 
3377  result = http_header_split_value(value);
3378  if (gwlist_len(result) == 0)
3379  return result;
3380 
3381  auth_scheme = gwlist_get(result, 0);
3382  i = 1;
3383  while (i < gwlist_len(result)) {
3384  int c;
3385  long pos;
3386 
3387  element = gwlist_get(result, i);
3388 
3389  /*
3390  * If the element starts with: token '='
3391  * then it's just an auth_param; append it to the current
3392  * auth_scheme. If it starts with: token token '='
3393  * then it's the start of a new auth scheme.
3394  *
3395  * To make the scan easier, we consider anything other
3396  * than whitespace or '=' to be part of a token.
3397  */
3398 
3399  /* Skip first token */
3400  for (pos = 0; pos < octstr_len(element); pos++) {
3401  c = octstr_get_char(element, pos);
3402  if (isspace(c) || c == '=')
3403  break;
3404  }
3405 
3406  /* Skip whitespace, if any */
3407  while (isspace(octstr_get_char(element, pos)))
3408  pos++;
3409 
3410  if (octstr_get_char(element, pos) == '=') {
3411  octstr_append_char(auth_scheme, ';');
3412  octstr_append(auth_scheme, element);
3413  gwlist_delete(result, i, 1);
3415  } else {
3416  char semicolon = ';';
3417  octstr_insert_data(element, pos, &semicolon, 1);
3418  auth_scheme = element;
3419  i++;
3420  }
3421  }
3422 
3423  return result;
3424 }
3425 
3426 
3427 void http_header_dump(List *headers)
3428 {
3429  long i;
3430 
3432 
3433  debug("gwlib.http", 0, "Dumping HTTP headers:");
3434  for (i = 0; headers != NULL && i < gwlist_len(headers); ++i)
3435  octstr_dump(gwlist_get(headers, i), 1);
3436  debug("gwlib.http", 0, "End of dump.");
3437 }
3438 
3439 
3440 void http_cgivar_dump(List *cgiargs)
3441 {
3442  HTTPCGIVar *v;
3443  long i, len;
3444 
3446 
3447  len = gwlist_len(cgiargs);
3448 
3449  debug("gwlib.http", 0, "Dumping %ld cgi variables:", len);
3450  for (i = 0; i < len; i++) {
3451  v = gwlist_get(cgiargs, i);
3452  octstr_dump(v->name, 0);
3453  octstr_dump(v->value, 0);
3454  }
3455  debug("gwlib.http", 0, "End of dump.");
3456 }
3457 
3458 
3459 void http_cgivar_dump_into(List *cgiargs, Octstr *os)
3460 {
3461  HTTPCGIVar *v;
3462  long i;
3463 
3464  if (os == NULL)
3465  return;
3466 
3468 
3469  for (i = 0; i < gwlist_len(cgiargs); i++) {
3470  v = gwlist_get(cgiargs, i);
3471  octstr_format_append(os, "&%E=%E", v->name, v->value);
3472  }
3473 }
3474 
3475 
3476 static int http_something_accepted(List *headers, char *header_name,
3477  char *what)
3478 {
3479  int found;
3480  long i;
3481  List *accepts;
3482  Octstr *needle = octstr_create(what);
3483 
3485  gw_assert(headers != NULL);
3486  gw_assert(what != NULL);
3487 
3488  /* return all headers with this name */
3489  accepts = http_header_find_all(headers, header_name);
3490 
3491  found = 0;
3492  for (i = 0; !found && i < gwlist_len(accepts); ++i) {
3493  Octstr *header_value = gwlist_get(accepts, i);
3494  if (octstr_case_search(header_value, needle, 0) != -1)
3495  found = 1;
3496  }
3497  octstr_destroy(needle);
3498  http_destroy_headers(accepts);
3499  return found;
3500 }
3501 
3502 
3503 int http_type_accepted(List *headers, char *type)
3504 {
3505  return http_something_accepted(headers, "Accept", type);
3506 }
3507 
3508 
3509 int http_charset_accepted(List *headers, char *charset)
3510 {
3511  return http_something_accepted(headers, "Accept-Charset", charset);
3512 }
3513 
3514 
3516 {
3517  Octstr *os;
3518 
3519  if (password != NULL)
3520  os = octstr_format("%S:%S", username, password);
3521  else
3522  os = octstr_format("%S", username);
3524  octstr_strip_blanks(os);
3525  octstr_insert(os, octstr_imm("Basic "), 0);
3526  http_header_add(headers, "Authorization", octstr_get_cstr(os));
3527  octstr_destroy(os);
3528 }
3529 
3530 
3532 {
3533  long pos, len, end;
3534  int c, found = 0;
3535  Octstr *result = NULL;
3536 
3537  len = octstr_len(value);
3538  /* Find the start of the first parameter. */
3539  for (pos = 0; pos < len; pos++) {
3540  c = octstr_get_char(value, pos);
3541  if (c == ';')
3542  break;
3543  else if (c == '"')
3544  pos += http_header_quoted_string_len(value, pos) - 1;
3545  }
3546 
3547  if (pos >= len)
3548  return NULL; /* no parameters */
3549 
3550  for (pos++; pos > 0 && pos < len && found == 0; pos++) {
3551  Octstr *key = NULL;
3552  Octstr *val = NULL;
3553 
3554  end = octstr_search_char(value, '=', pos);
3555  if (end < 0)
3556  end = octstr_search_char(value, ';', pos);
3557  if (end < 0)
3558  end = octstr_len(value);
3559  key = octstr_copy(value, pos, end - pos);
3560  octstr_strip_blanks(key);
3561  pos = end;
3562 
3563  if (octstr_get_char(value, pos) == '=') {
3564  pos++;
3565  while (isspace(octstr_get_char(value, pos)))
3566  pos++;
3567  if (octstr_get_char(value, pos) == '"')
3568  end = pos + http_header_quoted_string_len(value, pos);
3569  else
3570  end = octstr_search_char(value, ';', pos);
3571  if (end < 0)
3572  end = octstr_len(value);
3573  val = octstr_copy(value, pos, end - pos);
3574  octstr_strip_blanks(val);
3575  pos = end;
3576  pos = octstr_search_char(value, ';', pos);
3577  }
3578 
3579  /* is this the pair we look for? bail out then*/
3580  if (octstr_case_compare(key, parameter) == 0) {
3581  found++;
3582  result = octstr_duplicate(val);
3583  }
3584 
3585  octstr_destroy(key);
3586  octstr_destroy(val);
3587  }
3588 
3589  return result;
3590 }
3591 
3592 
3593 /***********************************************************************
3594  * Module initialization and shutdown.
3595  */
3596 
3597 
3598 void http_init(void)
3599 {
3601 
3602 #ifdef HAVE_LIBSSL
3603  conn_init_ssl();
3604 #endif /* HAVE_LIBSSL */
3605  proxy_init();
3606  client_init();
3607  conn_pool_init();
3608  port_init();
3609  server_init();
3610 #ifdef HAVE_LIBSSL
3611  server_ssl_init();
3612 #endif /* HAVE_LIBSSL */
3613 
3614  run_status = running;
3615 }
3616 
3617 
3618 void http_shutdown(void)
3619 {
3622 
3624 
3626  client_shutdown();
3627  server_shutdown();
3628  port_shutdown();
3629  proxy_shutdown();
3630 #ifdef HAVE_LIBSSL
3631  conn_shutdown_ssl();
3632  server_shutdown_ssl();
3633 #endif /* HAVE_LIBSSL */
3634  run_status = limbo;
3635 }
3636 
3637 
3638 /*
3639  * This function relies on the HTTP_STATUS_* enum values being
3640  * chosen to fit this.
3641  */
3643 {
3644  int sclass;
3645 
3646  if (code < 100 || code >= 600)
3647  sclass = HTTP_STATUS_UNKNOWN;
3648  else
3649  sclass = code - (code % 100);
3650  return sclass;
3651 }
3652 
3653 
3655 {
3656  gw_assert(method != NULL);
3657 
3658  if (octstr_str_compare(method, "GET") == 0) {
3659  return HTTP_METHOD_GET;
3660  }
3661  else if (octstr_str_compare(method, "POST") == 0) {
3662  return HTTP_METHOD_POST;
3663  }
3664  else if (octstr_str_compare(method, "HEAD") == 0) {
3665  return HTTP_METHOD_HEAD;
3666  }
3667  else if (octstr_str_compare(method, "PUT") == 0) {
3668  return HTTP_METHOD_PUT;
3669  }
3670  else if (octstr_str_compare(method, "DELETE") == 0) {
3671  return HTTP_METHOD_DELETE;
3672  }
3673  else if (octstr_str_compare(method, "PATCH") == 0) {
3674  return HTTP_METHOD_PATCH;
3675  }
3676 
3677  return -1;
3678 }
3679 
3680 
3682 {
3684 
3685  return http_methods[method-1];
3686 }
3687 
void parse_cgivars(List *cgivars, Octstr *pairs)
Definition: http.c:2542
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
static Connection * get_connection(HTTPServer *trans)
Definition: http.c:1567
static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn)
Definition: http.c:513
Octstr * conn_read_line(Connection *conn)
Definition: conn.c:1134
char * http_method2name(int method)
Definition: http.c:3681
#define HTTP_MAX_FOLLOW
Definition: http.c:653
void error(int err, const char *fmt,...)
Definition: log.c:648
static List * active_connections
Definition: http.c:1899
void info(int err, const char *fmt,...)
Definition: log.c:672
static List * pending_requests
Definition: http.c:633
static void port_set_timeout(int port, long timeout)
Definition: http.c:2173
static void parse2trans(HTTPURLParse *p, HTTPServer *t)
Definition: http.c:1543
Definition: http.c:2014
Octstr * value
Definition: http.h:216
List * http_header_find_all(List *headers, char *name)
Definition: http.c:3115
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:2902
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
Octstr * pass
Definition: http.h:247
size_t name_len
Definition: wslexer.c:158
static HTTPClient * port_get_request(int port)
Definition: http.c:2149
Octstr * http_header_find_first_real(List *headers, char *name, const char *file, long line, const char *func)
Definition: http.c:3090
void * request_id
Definition: http.c:669
static long server_thread_id
Definition: http.c:1894
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2886
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
gw_assert(wtls_machine->packet_to_send !=NULL)
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:2758
void http_set_server_timeout(int port, long timeout)
Definition: http.c:2477
List * http_header_split_auth_value(Octstr *value)
Definition: http.c:3351
static Mutex * port_mutex
Definition: http.c:2024
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1504
static void server_init(void)
Definition: http.c:2773
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:525
Connection * conn
Definition: http.c:1872
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:351
static HTTPCaller * caller
Definition: smsbox.c:442
#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:3068
int octstr_url_decode(Octstr *ostr)
Definition: octstr.c:1746
Connection * conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host)
Definition: conn.c:501
int port
Definition: http.c:2016
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1517
int method
Definition: http.c:670
int code
Definition: smsc_cimd2.c:346
Octstr * fragment
Definition: http.h:250
Octstr * query
Definition: http.h:249
long chunked_body_chunk_len
Definition: http.c:366
void http_add_basic_auth(List *headers, Octstr *username, Octstr *password)
Definition: http.c:3515
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:122
void octstr_binary_to_base64(Octstr *ostr)
Definition: octstr.c:542
static Octstr * port_key(int port)
Definition: http.c:2051
FDSet * server_fdset
Definition: http.c:2020
void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset)
Definition: http.c:3225
static int client_is_persistent(List *headers, int use_version_1_0)
Definition: http.c:1982
Connection * conn
Definition: http.c:685
static Octstr * http_interface
Definition: http.c:123
int ssl
Definition: http.c:2017
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:3654
List * request_headers
Definition: http.c:673
long http_header_quoted_string_len(Octstr *header, long start)
Definition: http.c:3293
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1511
static int proxy_ssl
Definition: http.c:202
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1461
int fd
Definition: http.c:2015
int conn_eof(Connection *conn)
Definition: conn.c:705
int gwthread_poll(struct pollfd *fds, long numfds, double timeout)
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1346
int use_version_1_0
Definition: http.c:1882
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:1012
void gwthread_join_every(gwthread_func_t *func)
Octstr * http_request_url(HTTPClient *client)
Definition: http.c:2768
short events
Definition: gwpoll.h:86
unsigned long port
Definition: http.h:245
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:3203
FILE * file
Definition: log.c:169
static void client_init(void)
Definition: http.c:1840
static struct pid_list * found
static Octstr * our_host
Definition: radius_acct.c:86
Octstr * ip
Definition: http.c:1873
static List * new_server_sockets
Definition: http.c:1895
unsigned char * username
Definition: test_cimd2.c:99
static void client_destroy(void *client)
Definition: http.c:1932
Octstr * http_cgi_variable(List *list, char *name)
Definition: http.c:2836
static int parse_request_line(int *method, Octstr **url, int *use_version_1_0, Octstr *line)
Definition: http.c:2210
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:2081
void http_destroy_headers(List *headers)
Definition: http.c:2879
static Octstr * build_response(List *headers, Octstr *body)
Definition: http.c:1293
Octstr * host
Definition: http.h:244
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:121
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:1332
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:1760
void http_destroy_cgiargs(List *args)
Definition: http.c:2818
Octstr * body
Definition: http.c:363
void http_append_headers(List *to, List *from)
Definition: http.c:3052
static const char * http_reason_phrase(int status)
Definition: http.c:2645
unsigned char * password
Definition: test_cimd2.c:100
void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body)
Definition: http.c:2695
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
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:1051
int conn_get_connect_result(Connection *conn)
Definition: conn.c:530
int http_method(HTTPClient *client)
Definition: http.c:2763
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1303
void * dict_remove(Dict *dict, Octstr *key)
Definition: dict.c:307
static FDSet * port_get_fdset(int port)
Definition: http.c:2190
Counter * counter_create(void)
Definition: counter.c:94
Octstr * name
Definition: http.h:215
void http_close_proxy(void)
Definition: http.c:304
static void client_reset(HTTPClient *p)
Definition: http.c:1967
static void port_init(void)
Definition: http.c:2034
void * gwlist_extract_first(List *list)
Definition: list.c:305
static void server_shutdown(void)
Definition: http.c:2799
int method
Definition: http.c:1880
static HTTPClient * client_create(int port, Connection *conn, Octstr *ip)
Definition: http.c:1902
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:1552
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:2571
void http_close_port(int port)
Definition: http.c:2515
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1527
void parse_dump(HTTPURLParse *p)
Definition: http.c:1348
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:2019
List * headers
Definition: http.c:362
Octstr * username
Definition: http.c:691
void conn_destroy(Connection *conn)
Definition: conn.c:627
List * http_create_empty_headers(void)
Definition: http.c:2872
Octstr * request_body
Definition: http.c:674
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:952
static int send_request(HTTPServer *trans)
Definition: http.c:1611
void http_header_pack(List *headers)
Definition: http.c:2992
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:242
long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1102
static int proxy_port
Definition: http.c:201
int http_status_class(int code)
Definition: http.c:3642
#define http_header_find_first(headers, name)
Definition: http.h:603
List * http_header_split_value(Octstr *value)
Definition: http.c:3317
int conn_register_real(Connection *conn, FDSet *fdset, conn_callback_t callback, void *data, conn_callback_data_destroyer_t *data_destroyer)
Definition: conn.c:802
#define MAX_HEADER_LENGTH
Definition: http.c:2987
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
Octstr * http_get_header_parameter(Octstr *value, Octstr *parameter)
Definition: http.c:3531
char * name
Definition: smsc_cimd2.c:212
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:903
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:660
void http_cgivar_dump_into(List *cgiargs, Octstr *os)
Definition: http.c:3459
long conn_outbuf_len(Connection *conn)
Definition: conn.c:683
List * octstr_split_words(const Octstr *ostr)
Definition: octstr.c:1602
static List * closed_server_sockets
Definition: http.c:1896
Definition: gwpoll.h:84
static int http_something_accepted(List *headers, char *header_name, char *what)
Definition: http.c:3476
Octstr * url
Definition: http.c:1881
Octstr * hostname
Definition: fakewap.c:232
List * clients_with_requests
Definition: http.c:2018
void * http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url, List **headers, Octstr **body, int blocking)
Definition: http.c:1786
void http_remove_hop_headers(List *headers)
Definition: http.c:3161
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
static int parse_http_version(Octstr *version)
Definition: http.c:168
void http_set_interface(const Octstr *our_host)
Definition: http.c:1746
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:336
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:1667
int persistent_conn
Definition: http.c:1883
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
const char * content_type
Definition: fakewap.c:249
static void port_put_request(HTTPClient *client)
Definition: http.c:2129
enum HTTPServer::@60 state
static Octstr * proxy_hostname
Definition: http.c:200
Octstr * path
Definition: http.h:248
int http_open_port(int port, int ssl)
Definition: http.c:2509
#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:394
static void entity_destroy(HTTPEntity *ent)
Definition: http.c:445
static int keep_servers_open
Definition: http.c:1897
int http_open_port_if(int port, int ssl, Octstr *interface)
Definition: http.c:2483
body_expectation
Definition: http.c:331
static void destroy_int_pointer(void *p)
Definition: http.c:2792
void http_close_all_ports(void)
Definition: http.c:2526
Octstr * http_header_value(List *headers, Octstr *name)
Definition: http.c:2932
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
static void receive_request(Connection *conn, void *data)
Definition: http.c:2251
void dict_destroy(Dict *dict)
Definition: dict.c:215
void conn_unregister(Connection *conn)
Definition: conn.c:858
void http_init(void)
Definition: http.c:3598
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:1821
Definition: octstr.c:118
int fd
Definition: gwpoll.h:85
int conn_wait(Connection *conn, double seconds)
Definition: conn.c:904
void * gwlist_consume(List *list)
Definition: list.c:427
void http_cgivar_dump(List *cgiargs)
Definition: http.c:3440
static int http_client_timeout
Definition: http.c:91
static void write_request_thread(void *arg)
Definition: http.c:1681
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:726
static void destroy_struct_server(void *p)
Definition: http.c:2782
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:2025
int port
Definition: http.c:1871
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:973
static HTTPEntity * entity_create(enum body_expectation exp)
Definition: http.c:429
long http_header_remove_all(List *headers, char *name)
Definition: http.c:3135
int socklen_t
Definition: socket.h:73
int persistent
Definition: http.c:683
static void start_server_thread(void)
Definition: http.c:2458
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:749
HTTPCaller * http_caller_create(void)
Definition: http.c:897
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2507
int http_charset_accepted(List *headers, char *charset)
Definition: http.c:3509
List * http_header_duplicate(List *headers)
Definition: http.c:2969
enum HTTPClient::@61 state
static void port_shutdown(void)
Definition: http.c:2042
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:1327
static void server_thread(void *dummy)
Definition: http.c:2344
Octstr * date_format_http(unsigned long unixtime)
Definition: date.c:89
HTTPURLParse * parse_url(Octstr *url)
Definition: http.c:1377
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:1110
static void proxy_shutdown(void)
Definition: http.c:232
int conn_error(Connection *conn)
Definition: conn.c:716
static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn)
Definition: http.c:498
Octstr * user
Definition: http.h:246
static Mutex * server_thread_lock
Definition: http.c:1892
void fdset_set_timeout(FDSet *set, long timeout)
Definition: fdset.c:547
int http_type_accepted(List *headers, char *type)
Definition: http.c:3503
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:1848
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:1751
HTTPURLParse * http_urlparse_create(void)
Definition: http.c:1313
static Octstr * url
Definition: test_xmlrpc.c:84
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
#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:3279
static int header_is_called(Octstr *header, char *name)
Definition: http.c:2859
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:415
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:1244
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1640
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:3618
HTTPCaller * caller
Definition: http.c:668
Octstr * host
Definition: http.c:686
unsigned long conn_time
Definition: http.c:1884
static int start
HTTPEntity * request
Definition: http.c:1885
void http_header_dump(List *headers)
Definition: http.c:3427
static int port_match(void *client, void *port)
Definition: http.c:2028
Octstr * password
Definition: http.c:692
static struct port * port_add(int port)
Definition: http.c:2057
Octstr * conn_read_everything(Connection *conn)
Definition: conn.c:1090
Connection * conn_wrap_fd(int fd, int ssl)
Definition: conn.c:566
static volatile sig_atomic_t server_thread_is_running
Definition: http.c:1893
Octstr * scheme
Definition: http.h:243
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:871
static void start_client_threads(void)
Definition: http.c:1723
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.