#include "asterisk.h"
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include "asterisk/cli.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/strings.h"
#include "asterisk/config.h"
#include "asterisk/stringfields.h"
#include "asterisk/ast_version.h"
#include "asterisk/manager.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | http_uri_redirect |
struct | uri_redirects |
struct | uris |
Defines | |
#define | DO_SSL |
#define | HOOK_T ssize_t |
#define | LEN_T size_t |
#define | MAX_PREFIX 80 |
Functions | |
static int | __ast_http_load (int reload) |
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 URI handlers. | |
ast_str * | ast_http_error (int status, const char *title, const char *extra_header, const char *text) |
Return an ast_str malloc()'d string containing an HTTP error message. | |
int | ast_http_init (void) |
void | ast_http_prefix (char *buf, int len) |
Return the current prefix. | |
int | ast_http_reload (void) |
int | ast_http_uri_link (struct ast_http_uri *urih) |
Register a URI handler. | |
void | ast_http_uri_unlink (struct ast_http_uri *urih) |
Unregister a URI handler. | |
void | ast_http_uri_unlink_all_with_key (const char *key) |
Unregister all handlers with matching key. | |
static const char * | ftype2mtype (const char *ftype, char *wkspace, int wkspacelen) |
static char * | handle_show_http (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static struct ast_str * | handle_uri (struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method, int *status, char **title, int *contentlength, struct ast_variable **cookies, struct ast_variable *headers, unsigned int *static_content) |
static void | http_decode (char *s) |
static void * | httpd_helper_thread (void *arg) |
static struct ast_str * | 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 *vars, struct ast_variable *headers, int *status, char **title, int *contentlength) |
static uint32_t | manid_from_vars (struct ast_variable *sid) |
static struct ast_variable * | parse_cookies (char *cookies) |
static struct ast_str * | 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 *vars, struct ast_variable *headers, int *status, char **title, int *contentlength) |
Variables | |
static struct ast_cli_entry | cli_http [] |
static int | enablestatic |
static struct ast_tcptls_session_args | http_desc |
static struct ast_tls_config | http_tls_cfg |
static struct ast_tcptls_session_args | https_desc |
struct { | |
const char * ext | |
const char * mtype | |
} | mimetypes [] |
Limit the kinds of files we're willing to serve up. | |
static char | prefix [MAX_PREFIX] |
static struct ast_http_uri | staticuri |
static struct ast_http_uri | statusuri |
AMI over HTTP support - AMI over the http protocol
Definition in file http.c.
#define MAX_PREFIX 80 |
static int __ast_http_load | ( | int | reload | ) | [static] |
Definition at line 848 of file http.c.
References ahp, AST_CERTFILE, ast_config_load2(), ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_true(), ast_variable_browse(), ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, ast_tls_config::enabled, enabled, hp, http_desc, http_tls_cfg, https_desc, ast_tcptls_session_args::local_address, MAX_PREFIX, ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by ast_http_init(), and ast_http_reload().
00849 { 00850 struct ast_config *cfg; 00851 struct ast_variable *v; 00852 int enabled=0; 00853 int newenablestatic=0; 00854 struct hostent *hp; 00855 struct ast_hostent ahp; 00856 char newprefix[MAX_PREFIX] = ""; 00857 int have_sslbindaddr = 0; 00858 struct http_uri_redirect *redirect; 00859 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00860 00861 if ((cfg = ast_config_load2("http.conf", "http", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { 00862 return 0; 00863 } 00864 00865 /* default values */ 00866 memset(&http_desc.local_address, 0, sizeof(http_desc.local_address)); 00867 http_desc.local_address.sin_port = htons(8088); 00868 00869 memset(&https_desc.local_address, 0, sizeof(https_desc.local_address)); 00870 https_desc.local_address.sin_port = htons(8089); 00871 00872 http_tls_cfg.enabled = 0; 00873 if (http_tls_cfg.certfile) { 00874 ast_free(http_tls_cfg.certfile); 00875 } 00876 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 00877 if (http_tls_cfg.cipher) { 00878 ast_free(http_tls_cfg.cipher); 00879 } 00880 http_tls_cfg.cipher = ast_strdup(""); 00881 00882 AST_RWLIST_WRLOCK(&uri_redirects); 00883 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) { 00884 ast_free(redirect); 00885 } 00886 AST_RWLIST_UNLOCK(&uri_redirects); 00887 00888 if (cfg) { 00889 v = ast_variable_browse(cfg, "general"); 00890 for (; v; v = v->next) { 00891 if (!strcasecmp(v->name, "enabled")) { 00892 enabled = ast_true(v->value); 00893 } else if (!strcasecmp(v->name, "sslenable")) { 00894 http_tls_cfg.enabled = ast_true(v->value); 00895 } else if (!strcasecmp(v->name, "sslbindport")) { 00896 https_desc.local_address.sin_port = htons(atoi(v->value)); 00897 } else if (!strcasecmp(v->name, "sslcert")) { 00898 ast_free(http_tls_cfg.certfile); 00899 http_tls_cfg.certfile = ast_strdup(v->value); 00900 } else if (!strcasecmp(v->name, "sslcipher")) { 00901 ast_free(http_tls_cfg.cipher); 00902 http_tls_cfg.cipher = ast_strdup(v->value); 00903 } else if (!strcasecmp(v->name, "enablestatic")) { 00904 newenablestatic = ast_true(v->value); 00905 } else if (!strcasecmp(v->name, "bindport")) { 00906 http_desc.local_address.sin_port = htons(atoi(v->value)); 00907 } else if (!strcasecmp(v->name, "sslbindaddr")) { 00908 if ((hp = ast_gethostbyname(v->value, &ahp))) { 00909 memcpy(&https_desc.local_address.sin_addr, hp->h_addr, sizeof(https_desc.local_address.sin_addr)); 00910 have_sslbindaddr = 1; 00911 } else { 00912 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); 00913 } 00914 } else if (!strcasecmp(v->name, "bindaddr")) { 00915 if ((hp = ast_gethostbyname(v->value, &ahp))) { 00916 memcpy(&http_desc.local_address.sin_addr, hp->h_addr, sizeof(http_desc.local_address.sin_addr)); 00917 } else { 00918 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); 00919 } 00920 } else if (!strcasecmp(v->name, "prefix")) { 00921 if (!ast_strlen_zero(v->value)) { 00922 newprefix[0] = '/'; 00923 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1); 00924 } else { 00925 newprefix[0] = '\0'; 00926 } 00927 } else if (!strcasecmp(v->name, "redirect")) { 00928 add_redirect(v->value); 00929 } else { 00930 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name); 00931 } 00932 } 00933 00934 ast_config_destroy(cfg); 00935 } 00936 00937 if (!have_sslbindaddr) { 00938 https_desc.local_address.sin_addr = http_desc.local_address.sin_addr; 00939 } 00940 if (enabled) { 00941 http_desc.local_address.sin_family = https_desc.local_address.sin_family = AF_INET; 00942 } 00943 if (strcmp(prefix, newprefix)) { 00944 ast_copy_string(prefix, newprefix, sizeof(prefix)); 00945 } 00946 enablestatic = newenablestatic; 00947 ast_tcptls_server_start(&http_desc); 00948 if (ast_ssl_setup(https_desc.tls_cfg)) { 00949 ast_tcptls_server_start(&https_desc); 00950 } 00951 00952 return 0; 00953 }
static void add_redirect | ( | const char * | value | ) | [static] |
Add a new URI redirect The entries in the redirect list are sorted by length, just like the list of URI handlers.
Definition at line 793 of file http.c.
References ast_calloc, ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_FIRST, AST_RWLIST_INSERT_AFTER, AST_RWLIST_INSERT_HEAD, AST_RWLIST_INSERT_TAIL, AST_RWLIST_NEXT, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_skip_blanks(), ast_strdupa, http_uri_redirect::dest, http_uri_redirect::entry, LOG_WARNING, strsep(), and http_uri_redirect::target.
00794 { 00795 char *target, *dest; 00796 struct http_uri_redirect *redirect, *cur; 00797 unsigned int target_len; 00798 unsigned int total_len; 00799 00800 dest = ast_strdupa(value); 00801 dest = ast_skip_blanks(dest); 00802 target = strsep(&dest, " "); 00803 target = ast_skip_blanks(target); 00804 target = strsep(&target, " "); /* trim trailing whitespace */ 00805 00806 if (!dest) { 00807 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value); 00808 return; 00809 } 00810 00811 target_len = strlen(target) + 1; 00812 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1; 00813 00814 if (!(redirect = ast_calloc(1, total_len))) { 00815 return; 00816 } 00817 00818 redirect->dest = redirect->target + target_len; 00819 strcpy(redirect->target, target); 00820 strcpy(redirect->dest, dest); 00821 00822 AST_RWLIST_WRLOCK(&uri_redirects); 00823 00824 target_len--; /* So we can compare directly with strlen() */ 00825 if (AST_RWLIST_EMPTY(&uri_redirects) 00826 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len) { 00827 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry); 00828 AST_RWLIST_UNLOCK(&uri_redirects); 00829 00830 return; 00831 } 00832 00833 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) { 00834 if (AST_RWLIST_NEXT(cur, entry) 00835 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len) { 00836 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry); 00837 AST_RWLIST_UNLOCK(&uri_redirects); 00838 00839 return; 00840 } 00841 } 00842 00843 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry); 00844 00845 AST_RWLIST_UNLOCK(&uri_redirects); 00846 }
struct ast_str* ast_http_error | ( | int | status, | |
const char * | title, | |||
const char * | extra_header, | |||
const char * | text | |||
) |
Return an ast_str malloc()'d string containing an HTTP error message.
Definition at line 309 of file http.c.
References ast_str_create(), and ast_str_set().
Referenced by handle_uri(), http_post_callback(), httpd_helper_thread(), phoneprov_callback(), and static_callback().
00310 { 00311 struct ast_str *out = ast_str_create(512); 00312 00313 if (out == NULL) { 00314 return out; 00315 } 00316 00317 ast_str_set(&out, 0, 00318 "Content-type: text/html\r\n" 00319 "%s" 00320 "\r\n" 00321 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00322 "<html><head>\r\n" 00323 "<title>%d %s</title>\r\n" 00324 "</head><body>\r\n" 00325 "<h1>%s</h1>\r\n" 00326 "<p>%s</p>\r\n" 00327 "<hr />\r\n" 00328 "<address>Asterisk Server</address>\r\n" 00329 "</body></html>\r\n", 00330 (extra_header ? extra_header : ""), status, title, title, text); 00331 00332 return out; 00333 }
int ast_http_init | ( | void | ) |
Provided by http.c
Definition at line 1022 of file http.c.
References __ast_http_load(), ast_cli_register_multiple(), ast_http_uri_link(), cli_http, staticuri, and statusuri.
Referenced by main().
01023 { 01024 ast_http_uri_link(&statusuri); 01025 ast_http_uri_link(&staticuri); 01026 ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry)); 01027 01028 return __ast_http_load(0); 01029 }
void ast_http_prefix | ( | char * | buf, | |
int | len | |||
) |
Return the current prefix.
buf[out] | destination buffer for previous | |
len[in] | length of prefix to copy |
Definition at line 147 of file http.c.
References ast_copy_string().
00148 { 00149 if (buf) { 00150 ast_copy_string(buf, prefix, len); 00151 } 00152 }
int ast_http_reload | ( | void | ) |
Provided by http.c
Definition at line 1013 of file http.c.
References __ast_http_load().
01014 { 01015 return __ast_http_load(1); 01016 }
int ast_http_uri_link | ( | struct ast_http_uri * | urih | ) |
Register a URI handler.
They are sorted by length of the string, not alphabetically. Duplicate entries are not replaced, but the insertion order (using <= and not just <) makes sure that more recent insertions hide older ones. On a lookup, we just scan the list and stop at the first matching entry.
Definition at line 344 of file http.c.
References ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_FIRST, AST_RWLIST_INSERT_AFTER, AST_RWLIST_INSERT_HEAD, AST_RWLIST_INSERT_TAIL, AST_RWLIST_NEXT, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_http_uri::description, ast_http_uri::entry, len(), LOG_WARNING, ast_http_uri::supports_get, ast_http_uri::supports_post, and ast_http_uri::uri.
Referenced by __ast_http_post_load(), ast_http_init(), and load_module().
00345 { 00346 struct ast_http_uri *uri; 00347 int len = strlen(urih->uri); 00348 00349 if (!(urih->supports_get || urih->supports_post)) { 00350 ast_log(LOG_WARNING, "URI handler does not provide either GET or POST method: %s (%s)\n", urih->uri, urih->description); 00351 return -1; 00352 } 00353 00354 AST_RWLIST_WRLOCK(&uris); 00355 00356 if (AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len) { 00357 AST_RWLIST_INSERT_HEAD(&uris, urih, entry); 00358 AST_RWLIST_UNLOCK(&uris); 00359 00360 return 0; 00361 } 00362 00363 AST_RWLIST_TRAVERSE(&uris, uri, entry) { 00364 if (AST_RWLIST_NEXT(uri, entry) && 00365 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) { 00366 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry); 00367 AST_RWLIST_UNLOCK(&uris); 00368 00369 return 0; 00370 } 00371 } 00372 00373 AST_RWLIST_INSERT_TAIL(&uris, urih, entry); 00374 00375 AST_RWLIST_UNLOCK(&uris); 00376 00377 return 0; 00378 }
void ast_http_uri_unlink | ( | struct ast_http_uri * | urih | ) |
Unregister a URI handler.
Definition at line 380 of file http.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_http_uri::entry.
Referenced by unload_module().
00381 { 00382 AST_RWLIST_WRLOCK(&uris); 00383 AST_RWLIST_REMOVE(&uris, urih, entry); 00384 AST_RWLIST_UNLOCK(&uris); 00385 }
void ast_http_uri_unlink_all_with_key | ( | const char * | key | ) |
Unregister all handlers with matching key.
Definition at line 387 of file http.c.
References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_http_uri::data, ast_http_uri::dmallocd, ast_http_uri::entry, ast_http_uri::key, and ast_http_uri::mallocd.
Referenced by __ast_http_post_load(), and unload_module().
00388 { 00389 struct ast_http_uri *urih; 00390 AST_RWLIST_WRLOCK(&uris); 00391 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) { 00392 if (!strcmp(urih->key, key)) { 00393 AST_RWLIST_REMOVE_CURRENT(entry); 00394 } 00395 if (urih->dmallocd) { 00396 ast_free(urih->data); 00397 } 00398 if (urih->mallocd) { 00399 ast_free(urih); 00400 } 00401 } 00402 AST_RWLIST_TRAVERSE_SAFE_END; 00403 AST_RWLIST_UNLOCK(&uris); 00404 }
static const char* ftype2mtype | ( | const char * | ftype, | |
char * | wkspace, | |||
int | wkspacelen | |||
) | [static] |
Definition at line 118 of file http.c.
References ARRAY_LEN, ext, mimetypes, and S_OR.
Referenced by static_callback().
00119 { 00120 int x; 00121 00122 if (ftype) { 00123 for (x = 0; x < ARRAY_LEN(mimetypes); x++) { 00124 if (!strcasecmp(ftype, mimetypes[x].ext)) { 00125 return mimetypes[x].mtype; 00126 } 00127 } 00128 } 00129 00130 snprintf(wkspace, wkspacelen, "text/%s", S_OR(ftype, "plain")); 00131 00132 return wkspace; 00133 }
static char* handle_show_http | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 955 of file http.c.
References ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_http_uri::description, http_uri_redirect::dest, ast_tls_config::enabled, http_uri_redirect::entry, ast_cli_args::fd, ast_http_uri::has_subtree, http_desc, http_tls_cfg, https_desc, ast_tcptls_session_args::old_address, http_uri_redirect::target, ast_http_uri::uri, and ast_cli_entry::usage.
00956 { 00957 struct ast_http_uri *urih; 00958 struct http_uri_redirect *redirect; 00959 00960 switch (cmd) { 00961 case CLI_INIT: 00962 e->command = "http show status"; 00963 e->usage = 00964 "Usage: http show status\n" 00965 " Lists status of internal HTTP engine\n"; 00966 return NULL; 00967 case CLI_GENERATE: 00968 return NULL; 00969 } 00970 00971 if (a->argc != 3) { 00972 return CLI_SHOWUSAGE; 00973 } 00974 ast_cli(a->fd, "HTTP Server Status:\n"); 00975 ast_cli(a->fd, "Prefix: %s\n", prefix); 00976 if (!http_desc.old_address.sin_family) { 00977 ast_cli(a->fd, "Server Disabled\n\n"); 00978 } else { 00979 ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n", 00980 ast_inet_ntoa(http_desc.old_address.sin_addr), 00981 ntohs(http_desc.old_address.sin_port)); 00982 if (http_tls_cfg.enabled) { 00983 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n", 00984 ast_inet_ntoa(https_desc.old_address.sin_addr), 00985 ntohs(https_desc.old_address.sin_port)); 00986 } 00987 } 00988 00989 ast_cli(a->fd, "Enabled URI's:\n"); 00990 AST_RWLIST_RDLOCK(&uris); 00991 if (AST_RWLIST_EMPTY(&uris)) { 00992 ast_cli(a->fd, "None.\n"); 00993 } else { 00994 AST_RWLIST_TRAVERSE(&uris, urih, entry) { 00995 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : ""), urih->description); 00996 } 00997 } 00998 AST_RWLIST_UNLOCK(&uris); 00999 01000 ast_cli(a->fd, "\nEnabled Redirects:\n"); 01001 AST_RWLIST_RDLOCK(&uri_redirects); 01002 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) { 01003 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest); 01004 } 01005 if (AST_RWLIST_EMPTY(&uri_redirects)) { 01006 ast_cli(a->fd, " None.\n"); 01007 } 01008 AST_RWLIST_UNLOCK(&uri_redirects); 01009 01010 return CLI_SUCCESS; 01011 }
static struct ast_str* handle_uri | ( | struct ast_tcptls_session_instance * | ser, | |
char * | uri, | |||
enum ast_http_method | method, | |||
int * | status, | |||
char ** | title, | |||
int * | contentlength, | |||
struct ast_variable ** | cookies, | |||
struct ast_variable * | headers, | |||
unsigned int * | static_content | |||
) | [static] |
Definition at line 423 of file http.c.
References ast_debug, ast_http_error(), AST_HTTP_GET, AST_HTTP_POST, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_variable_new(), ast_variables_destroy(), astman_is_authed(), buf, ast_http_uri::callback, cleanup(), http_uri_redirect::dest, http_uri_redirect::entry, ast_http_uri::has_subtree, http_decode(), manid_from_vars(), ast_variable::next, ast_http_uri::static_content, strsep(), ast_http_uri::supports_get, ast_http_uri::supports_post, http_uri_redirect::target, ast_http_uri::uri, and var.
Referenced by httpd_helper_thread().
00426 { 00427 char *c; 00428 struct ast_str *out = NULL; 00429 char *params = uri; 00430 struct ast_http_uri *urih = NULL; 00431 int l; 00432 struct ast_variable *vars = NULL, *v, *prev = NULL; 00433 struct http_uri_redirect *redirect; 00434 int saw_method = 0; 00435 00436 /* preserve previous behavior of only support URI parameters on GET requests */ 00437 if (method == AST_HTTP_GET) { 00438 strsep(¶ms, "?"); 00439 00440 /* Extract arguments from the request and store them in variables. 00441 * Note that a request can have multiple arguments with the same 00442 * name, and we store them all in the list of variables. 00443 * It is up to the application to handle multiple values. 00444 */ 00445 if (params) { 00446 char *var, *val; 00447 00448 while ((val = strsep(¶ms, "&"))) { 00449 var = strsep(&val, "="); 00450 if (val) { 00451 http_decode(val); 00452 } else { 00453 val = ""; 00454 } 00455 http_decode(var); 00456 if ((v = ast_variable_new(var, val, ""))) { 00457 if (vars) { 00458 prev->next = v; 00459 } else { 00460 vars = v; 00461 } 00462 prev = v; 00463 } 00464 } 00465 } 00466 } 00467 00468 /* 00469 * Append the cookies to the list of variables. 00470 * This saves a pass in the cookies list, but has the side effect 00471 * that a variable might mask a cookie with the same name if the 00472 * application stops at the first match. 00473 * Note that this is the same behaviour as $_REQUEST variables in PHP. 00474 */ 00475 if (prev) { 00476 prev->next = *cookies; 00477 } else { 00478 vars = *cookies; 00479 } 00480 *cookies = NULL; 00481 00482 http_decode(uri); 00483 00484 AST_RWLIST_RDLOCK(&uri_redirects); 00485 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) { 00486 if (!strcasecmp(uri, redirect->target)) { 00487 char buf[512]; 00488 00489 snprintf(buf, sizeof(buf), "Location: %s\r\n", redirect->dest); 00490 out = ast_http_error((*status = 302), 00491 (*title = ast_strdup("Moved Temporarily")), 00492 buf, "Redirecting..."); 00493 00494 break; 00495 } 00496 } 00497 AST_RWLIST_UNLOCK(&uri_redirects); 00498 00499 if (redirect) { 00500 goto cleanup; 00501 } 00502 00503 /* We want requests to start with the (optional) prefix and '/' */ 00504 l = strlen(prefix); 00505 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') { 00506 uri += l + 1; 00507 /* scan registered uris to see if we match one. */ 00508 AST_RWLIST_RDLOCK(&uris); 00509 AST_RWLIST_TRAVERSE(&uris, urih, entry) { 00510 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l); 00511 if (!saw_method) { 00512 switch (method) { 00513 case AST_HTTP_GET: 00514 if (urih->supports_get) { 00515 saw_method = 1; 00516 } 00517 break; 00518 case AST_HTTP_POST: 00519 if (urih->supports_post) { 00520 saw_method = 1; 00521 } 00522 break; 00523 } 00524 } 00525 00526 l = strlen(urih->uri); 00527 c = uri + l; /* candidate */ 00528 00529 if (strncasecmp(urih->uri, uri, l) || /* no match */ 00530 (*c && *c != '/')) { /* substring */ 00531 continue; 00532 } 00533 00534 if (*c == '/') { 00535 c++; 00536 } 00537 00538 if (!*c || urih->has_subtree) { 00539 if (((method == AST_HTTP_GET) && urih->supports_get) || 00540 ((method == AST_HTTP_POST) && urih->supports_post)) { 00541 uri = c; 00542 00543 break; 00544 } 00545 } 00546 } 00547 00548 if (!urih) { 00549 AST_RWLIST_UNLOCK(&uris); 00550 } 00551 } 00552 00553 if (method == AST_HTTP_POST && !astman_is_authed(manid_from_vars(vars))) { 00554 out = ast_http_error((*status = 403), 00555 (*title = ast_strdup("Access Denied")), 00556 NULL, "You do not have permission to access the requested URL."); 00557 } else if (urih) { 00558 *static_content = urih->static_content; 00559 out = urih->callback(ser, urih, uri, method, vars, headers, status, title, contentlength); 00560 AST_RWLIST_UNLOCK(&uris); 00561 } else if (saw_method) { 00562 out = ast_http_error((*status = 404), 00563 (*title = ast_strdup("Not Found")), NULL, 00564 "The requested URL was not found on this server."); 00565 } else { 00566 out = ast_http_error((*status = 501), 00567 (*title = ast_strdup("Not Implemented")), NULL, 00568 "Attempt to use unimplemented / unsupported method"); 00569 } 00570 00571 cleanup: 00572 ast_variables_destroy(vars); 00573 00574 return out; 00575 }
static void http_decode | ( | char * | s | ) | [static] |
Definition at line 411 of file http.c.
References ast_uri_decode().
Referenced by handle_uri().
00412 { 00413 char *t; 00414 00415 for (t = s; *t; t++) { 00416 if (*t == '+') 00417 *t = ' '; 00418 } 00419 00420 ast_uri_decode(s); 00421 }
static void * httpd_helper_thread | ( | void * | arg | ) | [static] |
Definition at line 659 of file http.c.
References ao2_ref, ast_free, ast_get_version(), ast_http_error(), AST_HTTP_GET, AST_HTTP_POST, ast_localtime(), ast_log(), ast_skip_blanks(), ast_skip_nonblanks(), ast_strftime(), ast_strlen_zero(), ast_trim_blanks(), ast_tvnow(), ast_variable_new(), ast_variables_destroy(), buf, errno, ast_tcptls_session_instance::f, fwrite, handle_uri(), LOG_WARNING, name, ast_variable::next, parse_cookies(), status, ast_str::str, and strsep().
00660 { 00661 char buf[4096]; 00662 char cookie[4096]; 00663 struct ast_tcptls_session_instance *ser = data; 00664 struct ast_variable *vars=NULL, *headers = NULL; 00665 char *uri, *title=NULL; 00666 int status = 200, contentlength = 0; 00667 struct ast_str *out = NULL; 00668 unsigned int static_content = 0; 00669 struct ast_variable *tail = headers; 00670 00671 if (!fgets(buf, sizeof(buf), ser->f)) { 00672 goto done; 00673 } 00674 00675 uri = ast_skip_nonblanks(buf); /* Skip method */ 00676 if (*uri) { 00677 *uri++ = '\0'; 00678 } 00679 00680 uri = ast_skip_blanks(uri); /* Skip white space */ 00681 00682 if (*uri) { /* terminate at the first blank */ 00683 char *c = ast_skip_nonblanks(uri); 00684 00685 if (*c) { 00686 *c = '\0'; 00687 } 00688 } 00689 00690 /* process "Cookie: " lines */ 00691 while (fgets(cookie, sizeof(cookie), ser->f)) { 00692 /* Trim trailing characters */ 00693 ast_trim_blanks(cookie); 00694 if (ast_strlen_zero(cookie)) { 00695 break; 00696 } 00697 if (!strncasecmp(cookie, "Cookie: ", 8)) { 00698 vars = parse_cookies(cookie); 00699 } else { 00700 char *name, *val; 00701 00702 val = cookie; 00703 name = strsep(&val, ":"); 00704 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00705 continue; 00706 } 00707 ast_trim_blanks(name); 00708 val = ast_skip_blanks(val); 00709 00710 if (!headers) { 00711 headers = ast_variable_new(name, val, __FILE__); 00712 tail = headers; 00713 } else { 00714 tail->next = ast_variable_new(name, val, __FILE__); 00715 tail = tail->next; 00716 } 00717 } 00718 } 00719 00720 if (!*uri) { 00721 out = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); 00722 } else if (strcasecmp(buf, "post") && strcasecmp(buf, "get")) { 00723 out = ast_http_error(501, "Not Implemented", NULL, 00724 "Attempt to use unimplemented / unsupported method"); 00725 } else { /* try to serve it */ 00726 out = handle_uri(ser, uri, (!strcasecmp(buf, "get")) ? AST_HTTP_GET : AST_HTTP_POST, 00727 &status, &title, &contentlength, &vars, headers, &static_content); 00728 } 00729 00730 /* If they aren't mopped up already, clean up the cookies */ 00731 if (vars) { 00732 ast_variables_destroy(vars); 00733 } 00734 /* Clean up all the header information pulled as well */ 00735 if (headers) { 00736 ast_variables_destroy(headers); 00737 } 00738 00739 if (out) { 00740 struct timeval now = ast_tvnow(); 00741 char timebuf[256]; 00742 struct ast_tm tm; 00743 00744 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT")); 00745 fprintf(ser->f, 00746 "HTTP/1.1 %d %s\r\n" 00747 "Server: Asterisk/%s\r\n" 00748 "Date: %s\r\n" 00749 "Connection: close\r\n" 00750 "%s", 00751 status, title ? title : "OK", ast_get_version(), timebuf, 00752 static_content ? "" : "Cache-Control: no-cache, no-store\r\n"); 00753 /* We set the no-cache headers only for dynamic content. 00754 * If you want to make sure the static file you requested is not from cache, 00755 * append a random variable to your GET request. Ex: 'something.html?r=109987734' 00756 */ 00757 if (!contentlength) { /* opaque body ? just dump it hoping it is properly formatted */ 00758 fprintf(ser->f, "%s", out->str); 00759 } else { 00760 char *tmp = strstr(out->str, "\r\n\r\n"); 00761 00762 if (tmp) { 00763 fprintf(ser->f, "Content-length: %d\r\n", contentlength); 00764 /* first write the header, then the body */ 00765 if (fwrite(out->str, 1, (tmp + 4 - out->str), ser->f) != tmp + 4 - out->str) { 00766 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00767 } 00768 if (fwrite(tmp + 4, 1, contentlength, ser->f) != contentlength ) { 00769 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00770 } 00771 } 00772 } 00773 ast_free(out); 00774 } 00775 00776 if (title) { 00777 ast_free(title); 00778 } 00779 00780 done: 00781 fclose(ser->f); 00782 ao2_ref(ser, -1); 00783 ser = NULL; 00784 00785 return NULL; 00786 }
static struct ast_str* 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 * | vars, | |||
struct ast_variable * | headers, | |||
int * | status, | |||
char ** | title, | |||
int * | contentlength | |||
) | [static] |
Definition at line 243 of file http.c.
References ast_inet_ntoa(), ast_str_append(), ast_str_create(), ast_tls_config::enabled, http_desc, http_tls_cfg, https_desc, ast_variable::name, ast_variable::next, ast_tcptls_session_args::old_address, and ast_variable::value.
00244 { 00245 struct ast_str *out = ast_str_create(512); 00246 struct ast_variable *v; 00247 00248 if (out == NULL) { 00249 return out; 00250 } 00251 00252 ast_str_append(&out, 0, 00253 "\r\n" 00254 "<title>Asterisk HTTP Status</title>\r\n" 00255 "<body bgcolor=\"#ffffff\">\r\n" 00256 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n" 00257 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n"); 00258 ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); 00259 ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", 00260 ast_inet_ntoa(http_desc.old_address.sin_addr)); 00261 ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n", 00262 ntohs(http_desc.old_address.sin_port)); 00263 00264 if (http_tls_cfg.enabled) { 00265 ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n", 00266 ntohs(https_desc.old_address.sin_port)); 00267 } 00268 00269 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00270 00271 for (v = vars; v; v = v->next) { 00272 if (strncasecmp(v->name, "cookie_", 7)) { 00273 ast_str_append(&out, 0, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00274 } 00275 } 00276 00277 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00278 00279 for (v = vars; v; v = v->next) { 00280 if (!strncasecmp(v->name, "cookie_", 7)) { 00281 ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00282 } 00283 } 00284 00285 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"); 00286 return out; 00287 }
static uint32_t manid_from_vars | ( | struct ast_variable * | sid | ) | [static] |
Definition at line 135 of file http.c.
References ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by handle_uri(), and static_callback().
00135 { 00136 uint32_t mngid; 00137 00138 while (sid && strcmp(sid->name, "mansession_id")) 00139 sid = sid->next; 00140 00141 if (!sid || sscanf(sid->value, "%30x", &mngid) != 1) 00142 return 0; 00143 00144 return mngid; 00145 }
static struct ast_variable* parse_cookies | ( | char * | cookies | ) | [static] |
replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.
Definition at line 622 of file http.c.
References ast_log(), ast_strip(), ast_strip_quoted(), ast_strlen_zero(), ast_variable_new(), LOG_DEBUG, name, option_debug, strsep(), and var.
Referenced by httpd_helper_thread().
00623 { 00624 char *cur; 00625 struct ast_variable *vars = NULL, *var; 00626 00627 /* Skip Cookie: */ 00628 cookies += 8; 00629 00630 while ((cur = strsep(&cookies, ";"))) { 00631 char *name, *val; 00632 00633 name = val = cur; 00634 strsep(&val, "="); 00635 00636 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00637 continue; 00638 } 00639 00640 name = ast_strip(name); 00641 val = ast_strip_quoted(val, "\"", "\""); 00642 00643 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00644 continue; 00645 } 00646 00647 if (option_debug) { 00648 ast_log(LOG_DEBUG, "mmm ... cookie! Name: '%s' Value: '%s'\n", name, val); 00649 } 00650 00651 var = ast_variable_new(name, val, __FILE__); 00652 var->next = vars; 00653 vars = var; 00654 } 00655 00656 return vars; 00657 }
static struct ast_str* 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 * | vars, | |||
struct ast_variable * | headers, | |||
int * | status, | |||
char ** | title, | |||
int * | contentlength | |||
) | [static] |
Definition at line 154 of file http.c.
References ast_config_AST_DATA_DIR, ast_get_version(), ast_http_error(), ast_localtime(), ast_log(), ast_strdup, ast_strftime(), ast_strlen_zero(), ast_tvnow(), astman_is_authed(), buf, errno, ast_tcptls_session_instance::f, ftype2mtype(), fwrite, len(), LOG_WARNING, manid_from_vars(), and mtype.
00155 { 00156 char *path; 00157 char *ftype; 00158 const char *mtype; 00159 char wkspace[80]; 00160 struct stat st; 00161 int len; 00162 int fd; 00163 struct timeval now = ast_tvnow(); 00164 char buf[256]; 00165 struct ast_tm tm; 00166 00167 /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration 00168 substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */ 00169 if (!enablestatic || ast_strlen_zero(uri)) { 00170 goto out403; 00171 } 00172 00173 /* Disallow any funny filenames at all */ 00174 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) { 00175 goto out403; 00176 } 00177 00178 if (strstr(uri, "/..")) { 00179 goto out403; 00180 } 00181 00182 if ((ftype = strrchr(uri, '.'))) { 00183 ftype++; 00184 } 00185 00186 mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace)); 00187 00188 /* Cap maximum length */ 00189 if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) { 00190 goto out403; 00191 } 00192 00193 path = alloca(len); 00194 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri); 00195 if (stat(path, &st)) { 00196 goto out404; 00197 } 00198 00199 if (S_ISDIR(st.st_mode)) { 00200 goto out404; 00201 } 00202 00203 if ((fd = open(path, O_RDONLY)) < 0) { 00204 goto out403; 00205 } 00206 00207 if (strstr(path, "/private/") && !astman_is_authed(manid_from_vars(vars))) { 00208 goto out403; 00209 } 00210 00211 ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT")); 00212 fprintf(ser->f, "HTTP/1.1 200 OK\r\n" 00213 "Server: Asterisk/%s\r\n" 00214 "Date: %s\r\n" 00215 "Connection: close\r\n" 00216 "Cache-Control: private\r\n" 00217 "Content-Length: %d\r\n" 00218 "Content-type: %s\r\n\r\n", 00219 ast_get_version(), buf, (int) st.st_size, mtype); 00220 00221 while ((len = read(fd, buf, sizeof(buf))) > 0) { 00222 if (fwrite(buf, 1, len, ser->f) != len) { 00223 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00224 } 00225 } 00226 00227 close(fd); 00228 00229 return NULL; 00230 00231 out404: 00232 return ast_http_error((*status = 404), 00233 (*title = ast_strdup("Not Found")), 00234 NULL, "The requested URL was not found on this server."); 00235 00236 out403: 00237 return ast_http_error((*status = 403), 00238 (*title = ast_strdup("Access Denied")), 00239 NULL, "You do not have permission to access the requested URL."); 00240 }
struct ast_cli_entry cli_http[] [static] |
Initial value:
{ { .handler = handle_show_http , .summary = "Display HTTP server status" ,__VA_ARGS__ }, }
Definition at line 1018 of file http.c.
Referenced by ast_http_init().
int enablestatic [static] |
const char* ext |
Definition at line 97 of file http.c.
Referenced by ast_filehelper(), ast_rtp_read(), cli_console_dial(), common_exec(), console_transfer(), do_directory(), exts_compare(), ftype2mtype(), handle_cli_dialplan_save(), iax_park_thread(), misdn_call(), misdn_request(), mixmonitor_thread(), moh_scan_files(), oh323_request(), pbx_load_config(), pbx_load_users(), record_exec(), register_exten(), register_peer_exten(), sip_park_thread(), sip_request_call(), and unregister_exten().
struct ast_tcptls_session_args http_desc [static] |
we have up to two accepting threads, one for http, one for https
Definition at line 69 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct ast_tls_config http_tls_cfg [static] |
Definition at line 62 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct ast_tcptls_session_args https_desc [static] |
Definition at line 79 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct { ... } mimetypes[] [static] |
const char* mtype |
char prefix[MAX_PREFIX] [static] |
Definition at line 92 of file http.c.
Referenced by _while_exec(), ast_db_deltree(), ast_db_gettree(), ast_remotecontrol(), exec_clearhash(), handle_cli_database_show(), hashkeys_read(), read_config(), shared_read(), shared_write(), sip_show_settings(), and while_continue_exec().
struct ast_http_uri staticuri [static] |
struct ast_http_uri statusuri [static] |