Wed Jan 8 2020 09:49:48

Asterisk developer's documentation


http.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*!
20  * \file
21  * \brief http server for AMI access
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * This program implements a tiny http server
26  * and was inspired by micro-httpd by Jef Poskanzer
27  *
28  * \extref GMime http://spruce.sourceforge.net/gmime/
29  *
30  * \ref AstHTTP - AMI over the http protocol
31  */
32 
33 /*** MODULEINFO
34  <support_level>core</support_level>
35  ***/
36 
37 #include "asterisk.h"
38 
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416066 $")
40 
41 #include <time.h>
42 #include <sys/time.h>
43 #include <sys/stat.h>
44 #include <sys/signal.h>
45 #include <fcntl.h>
46 
47 #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
48 #include "asterisk/network.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/tcptls.h"
51 #include "asterisk/http.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/strings.h"
54 #include "asterisk/config.h"
55 #include "asterisk/stringfields.h"
56 #include "asterisk/ast_version.h"
57 #include "asterisk/manager.h"
58 #include "asterisk/_private.h"
59 #include "asterisk/astobj2.h"
60 
61 #define MAX_PREFIX 80
62 #define DEFAULT_SESSION_LIMIT 100
63 #define DEFAULT_SESSION_INACTIVITY 30000 /* (ms) Idle time waiting for data. */
64 
65 #define DEFAULT_HTTP_PORT 8088
66 #define DEFAULT_HTTPS_PORT 8089
67 
68 /* See http.h for more information about the SSL implementation */
69 #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
70 #define DO_SSL /* comment in/out if you want to support ssl */
71 #endif
72 
75 static int session_count = 0;
76 
78 
79 static void *httpd_helper_thread(void *arg);
80 
81 /*!
82  * we have up to two accepting threads, one for http, one for https
83  */
85  .accept_fd = -1,
86  .master = AST_PTHREADT_NULL,
87  .tls_cfg = NULL,
88  .poll_timeout = -1,
89  .name = "http server",
90  .accept_fn = ast_tcptls_server_root,
91  .worker_fn = httpd_helper_thread,
92 };
93 
95  .accept_fd = -1,
96  .master = AST_PTHREADT_NULL,
97  .tls_cfg = &http_tls_cfg,
98  .poll_timeout = -1,
99  .name = "https server",
100  .accept_fn = ast_tcptls_server_root,
101  .worker_fn = httpd_helper_thread,
102 };
103 
104 static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri); /*!< list of supported handlers */
105 
106 /* all valid URIs must be prepended by the string in prefix. */
107 static char prefix[MAX_PREFIX];
108 static int enablestatic;
109 
110 /*! \brief Limit the kinds of files we're willing to serve up */
111 static struct {
112  const char *ext;
113  const char *mtype;
114 } mimetypes[] = {
115  { "png", "image/png" },
116  { "xml", "text/xml" },
117  { "jpg", "image/jpeg" },
118  { "js", "application/x-javascript" },
119  { "wav", "audio/x-wav" },
120  { "mp3", "audio/mpeg" },
121  { "svg", "image/svg+xml" },
122  { "svgz", "image/svg+xml" },
123  { "gif", "image/gif" },
124  { "html", "text/html" },
125  { "htm", "text/html" },
126  { "css", "text/css" },
127  { "cnf", "text/plain" },
128  { "cfg", "text/plain" },
129  { "bin", "application/octet-stream" },
130  { "sbn", "application/octet-stream" },
131  { "ld", "application/octet-stream" },
132 };
133 
136  char *dest;
137  char target[0];
138 };
139 
141 
142 static const struct ast_cfhttp_methods_text {
143  enum ast_http_method method;
144  const char *text;
145 } ast_http_methods_text[] = {
146  { AST_HTTP_UNKNOWN, "UNKNOWN" },
147  { AST_HTTP_GET, "GET" },
148  { AST_HTTP_POST, "POST" },
149  { AST_HTTP_HEAD, "HEAD" },
150  { AST_HTTP_PUT, "PUT" },
151 };
152 
153 const char *ast_get_http_method(enum ast_http_method method)
154 {
155  int x;
156 
157  for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) {
158  if (ast_http_methods_text[x].method == method) {
159  return ast_http_methods_text[x].text;
160  }
161  }
162 
163  return NULL;
164 }
165 
166 const char *ast_http_ftype2mtype(const char *ftype)
167 {
168  int x;
169 
170  if (ftype) {
171  for (x = 0; x < ARRAY_LEN(mimetypes); x++) {
172  if (!strcasecmp(ftype, mimetypes[x].ext)) {
173  return mimetypes[x].mtype;
174  }
175  }
176  }
177  return NULL;
178 }
179 
180 uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
181 {
182  uint32_t mngid = 0;
183  struct ast_variable *v, *cookies;
184 
185  cookies = ast_http_get_cookies(headers);
186  for (v = cookies; v; v = v->next) {
187  if (!strcasecmp(v->name, "mansession_id")) {
188  sscanf(v->value, "%30x", &mngid);
189  break;
190  }
191  }
192  ast_variables_destroy(cookies);
193  return mngid;
194 }
195 
196 void ast_http_prefix(char *buf, int len)
197 {
198  if (buf) {
199  ast_copy_string(buf, prefix, len);
200  }
201 }
202 
204  const struct ast_http_uri *urih, const char *uri,
205  enum ast_http_method method, struct ast_variable *get_vars,
206  struct ast_variable *headers)
207 {
208  char *path;
209  const char *ftype;
210  const char *mtype;
211  char wkspace[80];
212  struct stat st;
213  int len;
214  int fd;
215  struct ast_str *http_header;
216  struct timeval tv;
217  struct ast_tm tm;
218  char timebuf[80], etag[23];
219  struct ast_variable *v;
220  int not_modified = 0;
221 
222  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
223  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
224  return -1;
225  }
226 
227  /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
228  substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
229  if (!enablestatic || ast_strlen_zero(uri)) {
230  goto out403;
231  }
232 
233  /* Disallow any funny filenames at all (checking first character only??) */
234  if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) {
235  goto out403;
236  }
237 
238  if (strstr(uri, "/..")) {
239  goto out403;
240  }
241 
242  if ((ftype = strrchr(uri, '.'))) {
243  ftype++;
244  }
245 
246  if (!(mtype = ast_http_ftype2mtype(ftype))) {
247  snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain"));
248  mtype = wkspace;
249  }
250 
251  /* Cap maximum length */
252  if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
253  goto out403;
254  }
255 
256  path = ast_alloca(len);
257  sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
258  if (stat(path, &st)) {
259  goto out404;
260  }
261 
262  if (S_ISDIR(st.st_mode)) {
263  goto out404;
264  }
265 
266  if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
267  goto out403;
268  }
269 
270  fd = open(path, O_RDONLY);
271  if (fd < 0) {
272  goto out403;
273  }
274 
275  /* make "Etag:" http header value */
276  snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
277 
278  /* make "Last-Modified:" http header value */
279  tv.tv_sec = st.st_mtime;
280  tv.tv_usec = 0;
281  ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
282 
283  /* check received "If-None-Match" request header and Etag value for file */
284  for (v = headers; v; v = v->next) {
285  if (!strcasecmp(v->name, "If-None-Match")) {
286  if (!strcasecmp(v->value, etag)) {
287  not_modified = 1;
288  }
289  break;
290  }
291  }
292 
293  if ( (http_header = ast_str_create(255)) == NULL) {
294  close(fd);
295  return -1;
296  }
297 
298  ast_str_set(&http_header, 0, "Content-type: %s\r\n"
299  "ETag: %s\r\n"
300  "Last-Modified: %s\r\n",
301  mtype,
302  etag,
303  timebuf);
304 
305  /* ast_http_send() frees http_header, so we don't need to do it before returning */
306  if (not_modified) {
307  ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
308  } else {
309  ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1); /* static content flag is set */
310  }
311  close(fd);
312  return 0;
313 
314 out404:
315  ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
316  return -1;
317 
318 out403:
319  ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
320  return -1;
321 }
322 
324  const struct ast_http_uri *urih, const char *uri,
325  enum ast_http_method method, struct ast_variable *get_vars,
326  struct ast_variable *headers)
327 {
328  struct ast_str *out;
329  struct ast_variable *v, *cookies = NULL;
330 
331  if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
332  ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
333  return -1;
334  }
335 
336  if ( (out = ast_str_create(512)) == NULL) {
337  return -1;
338  }
339 
340  ast_str_append(&out, 0,
341  "<title>Asterisk HTTP Status</title>\r\n"
342  "<body bgcolor=\"#ffffff\">\r\n"
343  "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
344  "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
345 
346  ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
347  ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
349  ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
351  if (http_tls_cfg.enabled) {
352  ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
354  }
355  ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
356  for (v = get_vars; v; v = v->next) {
357  ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
358  }
359  ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
360 
361  cookies = ast_http_get_cookies(headers);
362  for (v = cookies; v; v = v->next) {
363  ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
364  }
365  ast_variables_destroy(cookies);
366 
367  ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
368  ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
369  return 0;
370 }
371 
372 static struct ast_http_uri statusuri = {
374  .description = "Asterisk HTTP General Status",
375  .uri = "httpstatus",
376  .has_subtree = 0,
377  .data = NULL,
378  .key = __FILE__,
379 };
380 
381 static struct ast_http_uri staticuri = {
383  .description = "Asterisk HTTP Static Delivery",
384  .uri = "static",
385  .has_subtree = 1,
386  .data = NULL,
387  .key= __FILE__,
388 };
389 
390 
391 /* send http/1.1 response */
392 /* free content variable and close socket*/
394  enum ast_http_method method, int status_code, const char *status_title,
395  struct ast_str *http_header, struct ast_str *out, const int fd,
396  unsigned int static_content)
397 {
398  struct timeval now = ast_tvnow();
399  struct ast_tm tm;
400  char timebuf[80];
401  int content_length = 0;
402 
403  if (!ser || 0 == ser->f) {
404  return;
405  }
406 
407  ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
408 
409  /* calc content length */
410  if (out) {
411  content_length += ast_str_strlen(out);
412  }
413 
414  if (fd) {
415  content_length += lseek(fd, 0, SEEK_END);
416  lseek(fd, 0, SEEK_SET);
417  }
418 
419  /* send http header */
420  fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
421  "Server: Asterisk/%s\r\n"
422  "Date: %s\r\n"
423  "Connection: close\r\n"
424  "%s"
425  "Content-Length: %d\r\n"
426  "%s"
427  "\r\n",
428  status_code, status_title ? status_title : "OK",
429  ast_get_version(),
430  timebuf,
431  static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
432  content_length,
433  http_header ? ast_str_buffer(http_header) : ""
434  );
435 
436  /* send content */
437  if (method != AST_HTTP_HEAD || status_code >= 400) {
438  if (out && ast_str_strlen(out)) {
439  if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) {
440  ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
441  }
442  }
443 
444  if (fd) {
445  char buf[256];
446  int len;
447  while ((len = read(fd, buf, sizeof(buf))) > 0) {
448  if (fwrite(buf, len, 1, ser->f) != 1) {
449  ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
450  break;
451  }
452  }
453  }
454  }
455 
456  if (http_header) {
457  ast_free(http_header);
458  }
459  if (out) {
460  ast_free(out);
461  }
462 
464  return;
465 }
466 
467 /* Send http "401 Unauthorized" responce and close socket*/
468 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
469  const unsigned long nonce, const unsigned long opaque, int stale,
470  const char *text)
471 {
472  struct ast_str *http_headers = ast_str_create(128);
473  struct ast_str *out = ast_str_create(512);
474 
475  if (!http_headers || !out) {
476  ast_free(http_headers);
477  ast_free(out);
478  return;
479  }
480 
481  ast_str_set(&http_headers, 0,
482  "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
483  "Content-type: text/html\r\n",
484  realm ? realm : "Asterisk",
485  nonce,
486  opaque,
487  stale ? ", stale=true" : "");
488 
489  ast_str_set(&out, 0,
490  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
491  "<html><head>\r\n"
492  "<title>401 Unauthorized</title>\r\n"
493  "</head><body>\r\n"
494  "<h1>401 Unauthorized</h1>\r\n"
495  "<p>%s</p>\r\n"
496  "<hr />\r\n"
497  "<address>Asterisk Server</address>\r\n"
498  "</body></html>\r\n",
499  text ? text : "");
500 
501  ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
502  return;
503 }
504 
505 /* send http error response and close socket*/
506 void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
507 {
508  struct ast_str *http_headers = ast_str_create(40);
509  struct ast_str *out = ast_str_create(256);
510 
511  if (!http_headers || !out) {
512  ast_free(http_headers);
513  ast_free(out);
514  return;
515  }
516 
517  ast_str_set(&http_headers, 0, "Content-type: text/html\r\n");
518 
519  ast_str_set(&out, 0,
520  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
521  "<html><head>\r\n"
522  "<title>%d %s</title>\r\n"
523  "</head><body>\r\n"
524  "<h1>%s</h1>\r\n"
525  "<p>%s</p>\r\n"
526  "<hr />\r\n"
527  "<address>Asterisk Server</address>\r\n"
528  "</body></html>\r\n",
529  status_code, status_title, status_title, text);
530 
531  ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
532  return;
533 }
534 
535 /*! \brief
536  * Link the new uri into the list.
537  *
538  * They are sorted by length of
539  * the string, not alphabetically. Duplicate entries are not replaced,
540  * but the insertion order (using <= and not just <) makes sure that
541  * more recent insertions hide older ones.
542  * On a lookup, we just scan the list and stop at the first matching entry.
543  */
545 {
546  struct ast_http_uri *uri;
547  int len = strlen(urih->uri);
548 
550 
551  if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
554  return 0;
555  }
556 
557  AST_RWLIST_TRAVERSE(&uris, uri, entry) {
558  if (AST_RWLIST_NEXT(uri, entry) &&
559  strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
560  AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
562 
563  return 0;
564  }
565  }
566 
568 
570 
571  return 0;
572 }
573 
575 {
577  AST_RWLIST_REMOVE(&uris, urih, entry);
579 }
580 
582 {
583  struct ast_http_uri *urih;
586  if (!strcmp(urih->key, key)) {
588  if (urih->dmallocd) {
589  ast_free(urih->data);
590  }
591  if (urih->mallocd) {
592  ast_free(urih);
593  }
594  }
595  }
598 }
599 
600 /*
601  * Decode special characters in http uri.
602  * We have ast_uri_decode to handle %XX sequences, but spaces
603  * are encoded as a '+' so we need to replace them beforehand.
604  */
605 static void http_decode(char *s)
606 {
607  char *t;
608 
609  for (t = s; *t; t++) {
610  if (*t == '+') {
611  *t = ' ';
612  }
613  }
614 
615  ast_uri_decode(s);
616 }
617 
618 #define MAX_POST_CONTENT 1025
619 
620 /*
621  * get post variables from client Request Entity-Body, if content type is
622  * application/x-www-form-urlencoded
623  */
625  struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
626 {
627  int content_length = 0;
628  struct ast_variable *v, *post_vars=NULL, *prev = NULL;
629  char *buf, *var, *val;
630  int res;
631 
632  for (v = headers; v; v = v->next) {
633  if (!strcasecmp(v->name, "Content-Type")) {
634  if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
635  return NULL;
636  }
637  break;
638  }
639  }
640 
641  for (v = headers; v; v = v->next) {
642  if (!strcasecmp(v->name, "Content-Length")) {
643  content_length = atoi(v->value);
644  break;
645  }
646  }
647 
648  if (content_length <= 0) {
649  return NULL;
650  }
651 
652  if (content_length > MAX_POST_CONTENT - 1) {
653  ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
654  content_length, MAX_POST_CONTENT);
655  ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
656  return NULL;
657  }
658 
659  buf = ast_malloc(content_length + 1);
660  if (!buf) {
661  return NULL;
662  }
663 
664  res = fread(buf, 1, content_length, ser->f);
665  if (res < content_length) {
666  /* Error, distinguishable by ferror() or feof(), but neither
667  * is good. */
668  goto done;
669  }
670  buf[content_length] = '\0';
671 
672  while ((val = strsep(&buf, "&"))) {
673  var = strsep(&val, "=");
674  if (val) {
675  http_decode(val);
676  } else {
677  val = "";
678  }
679  http_decode(var);
680  if ((v = ast_variable_new(var, val, ""))) {
681  if (post_vars) {
682  prev->next = v;
683  } else {
684  post_vars = v;
685  }
686  prev = v;
687  }
688  }
689 
690 done:
691  ast_free(buf);
692  return post_vars;
693 }
694 
695 static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
696  enum ast_http_method method, struct ast_variable *headers)
697 {
698  char *c;
699  int res = -1;
700  char *params = uri;
701  struct ast_http_uri *urih = NULL;
702  int l;
703  struct ast_variable *get_vars = NULL, *v, *prev = NULL;
704  struct http_uri_redirect *redirect;
705 
706  ast_debug(2, "HTTP Request URI is %s \n", uri);
707 
708  strsep(&params, "?");
709  /* Extract arguments from the request and store them in variables. */
710  if (params) {
711  char *var, *val;
712 
713  while ((val = strsep(&params, "&"))) {
714  var = strsep(&val, "=");
715  if (val) {
716  http_decode(val);
717  } else {
718  val = "";
719  }
720  http_decode(var);
721  if ((v = ast_variable_new(var, val, ""))) {
722  if (get_vars) {
723  prev->next = v;
724  } else {
725  get_vars = v;
726  }
727  prev = v;
728  }
729  }
730  }
731  http_decode(uri);
732 
735  if (!strcasecmp(uri, redirect->target)) {
736  struct ast_str *http_header = ast_str_create(128);
737  ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
738  ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
739 
740  break;
741  }
742  }
744  if (redirect) {
745  goto cleanup;
746  }
747 
748  /* We want requests to start with the (optional) prefix and '/' */
749  l = strlen(prefix);
750  if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
751  uri += l + 1;
752  /* scan registered uris to see if we match one. */
754  AST_RWLIST_TRAVERSE(&uris, urih, entry) {
755  ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
756  l = strlen(urih->uri);
757  c = uri + l; /* candidate */
758  if (strncasecmp(urih->uri, uri, l) /* no match */
759  || (*c && *c != '/')) { /* substring */
760  continue;
761  }
762  if (*c == '/') {
763  c++;
764  }
765  if (!*c || urih->has_subtree) {
766  uri = c;
767  break;
768  }
769  }
771  }
772  if (urih) {
773  res = urih->callback(ser, urih, uri, method, get_vars, headers);
774  } else {
775  ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
776  }
777 
778 cleanup:
779  ast_variables_destroy(get_vars);
780  return res;
781 }
782 
783 #ifdef DO_SSL
784 #if defined(HAVE_FUNOPEN)
785 #define HOOK_T int
786 #define LEN_T int
787 #else
788 #define HOOK_T ssize_t
789 #define LEN_T size_t
790 #endif
791 
792 /*!
793  * replacement read/write functions for SSL support.
794  * We use wrappers rather than SSL_read/SSL_write directly so
795  * we can put in some debugging.
796  */
797 /*static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
798 {
799  int i = SSL_read(cookie, buf, len-1);
800 #if 0
801  if (i >= 0)
802  buf[i] = '\0';
803  ast_verbose("ssl read size %d returns %d <%s>\n", (int)len, i, buf);
804 #endif
805  return i;
806 }
807 
808 static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
809 {
810 #if 0
811  char *s = ast_alloca(len+1);
812  strncpy(s, buf, len);
813  s[len] = '\0';
814  ast_verbose("ssl write size %d <%s>\n", (int)len, s);
815 #endif
816  return SSL_write(cookie, buf, len);
817 }
818 
819 static int ssl_close(void *cookie)
820 {
821  close(SSL_get_fd(cookie));
822  SSL_shutdown(cookie);
823  SSL_free(cookie);
824  return 0;
825 }*/
826 #endif /* DO_SSL */
827 
828 static struct ast_variable *parse_cookies(const char *cookies)
829 {
830  char *parse = ast_strdupa(cookies);
831  char *cur;
832  struct ast_variable *vars = NULL, *var;
833 
834  while ((cur = strsep(&parse, ";"))) {
835  char *name, *val;
836 
837  name = val = cur;
838  strsep(&val, "=");
839 
840  if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
841  continue;
842  }
843 
844  name = ast_strip(name);
845  val = ast_strip_quoted(val, "\"", "\"");
846 
847  if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
848  continue;
849  }
850 
851  ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val);
852 
853  var = ast_variable_new(name, val, __FILE__);
854  var->next = vars;
855  vars = var;
856  }
857 
858  return vars;
859 }
860 
861 /* get cookie from Request headers */
863 {
864  struct ast_variable *v, *cookies = NULL;
865 
866  for (v = headers; v; v = v->next) {
867  if (!strcasecmp(v->name, "Cookie")) {
868  ast_variables_destroy(cookies);
869  cookies = parse_cookies(v->value);
870  }
871  }
872  return cookies;
873 }
874 
875 /*! Limit the number of request headers in case the sender is being ridiculous. */
876 #define MAX_HTTP_REQUEST_HEADERS 100
877 
878 static void *httpd_helper_thread(void *data)
879 {
880  char buf[4096];
881  char header_line[4096];
882  struct ast_tcptls_session_instance *ser = data;
883  struct ast_variable *headers = NULL;
884  struct ast_variable *tail = headers;
885  char *uri, *method;
886  enum ast_http_method http_method = AST_HTTP_UNKNOWN;
887  int remaining_headers;
888  int flags;
889  struct protoent *p;
890 
891  if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
892  goto done;
893  }
894 
895  /* here we set TCP_NODELAY on the socket to disable Nagle's algorithm.
896  * This is necessary to prevent delays (caused by buffering) as we
897  * write to the socket in bits and pieces. */
898  p = getprotobyname("tcp");
899  if (p) {
900  int arg = 1;
901  if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
902  ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno));
903  ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
904  }
905  } else {
906  ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n");
907  ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
908  }
909 
910  /* make sure socket is non-blocking */
911  flags = fcntl(ser->fd, F_GETFL);
912  flags |= O_NONBLOCK;
913  fcntl(ser->fd, F_SETFL, flags);
914 
915  /* We can let the stream wait for data to arrive. */
917 
919 
920  if (!fgets(buf, sizeof(buf), ser->f) || feof(ser->f)) {
921  goto done;
922  }
923 
924  /* Get method */
925  method = ast_skip_blanks(buf);
926  uri = ast_skip_nonblanks(method);
927  if (*uri) {
928  *uri++ = '\0';
929  }
930 
931  if (!strcasecmp(method,"GET")) {
932  http_method = AST_HTTP_GET;
933  } else if (!strcasecmp(method,"POST")) {
934  http_method = AST_HTTP_POST;
935  } else if (!strcasecmp(method,"HEAD")) {
936  http_method = AST_HTTP_HEAD;
937  } else if (!strcasecmp(method,"PUT")) {
938  http_method = AST_HTTP_PUT;
939  }
940 
941  uri = ast_skip_blanks(uri); /* Skip white space */
942 
943  if (*uri) { /* terminate at the first blank */
944  char *c = ast_skip_nonblanks(uri);
945 
946  if (*c) {
947  *c = '\0';
948  }
949  } else {
950  ast_http_error(ser, 400, "Bad Request", "Invalid Request");
951  goto done;
952  }
953 
954  /* process "Request Headers" lines */
955  remaining_headers = MAX_HTTP_REQUEST_HEADERS;
956  for (;;) {
957  char *name;
958  char *value;
959 
960  if (!fgets(header_line, sizeof(header_line), ser->f) || feof(ser->f)) {
961  ast_http_error(ser, 400, "Bad Request", "Timeout");
962  goto done;
963  }
964 
965  /* Trim trailing characters */
966  ast_trim_blanks(header_line);
967  if (ast_strlen_zero(header_line)) {
968  /* A blank line ends the request header section. */
969  break;
970  }
971 
972  value = header_line;
973  name = strsep(&value, ":");
974  if (!value) {
975  continue;
976  }
977 
978  value = ast_skip_blanks(value);
979  if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
980  continue;
981  }
982 
983  ast_trim_blanks(name);
984 
985  if (!remaining_headers--) {
986  /* Too many headers. */
987  ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
988  goto done;
989  }
990  if (!headers) {
991  headers = ast_variable_new(name, value, __FILE__);
992  tail = headers;
993  } else {
994  tail->next = ast_variable_new(name, value, __FILE__);
995  tail = tail->next;
996  }
997  if (!tail) {
998  /*
999  * Variable allocation failure.
1000  * Try to make some room.
1001  */
1002  ast_variables_destroy(headers);
1003  headers = NULL;
1004 
1005  ast_http_error(ser, 500, "Server Error", "Out of memory");
1006  goto done;
1007  }
1008  }
1009 
1010  handle_uri(ser, uri, http_method, headers);
1011 
1012 done:
1013  ast_atomic_fetchadd_int(&session_count, -1);
1014 
1015  /* clean up all the header information */
1016  ast_variables_destroy(headers);
1017 
1018  if (ser->f) {
1020  }
1021  ao2_ref(ser, -1);
1022  ser = NULL;
1023  return NULL;
1024 }
1025 
1026 /*!
1027  * \brief Add a new URI redirect
1028  * The entries in the redirect list are sorted by length, just like the list
1029  * of URI handlers.
1030  */
1031 static void add_redirect(const char *value)
1032 {
1033  char *target, *dest;
1034  struct http_uri_redirect *redirect, *cur;
1035  unsigned int target_len;
1036  unsigned int total_len;
1037 
1038  dest = ast_strdupa(value);
1039  dest = ast_skip_blanks(dest);
1040  target = strsep(&dest, " ");
1041  target = ast_skip_blanks(target);
1042  target = strsep(&target, " "); /* trim trailing whitespace */
1043 
1044  if (!dest) {
1045  ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
1046  return;
1047  }
1048 
1049  target_len = strlen(target) + 1;
1050  total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
1051 
1052  if (!(redirect = ast_calloc(1, total_len))) {
1053  return;
1054  }
1055  redirect->dest = redirect->target + target_len;
1056  strcpy(redirect->target, target);
1057  strcpy(redirect->dest, dest);
1058 
1060 
1061  target_len--; /* So we can compare directly with strlen() */
1063  || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
1066 
1067  return;
1068  }
1069 
1071  if (AST_RWLIST_NEXT(cur, entry)
1072  && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
1073  AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
1075  return;
1076  }
1077  }
1078 
1080 
1082 }
1083 
1084 static int __ast_http_load(int reload)
1085 {
1086  struct ast_config *cfg;
1087  struct ast_variable *v;
1088  int enabled=0;
1089  int newenablestatic=0;
1090  struct hostent *hp;
1091  struct ast_hostent ahp;
1092  char newprefix[MAX_PREFIX] = "";
1093  struct http_uri_redirect *redirect;
1094  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1095  struct sockaddr_in tmp = {0,};
1096  struct sockaddr_in tmp2 = {0,};
1097  int http_tls_was_enabled = 0;
1098 
1099  cfg = ast_config_load2("http.conf", "http", config_flags);
1101  return 0;
1102  }
1103 
1104  http_tls_was_enabled = (reload && http_tls_cfg.enabled);
1105 
1106  tmp.sin_family = AF_INET;
1107  tmp.sin_port = htons(DEFAULT_HTTP_PORT);
1108  ast_sockaddr_from_sin(&http_desc.local_address, &tmp);
1109 
1110  http_tls_cfg.enabled = 0;
1111  if (http_tls_cfg.certfile) {
1113  }
1115 
1116  if (http_tls_cfg.pvtfile) {
1118  }
1120 
1121  if (http_tls_cfg.cipher) {
1123  }
1125 
1127  while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
1128  ast_free(redirect);
1129  }
1131 
1132  ast_sockaddr_setnull(&https_desc.local_address);
1133 
1134  session_limit = DEFAULT_SESSION_LIMIT;
1135  session_inactivity = DEFAULT_SESSION_INACTIVITY;
1136 
1137  if (cfg) {
1138  v = ast_variable_browse(cfg, "general");
1139  for (; v; v = v->next) {
1140 
1141  /* read tls config options while preventing unsupported options from being set */
1142  if (strcasecmp(v->name, "tlscafile")
1143  && strcasecmp(v->name, "tlscapath")
1144  && strcasecmp(v->name, "tlscadir")
1145  && strcasecmp(v->name, "tlsverifyclient")
1146  && strcasecmp(v->name, "tlsdontverifyserver")
1147  && strcasecmp(v->name, "tlsclientmethod")
1148  && strcasecmp(v->name, "sslclientmethod")
1149  && strcasecmp(v->name, "tlscipher")
1150  && strcasecmp(v->name, "sslcipher")
1151  && !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
1152  continue;
1153  }
1154 
1155  if (!strcasecmp(v->name, "enabled")) {
1156  enabled = ast_true(v->value);
1157  } else if (!strcasecmp(v->name, "enablestatic")) {
1158  newenablestatic = ast_true(v->value);
1159  } else if (!strcasecmp(v->name, "bindport")) {
1161  atoi(v->value));
1162  } else if (!strcasecmp(v->name, "bindaddr")) {
1163  if ((hp = ast_gethostbyname(v->value, &ahp))) {
1165  &tmp);
1166  memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr));
1168  &tmp);
1169  } else {
1170  ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
1171  }
1172  } else if (!strcasecmp(v->name, "prefix")) {
1173  if (!ast_strlen_zero(v->value)) {
1174  newprefix[0] = '/';
1175  ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
1176  } else {
1177  newprefix[0] = '\0';
1178  }
1179  } else if (!strcasecmp(v->name, "redirect")) {
1180  add_redirect(v->value);
1181  } else if (!strcasecmp(v->name, "sessionlimit")) {
1183  &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
1184  ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
1185  v->name, v->value, v->lineno);
1186  }
1187  } else if (!strcasecmp(v->name, "session_inactivity")) {
1189  &session_inactivity, DEFAULT_SESSION_INACTIVITY, 1, INT_MAX)) {
1190  ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
1191  v->name, v->value, v->lineno);
1192  }
1193  } else {
1194  ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
1195  }
1196  }
1197 
1198  ast_config_destroy(cfg);
1199  }
1200  /* if the https address has not been set, default is the same as non secure http */
1201  ast_sockaddr_to_sin(&http_desc.local_address, &tmp);
1202  ast_sockaddr_to_sin(&https_desc.local_address, &tmp2);
1203  if (!tmp2.sin_addr.s_addr) {
1204  tmp2.sin_addr = tmp.sin_addr;
1205  }
1206  if (!tmp2.sin_port) {
1207  tmp2.sin_port = htons(DEFAULT_HTTPS_PORT);
1208  }
1209  ast_sockaddr_from_sin(&https_desc.local_address, &tmp2);
1210  if (!enabled) {
1211  ast_sockaddr_setnull(&http_desc.local_address);
1212  ast_sockaddr_setnull(&https_desc.local_address);
1213  }
1214  if (strcmp(prefix, newprefix)) {
1215  ast_copy_string(prefix, newprefix, sizeof(prefix));
1216  }
1217  enablestatic = newenablestatic;
1218  ast_tcptls_server_start(&http_desc);
1219  /* If https was enabled previously but now is not, then stop the service */
1220  if (http_tls_was_enabled && !http_tls_cfg.enabled) {
1221  ast_tcptls_server_stop(&https_desc);
1222  } else if (ast_ssl_setup(https_desc.tls_cfg)) {
1223  ast_tcptls_server_start(&https_desc);
1224  }
1225 
1226  return 0;
1227 }
1228 
1229 static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1230 {
1231  struct ast_http_uri *urih;
1232  struct http_uri_redirect *redirect;
1233  struct sockaddr_in tmp;
1234 
1235  switch (cmd) {
1236  case CLI_INIT:
1237  e->command = "http show status";
1238  e->usage =
1239  "Usage: http show status\n"
1240  " Lists status of internal HTTP engine\n";
1241  return NULL;
1242  case CLI_GENERATE:
1243  return NULL;
1244  }
1245 
1246  if (a->argc != 3) {
1247  return CLI_SHOWUSAGE;
1248  }
1249  ast_cli(a->fd, "HTTP Server Status:\n");
1250  ast_cli(a->fd, "Prefix: %s\n", prefix);
1251  ast_sockaddr_to_sin(&http_desc.old_address, &tmp);
1252  if (!tmp.sin_family) {
1253  ast_cli(a->fd, "Server Disabled\n\n");
1254  } else {
1255  ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n",
1256  ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port));
1257  if (http_tls_cfg.enabled) {
1258  ast_sockaddr_to_sin(&https_desc.old_address, &tmp);
1259  ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
1260  ast_inet_ntoa(tmp.sin_addr),
1261  ntohs(tmp.sin_port));
1262  }
1263  }
1264 
1265  ast_cli(a->fd, "Enabled URI's:\n");
1267  if (AST_RWLIST_EMPTY(&uris)) {
1268  ast_cli(a->fd, "None.\n");
1269  } else {
1270  AST_RWLIST_TRAVERSE(&uris, urih, entry)
1271  ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
1272  }
1274 
1275  ast_cli(a->fd, "\nEnabled Redirects:\n");
1278  ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
1280  ast_cli(a->fd, " None.\n");
1281  }
1283 
1284  return CLI_SUCCESS;
1285 }
1286 
1288 {
1289  return __ast_http_load(1);
1290 }
1291 
1292 static struct ast_cli_entry cli_http[] = {
1293  AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
1294 };
1295 
1296 static void http_shutdown(void)
1297 {
1298  struct http_uri_redirect *redirect;
1300 
1301  ast_tcptls_server_stop(&http_desc);
1302  if (http_tls_cfg.enabled) {
1303  ast_tcptls_server_stop(&https_desc);
1304  }
1308 
1311 
1313  while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
1314  ast_free(redirect);
1315  }
1317 }
1318 
1319 int ast_http_init(void)
1320 {
1325 
1326  return __ast_http_load(0);
1327 }
static char * ast_sockaddr_stringify_addr(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:240
#define DEFAULT_HTTP_PORT
Definition: http.c:65
struct http_uri_redirect::@275 entry
#define AST_RWLIST_NEXT
Definition: linkedlists.h:440
static struct ast_variable * parse_cookies(const char *cookies)
Definition: http.c:828
char * pvtfile
Definition: tcptls.h:88
#define AST_CERTFILE
Definition: tcptls.h:68
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * strsep(char **str, const char *delims)
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
Definition: http.c:506
ast_http_callback callback
Definition: http.h:95
void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a ...
Definition: tcptls.c:964
String manipulation functions.
#define ast_strdup(a)
Definition: astmm.h:109
Definition: ast_expr2.c:325
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
Definition: tcptls.c:850
#define AST_RWLIST_INSERT_AFTER
Definition: linkedlists.h:687
#define DEFAULT_HTTPS_PORT
Definition: http.c:66
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
Asterisk version information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text)
Send http &quot;401 Unauthorized&quot; response and close socket.
Definition: http.c:468
const char * ast_get_version(void)
Retrieve the Asterisk version string.
Definition: version.c:14
void ast_uri_decode(char *s)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:484
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
static struct ast_cli_entry cli_http[]
Definition: http.c:1292
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
Definition: http.c:544
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
int lineno
Definition: config.h:87
const char * ast_http_ftype2mtype(const char *ftype) attribute_pure
Return mime type based on extension.
Definition: http.c:166
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1570
#define DEFAULT_SESSION_LIMIT
Definition: http.c:62
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
static struct ast_cfhttp_methods_text ast_http_methods_text[]
static struct ast_http_uri staticuri
Definition: http.c:381
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
Definition: http.c:574
Definition: cli.h:146
Configuration File Parser.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
const char * key
Definition: http.h:104
char * dest
Definition: http.c:136
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
arguments for the accepting thread
Definition: tcptls.h:123
const char * text
Definition: http.c:144
char * text
Definition: app_queue.c:1091
uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure
Return manager id, if exist, from request headers.
Definition: http.c:180
unsigned int has_subtree
Definition: http.h:96
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
int ast_http_init(void)
Definition: http.c:1319
int value
Definition: syslog.c:39
Generic support for tcp/tls servers in Asterisk.
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
#define MAX_PREFIX
Definition: http.c:61
const char * ext
Definition: http.c:112
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: config.c:2499
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
char * ast_skip_nonblanks(const char *str)
Gets a pointer to first whitespace character in a string.
Definition: strings.h:136
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
String fields in structures.
Utility functions.
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:106
static int httpstatus_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
Definition: http.c:323
unsigned int mallocd
Definition: http.h:98
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content)
Generic function for sending http/1.1 response.
Definition: http.c:393
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:874
static char * ast_sockaddr_stringify_port(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return a port only.
Definition: netsock2.h:302
Support for Private Asterisk HTTP Servers.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1431
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int astman_is_authed(uint32_t ident)
Determinie if a manager session ident is authenticated.
Definition: manager.c:5617
const char * value
Definition: config.h:79
void * ast_tcptls_server_root(void *)
Definition: tcptls.c:693
int ast_http_reload(void)
Definition: http.c:1287
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: config.c:2805
Asterisk file paths, configured in asterisk.conf.
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:642
static int enablestatic
Definition: http.c:108
const int fd
Definition: cli.h:153
unsigned int enabled
Definition: devicestate.c:205
#define AST_PTHREADT_NULL
Definition: lock.h:65
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
#define ao2_ref(o, delta)
Definition: astobj2.h:472
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
static struct ast_tls_config http_tls_cfg
Definition: http.c:77
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
const char * name
Definition: config.h:77
void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.
Definition: tcptls.c:107
struct ast_tcptls_stream * stream_cookie
Definition: tcptls.h:218
static struct ast_tcptls_session_args http_desc
Definition: http.c:84
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
Wrapper for network related headers, masking differences between various operating systems...
static void * httpd_helper_thread(void *arg)
Definition: http.c:878
const char * ast_config_AST_DATA_DIR
Definition: asterisk.c:262
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static int reload(void)
Definition: app_amd.c:497
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
static int __ast_http_load(int reload)
Definition: http.c:1084
static void add_redirect(const char *value)
Add a new URI redirect The entries in the redirect list are sorted by length, just like the list of U...
Definition: http.c:1031
static int session_limit
Definition: http.c:73
#define LOG_ERROR
Definition: logger.h:155
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
const char * mtype
Definition: http.c:113
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:422
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * description
Definition: http.h:93
static struct @274 mimetypes[]
Limit the kinds of files we&#39;re willing to serve up.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:122
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout)
Set the TCP/TLS stream inactivity timeout timer.
Definition: tcptls.c:91
static void http_shutdown(void)
Definition: http.c:1296
int errno
char target[0]
Definition: http.c:137
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
static const char name[]
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
#define MAX_POST_CONTENT
Definition: http.c:618
static struct ast_http_uri statusuri
Definition: http.c:372
static int session_inactivity
Definition: http.c:74
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
Prototypes for public functions only of internal interest,.
const char * ast_get_http_method(enum ast_http_method method) attribute_pure
Return http method name string.
Definition: http.c:153
struct ast_sockaddr old_address
Definition: tcptls.h:125
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2351
#define DEFAULT_SESSION_INACTIVITY
Definition: http.c:63
static int session_count
Definition: http.c:75
static void * cleanup(void *unused)
Definition: pbx_realtime.c:125
Structure used to handle boolean flags.
Definition: utils.h:200
char * certfile
Definition: tcptls.h:87
const char * usage
Definition: cli.h:171
static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method, struct ast_variable *headers)
Definition: http.c:695
#define CLI_SUCCESS
Definition: cli.h:43
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:726
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: utils.c:195
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
Closes a tcptls session instance&#39;s file and/or file descriptor. The tcptls_session will be set to NUL...
Definition: tcptls.c:1033
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
Definition of a URI handler.
Definition: http.h:91
static char * handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: http.c:1229
void ast_http_prefix(char *buf, int len)
Return the current prefix.
Definition: http.c:196
static int static_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
Definition: http.c:203
struct ast_variable * ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlenco...
Definition: http.c:624
int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
Used to parse conf files containing tls/ssl options.
Definition: tcptls.c:1072
void ast_http_uri_unlink_all_with_key(const char *key)
Unregister all handlers with matching key.
Definition: http.c:581
unsigned int dmallocd
Definition: http.h:100
static void http_decode(char *s)
Definition: http.c:605
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:870
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:629
#define MAX_HTTP_REQUEST_HEADERS
Definition: http.c:876
struct ast_variable * next
Definition: config.h:82
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
Definition: tcptls.c:1058
struct ast_tls_config * tls_cfg
Definition: tcptls.h:128
Definition: http.c:104
const char * uri
Definition: http.h:94
struct ast_sockaddr local_address
Definition: tcptls.h:124
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
ast_http_method
HTTP Request methods known by Asterisk.
Definition: http.h:56
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422
#define ast_malloc(a)
Definition: astmm.h:91
static struct hostent * hp
Definition: chan_skinny.c:1048
static struct ast_tcptls_session_args https_desc
Definition: http.c:94
char * cipher
Definition: tcptls.h:89
void * data
Definition: http.h:102
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
struct ast_variable * ast_http_get_cookies(struct ast_variable *headers)
Get cookie from Request headers.
Definition: http.c:862
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
static char prefix[MAX_PREFIX]
Definition: http.c:107
int enabled
Definition: tcptls.h:86