#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.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"

Go to the source code of this file.
Data Structures | |
| struct | http_uri_redirect |
| struct | uri_redirects |
| struct | uris |
Defines | |
| #define | MAX_PREFIX 80 |
Functions | |
| static int | __ast_http_load (int reload) |
| static void | __fini_uri_redirects (void) |
| static void | __fini_uris (void) |
| static void | __init_uri_redirects (void) |
| static void | __init_uris (void) |
| 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. | |
| 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. | |
| int | ast_http_init (void) |
| int | ast_http_reload (void) |
| int | ast_http_uri_link (struct ast_http_uri *urih) |
| Link the new uri into the list. | |
| void | ast_http_uri_unlink (struct ast_http_uri *urih) |
| Destroy an HTTP server. | |
| 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, int *status, char **title, int *contentlength, struct ast_variable **cookies, 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 char *uri, struct ast_variable *vars, 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 char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength) |
Variables | |
| static struct ast_cli_entry | cli_http [] |
| static int | enablestatic |
| static struct server_args | http_desc |
| static struct ast_tls_config | http_tls_cfg |
| static struct server_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 |
This program implements a tiny http server and was inspired by micro-httpd by Jef Poskanzer
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 1003 of file http.c.
References add_redirect(), AST_CERTFILE, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_gethostbyname(), ast_log(), AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_true(), ast_variable_browse(), ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, ast_tls_config::enabled, enabled, enablestatic, hp, http_tls_cfg, LOG_WARNING, MAX_PREFIX, ast_variable::name, ast_variable::next, prefix, server_args::sin, server_args::tls_cfg, and ast_variable::value.
Referenced by ast_http_init(), and ast_http_reload().
01004 { 01005 struct ast_config *cfg; 01006 struct ast_variable *v; 01007 int enabled=0; 01008 int newenablestatic=0; 01009 struct hostent *hp; 01010 struct ast_hostent ahp; 01011 char newprefix[MAX_PREFIX] = ""; 01012 int have_sslbindaddr = 0; 01013 struct http_uri_redirect *redirect; 01014 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01015 01016 if ((cfg = ast_config_load("http.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) 01017 return 0; 01018 01019 /* default values */ 01020 memset(&http_desc.sin, 0, sizeof(http_desc.sin)); 01021 http_desc.sin.sin_port = htons(8088); 01022 01023 memset(&https_desc.sin, 0, sizeof(https_desc.sin)); 01024 https_desc.sin.sin_port = htons(8089); 01025 01026 http_tls_cfg.enabled = 0; 01027 if (http_tls_cfg.certfile) 01028 ast_free(http_tls_cfg.certfile); 01029 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 01030 if (http_tls_cfg.cipher) 01031 ast_free(http_tls_cfg.cipher); 01032 http_tls_cfg.cipher = ast_strdup(""); 01033 01034 AST_RWLIST_WRLOCK(&uri_redirects); 01035 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) 01036 ast_free(redirect); 01037 AST_RWLIST_UNLOCK(&uri_redirects); 01038 01039 #ifdef ENABLE_UPLOADS 01040 destroy_post_mappings(); 01041 #endif /* ENABLE_UPLOADS */ 01042 01043 if (cfg) { 01044 v = ast_variable_browse(cfg, "general"); 01045 for (; v; v = v->next) { 01046 if (!strcasecmp(v->name, "enabled")) 01047 enabled = ast_true(v->value); 01048 else if (!strcasecmp(v->name, "sslenable")) 01049 http_tls_cfg.enabled = ast_true(v->value); 01050 else if (!strcasecmp(v->name, "sslbindport")) 01051 https_desc.sin.sin_port = htons(atoi(v->value)); 01052 else if (!strcasecmp(v->name, "sslcert")) { 01053 ast_free(http_tls_cfg.certfile); 01054 http_tls_cfg.certfile = ast_strdup(v->value); 01055 } else if (!strcasecmp(v->name, "sslcipher")) { 01056 ast_free(http_tls_cfg.cipher); 01057 http_tls_cfg.cipher = ast_strdup(v->value); 01058 } 01059 else if (!strcasecmp(v->name, "enablestatic")) 01060 newenablestatic = ast_true(v->value); 01061 else if (!strcasecmp(v->name, "bindport")) 01062 http_desc.sin.sin_port = htons(atoi(v->value)); 01063 else if (!strcasecmp(v->name, "sslbindaddr")) { 01064 if ((hp = ast_gethostbyname(v->value, &ahp))) { 01065 memcpy(&https_desc.sin.sin_addr, hp->h_addr, sizeof(https_desc.sin.sin_addr)); 01066 have_sslbindaddr = 1; 01067 } else { 01068 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); 01069 } 01070 } else if (!strcasecmp(v->name, "bindaddr")) { 01071 if ((hp = ast_gethostbyname(v->value, &ahp))) { 01072 memcpy(&http_desc.sin.sin_addr, hp->h_addr, sizeof(http_desc.sin.sin_addr)); 01073 } else { 01074 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); 01075 } 01076 } else if (!strcasecmp(v->name, "prefix")) { 01077 if (!ast_strlen_zero(v->value)) { 01078 newprefix[0] = '/'; 01079 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1); 01080 } else { 01081 newprefix[0] = '\0'; 01082 } 01083 } else if (!strcasecmp(v->name, "redirect")) { 01084 add_redirect(v->value); 01085 } else { 01086 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name); 01087 } 01088 } 01089 01090 #ifdef ENABLE_UPLOADS 01091 for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) 01092 add_post_mapping(v->name, v->value); 01093 #endif /* ENABLE_UPLOADS */ 01094 01095 ast_config_destroy(cfg); 01096 } 01097 if (!have_sslbindaddr) 01098 https_desc.sin.sin_addr = http_desc.sin.sin_addr; 01099 if (enabled) 01100 http_desc.sin.sin_family = https_desc.sin.sin_family = AF_INET; 01101 if (strcmp(prefix, newprefix)) 01102 ast_copy_string(prefix, newprefix, sizeof(prefix)); 01103 enablestatic = newenablestatic; 01104 ast_tcptls_server_start(&http_desc); 01105 if (ast_ssl_setup(https_desc.tls_cfg)) 01106 ast_tcptls_server_start(&https_desc); 01107 01108 return 0; 01109 }
| 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 908 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.
Referenced by __ast_http_load().
00909 { 00910 char *target, *dest; 00911 struct http_uri_redirect *redirect, *cur; 00912 unsigned int target_len; 00913 unsigned int total_len; 00914 00915 dest = ast_strdupa(value); 00916 dest = ast_skip_blanks(dest); 00917 target = strsep(&dest, " "); 00918 target = ast_skip_blanks(target); 00919 target = strsep(&target, " "); /* trim trailing whitespace */ 00920 00921 if (!dest) { 00922 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value); 00923 return; 00924 } 00925 00926 target_len = strlen(target) + 1; 00927 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1; 00928 00929 if (!(redirect = ast_calloc(1, total_len))) 00930 return; 00931 00932 redirect->dest = redirect->target + target_len; 00933 strcpy(redirect->target, target); 00934 strcpy(redirect->dest, dest); 00935 00936 AST_RWLIST_WRLOCK(&uri_redirects); 00937 00938 target_len--; /* So we can compare directly with strlen() */ 00939 if ( AST_RWLIST_EMPTY(&uri_redirects) 00940 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) { 00941 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry); 00942 AST_RWLIST_UNLOCK(&uri_redirects); 00943 return; 00944 } 00945 00946 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) { 00947 if ( AST_RWLIST_NEXT(cur, entry) 00948 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) { 00949 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry); 00950 AST_RWLIST_UNLOCK(&uri_redirects); 00951 return; 00952 } 00953 } 00954 00955 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry); 00956 00957 AST_RWLIST_UNLOCK(&uri_redirects); 00958 }
| struct ast_str* ast_http_error | ( | int | status, | |
| const char * | title, | |||
| const char * | extra_header, | |||
| const char * | text | |||
| ) | [read] |
Return an ast_str malloc()'d string containing an HTTP error message.
Definition at line 288 of file http.c.
References ast_str_create(), and ast_str_set().
Referenced by generic_http_callback(), handle_uri(), httpd_helper_thread(), phoneprov_callback(), and static_callback().
00289 { 00290 struct ast_str *out = ast_str_create(512); 00291 if (out == NULL) 00292 return out; 00293 ast_str_set(&out, 0, 00294 "Content-type: text/html\r\n" 00295 "%s" 00296 "\r\n" 00297 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00298 "<html><head>\r\n" 00299 "<title>%d %s</title>\r\n" 00300 "</head><body>\r\n" 00301 "<h1>%s</h1>\r\n" 00302 "<p>%s</p>\r\n" 00303 "<hr />\r\n" 00304 "<address>Asterisk Server</address>\r\n" 00305 "</body></html>\r\n", 00306 (extra_header ? extra_header : ""), status, title, title, text); 00307 return out; 00308 }
| int ast_http_init | ( | void | ) |
Definition at line 1188 of file http.c.
References __ast_http_load(), ast_cli_register_multiple(), ast_http_uri_link(), cli_http, staticuri, and statusuri.
Referenced by main().
01189 { 01190 #ifdef ENABLE_UPLOADS 01191 g_mime_init(0); 01192 #endif /* ENABLE_UPLOADS */ 01193 01194 ast_http_uri_link(&statusuri); 01195 ast_http_uri_link(&staticuri); 01196 ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry)); 01197 01198 return __ast_http_load(0); 01199 }
| int ast_http_reload | ( | void | ) |
Definition at line 1179 of file http.c.
References __ast_http_load().
01180 { 01181 return __ast_http_load(1); 01182 }
| int ast_http_uri_link | ( | struct ast_http_uri * | urih | ) |
Link the new uri into the list.
Link into the Asterisk HTTP server.
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 319 of file http.c.
References 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::entry, len(), and ast_http_uri::uri.
Referenced by __init_manager(), ast_http_init(), and load_module().
00320 { 00321 struct ast_http_uri *uri; 00322 int len = strlen(urih->uri); 00323 00324 AST_RWLIST_WRLOCK(&uris); 00325 00326 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) { 00327 AST_RWLIST_INSERT_HEAD(&uris, urih, entry); 00328 AST_RWLIST_UNLOCK(&uris); 00329 return 0; 00330 } 00331 00332 AST_RWLIST_TRAVERSE(&uris, uri, entry) { 00333 if ( AST_RWLIST_NEXT(uri, entry) 00334 && strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len ) { 00335 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry); 00336 AST_RWLIST_UNLOCK(&uris); 00337 return 0; 00338 } 00339 } 00340 00341 AST_RWLIST_INSERT_TAIL(&uris, urih, entry); 00342 00343 AST_RWLIST_UNLOCK(&uris); 00344 00345 return 0; 00346 }
| void ast_http_uri_unlink | ( | struct ast_http_uri * | urih | ) |
Destroy an HTTP server.
Definition at line 348 of file http.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_http_uri::entry.
Referenced by __init_manager(), and unload_module().
00349 { 00350 AST_RWLIST_WRLOCK(&uris); 00351 AST_RWLIST_REMOVE(&uris, urih, entry); 00352 AST_RWLIST_UNLOCK(&uris); 00353 }
| static const char* ftype2mtype | ( | const char * | ftype, | |
| char * | wkspace, | |||
| int | wkspacelen | |||
| ) | [static] |
Definition at line 135 of file http.c.
References ext, mimetypes, and mtype.
Referenced by build_profile(), and static_callback().
00136 { 00137 int x; 00138 if (ftype) { 00139 for (x=0;x<sizeof(mimetypes) / sizeof(mimetypes[0]); x++) { 00140 if (!strcasecmp(ftype, mimetypes[x].ext)) 00141 return mimetypes[x].mtype; 00142 } 00143 } 00144 snprintf(wkspace, wkspacelen, "text/%s", ftype ? ftype : "plain"); 00145 return wkspace; 00146 }
| static char* handle_show_http | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1111 of file http.c.
References ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, 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, ast_cli_args::fd, ast_http_uri::has_subtree, http_tls_cfg, server_args::oldsin, prefix, http_uri_redirect::target, ast_http_uri::uri, and ast_cli_entry::usage.
01112 { 01113 struct ast_http_uri *urih; 01114 struct http_uri_redirect *redirect; 01115 01116 #ifdef ENABLE_UPLOADS 01117 struct ast_http_post_mapping *post_map; 01118 #endif /* ENABLE_UPLOADS */ 01119 01120 switch (cmd) { 01121 case CLI_INIT: 01122 e->command = "http show status"; 01123 e->usage = 01124 "Usage: http show status\n" 01125 " Lists status of internal HTTP engine\n"; 01126 return NULL; 01127 case CLI_GENERATE: 01128 return NULL; 01129 } 01130 01131 if (a->argc != 3) 01132 return CLI_SHOWUSAGE; 01133 ast_cli(a->fd, "HTTP Server Status:\n"); 01134 ast_cli(a->fd, "Prefix: %s\n", prefix); 01135 if (!http_desc.oldsin.sin_family) 01136 ast_cli(a->fd, "Server Disabled\n\n"); 01137 else { 01138 ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n", 01139 ast_inet_ntoa(http_desc.oldsin.sin_addr), 01140 ntohs(http_desc.oldsin.sin_port)); 01141 if (http_tls_cfg.enabled) 01142 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n", 01143 ast_inet_ntoa(https_desc.oldsin.sin_addr), 01144 ntohs(https_desc.oldsin.sin_port)); 01145 } 01146 01147 ast_cli(a->fd, "Enabled URI's:\n"); 01148 AST_RWLIST_RDLOCK(&uris); 01149 if (AST_RWLIST_EMPTY(&uris)) { 01150 ast_cli(a->fd, "None.\n"); 01151 } else { 01152 AST_RWLIST_TRAVERSE(&uris, urih, entry) 01153 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description); 01154 } 01155 AST_RWLIST_UNLOCK(&uris); 01156 01157 ast_cli(a->fd, "\nEnabled Redirects:\n"); 01158 AST_RWLIST_RDLOCK(&uri_redirects); 01159 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) 01160 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest); 01161 if (AST_RWLIST_EMPTY(&uri_redirects)) 01162 ast_cli(a->fd, " None.\n"); 01163 AST_RWLIST_UNLOCK(&uri_redirects); 01164 01165 01166 #ifdef ENABLE_UPLOADS 01167 ast_cli(a->fd, "\nPOST mappings:\n"); 01168 AST_RWLIST_RDLOCK(&post_mappings); 01169 AST_LIST_TRAVERSE(&post_mappings, post_map, entry) { 01170 ast_cli(a->fd, "%s/%s => %s\n", prefix, post_map->from, post_map->to); 01171 } 01172 ast_cli(a->fd, "%s\n", AST_LIST_EMPTY(&post_mappings) ? "None.\n" : ""); 01173 AST_RWLIST_UNLOCK(&post_mappings); 01174 #endif /* ENABLE_UPLOADS */ 01175 01176 return CLI_SUCCESS; 01177 }
| static struct ast_str* handle_uri | ( | struct ast_tcptls_session_instance * | ser, | |
| char * | uri, | |||
| int * | status, | |||
| char ** | title, | |||
| int * | contentlength, | |||
| struct ast_variable ** | cookies, | |||
| unsigned int * | static_content | |||
| ) | [static, read] |
Definition at line 597 of file http.c.
References ast_http_error(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_variable_new(), ast_variables_destroy(), ast_http_uri::callback, cleanup(), http_uri_redirect::dest, http_uri_redirect::entry, ast_http_uri::has_subtree, http_decode(), ast_variable::next, prefix, ast_http_uri::static_content, strsep(), http_uri_redirect::target, and ast_http_uri::uri.
Referenced by httpd_helper_thread().
00600 { 00601 char *c; 00602 struct ast_str *out = NULL; 00603 char *params = uri; 00604 struct ast_http_uri *urih=NULL; 00605 int l; 00606 struct ast_variable *vars=NULL, *v, *prev = NULL; 00607 struct http_uri_redirect *redirect; 00608 00609 strsep(¶ms, "?"); 00610 /* Extract arguments from the request and store them in variables. */ 00611 if (params) { 00612 char *var, *val; 00613 00614 while ((val = strsep(¶ms, "&"))) { 00615 var = strsep(&val, "="); 00616 if (val) 00617 http_decode(val); 00618 else 00619 val = ""; 00620 http_decode(var); 00621 if ((v = ast_variable_new(var, val, ""))) { 00622 if (vars) 00623 prev->next = v; 00624 else 00625 vars = v; 00626 prev = v; 00627 } 00628 } 00629 } 00630 /* 00631 * Append the cookies to the variables (the only reason to have them 00632 * at the end is to avoid another pass of the cookies list to find 00633 * the tail). 00634 */ 00635 if (prev) 00636 prev->next = *cookies; 00637 else 00638 vars = *cookies; 00639 *cookies = NULL; 00640 http_decode(uri); 00641 00642 AST_RWLIST_RDLOCK(&uri_redirects); 00643 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) { 00644 if (!strcasecmp(uri, redirect->target)) { 00645 char buf[512]; 00646 snprintf(buf, sizeof(buf), "Location: %s\r\n", redirect->dest); 00647 out = ast_http_error((*status = 302), 00648 (*title = ast_strdup("Moved Temporarily")), 00649 buf, "Redirecting..."); 00650 00651 break; 00652 } 00653 } 00654 AST_RWLIST_UNLOCK(&uri_redirects); 00655 if (redirect) 00656 goto cleanup; 00657 00658 /* We want requests to start with the (optional) prefix and '/' */ 00659 l = strlen(prefix); 00660 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') { 00661 uri += l + 1; 00662 /* scan registered uris to see if we match one. */ 00663 AST_RWLIST_RDLOCK(&uris); 00664 AST_RWLIST_TRAVERSE(&uris, urih, entry) { 00665 l = strlen(urih->uri); 00666 c = uri + l; /* candidate */ 00667 if (strncasecmp(urih->uri, uri, l) /* no match */ 00668 || (*c && *c != '/')) /* substring */ 00669 continue; 00670 if (*c == '/') 00671 c++; 00672 if (!*c || urih->has_subtree) { 00673 uri = c; 00674 break; 00675 } 00676 } 00677 if (!urih) 00678 AST_RWLIST_UNLOCK(&uris); 00679 } 00680 if (urih) { 00681 if (urih->static_content) 00682 *static_content = 1; 00683 out = urih->callback(ser, uri, vars, status, title, contentlength); 00684 AST_RWLIST_UNLOCK(&uris); 00685 } else { 00686 out = ast_http_error(404, "Not Found", NULL, 00687 "The requested URL was not found on this server."); 00688 *status = 404; 00689 *title = ast_strdup("Not Found"); 00690 } 00691 00692 cleanup: 00693 ast_variables_destroy(vars); 00694 return out; 00695 }
| static void http_decode | ( | char * | s | ) | [static] |
Definition at line 585 of file http.c.
References ast_uri_decode().
Referenced by handle_uri().
00586 { 00587 char *t; 00588 00589 for (t = s; *t; t++) { 00590 if (*t == '+') 00591 *t = ' '; 00592 } 00593 00594 ast_uri_decode(s); 00595 }
| static void * httpd_helper_thread | ( | void * | arg | ) | [static] |
Definition at line 778 of file http.c.
References ao2_ref(), ast_free, ast_get_version(), ast_http_error(), ast_localtime(), ast_log(), ast_skip_blanks(), ast_skip_nonblanks(), ast_strdupa, ast_strftime(), ast_strlen_zero(), ast_trim_blanks(), ast_tvnow(), ast_variable_new(), ast_variables_destroy(), errno, ast_tcptls_session_instance::f, handle_uri(), LOG_WARNING, name, ast_variable::next, parse_cookies(), ast_str::str, and strsep().
00779 { 00780 char buf[4096]; 00781 char cookie[4096]; 00782 struct ast_tcptls_session_instance *ser = data; 00783 struct ast_variable *vars=NULL, *headers = NULL; 00784 char *uri, *title=NULL; 00785 int status = 200, contentlength = 0; 00786 struct ast_str *out = NULL; 00787 unsigned int static_content = 0; 00788 00789 if (!fgets(buf, sizeof(buf), ser->f)) 00790 goto done; 00791 00792 uri = ast_skip_nonblanks(buf); /* Skip method */ 00793 if (*uri) 00794 *uri++ = '\0'; 00795 00796 uri = ast_skip_blanks(uri); /* Skip white space */ 00797 00798 if (*uri) { /* terminate at the first blank */ 00799 char *c = ast_skip_nonblanks(uri); 00800 if (*c) 00801 *c = '\0'; 00802 } 00803 00804 /* process "Cookie: " lines */ 00805 while (fgets(cookie, sizeof(cookie), ser->f)) { 00806 /* Trim trailing characters */ 00807 ast_trim_blanks(cookie); 00808 if (ast_strlen_zero(cookie)) 00809 break; 00810 if (strncasecmp(cookie, "Cookie: ", 8)) { 00811 char *name, *value; 00812 struct ast_variable *var; 00813 00814 value = ast_strdupa(cookie); 00815 name = strsep(&value, ":"); 00816 if (!value) 00817 continue; 00818 value = ast_skip_blanks(value); 00819 if (ast_strlen_zero(value)) 00820 continue; 00821 var = ast_variable_new(name, value, ""); 00822 if (!var) 00823 continue; 00824 var->next = headers; 00825 headers = var; 00826 continue; 00827 } 00828 00829 if (vars) { 00830 ast_variables_destroy(vars); 00831 } 00832 vars = parse_cookies(cookie); 00833 } 00834 00835 if (!*uri) { 00836 out = ast_http_error(400, "Bad Request", NULL, "Invalid Request"); 00837 } else if (!strcasecmp(buf, "post")) { 00838 #ifdef ENABLE_UPLOADS 00839 out = handle_post(ser, uri, &status, &title, &contentlength, headers, vars); 00840 #else 00841 out = ast_http_error(501, "Not Implemented", NULL, 00842 "Attempt to use unimplemented / unsupported method"); 00843 #endif /* ENABLE_UPLOADS */ 00844 } else if (strcasecmp(buf, "get")) { 00845 out = ast_http_error(501, "Not Implemented", NULL, 00846 "Attempt to use unimplemented / unsupported method"); 00847 } else { /* try to serve it */ 00848 out = handle_uri(ser, uri, &status, &title, &contentlength, &vars, &static_content); 00849 } 00850 00851 /* If they aren't mopped up already, clean up the cookies */ 00852 if (vars) 00853 ast_variables_destroy(vars); 00854 /* Clean up all the header information pulled as well */ 00855 if (headers) 00856 ast_variables_destroy(headers); 00857 00858 if (out) { 00859 struct timeval tv = ast_tvnow(); 00860 char timebuf[256]; 00861 struct ast_tm tm; 00862 00863 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&tv, &tm, "GMT")); 00864 fprintf(ser->f, "HTTP/1.1 %d %s\r\n" 00865 "Server: Asterisk/%s\r\n" 00866 "Date: %s\r\n" 00867 "Connection: close\r\n" 00868 "%s", 00869 status, title ? title : "OK", ast_get_version(), timebuf, 00870 static_content ? "" : "Cache-Control: no-cache, no-store\r\n"); 00871 /* We set the no-cache headers only for dynamic content. 00872 * If you want to make sure the static file you requested is not from cache, 00873 * append a random variable to your GET request. Ex: 'something.html?r=109987734' 00874 */ 00875 if (!contentlength) { /* opaque body ? just dump it hoping it is properly formatted */ 00876 fprintf(ser->f, "%s", out->str); 00877 } else { 00878 char *tmp = strstr(out->str, "\r\n\r\n"); 00879 00880 if (tmp) { 00881 fprintf(ser->f, "Content-length: %d\r\n", contentlength); 00882 /* first write the header, then the body */ 00883 if (fwrite(out->str, 1, (tmp + 4 - out->str), ser->f) != tmp + 4 - out->str) { 00884 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00885 } 00886 if (fwrite(tmp + 4, 1, contentlength, ser->f) != contentlength ) { 00887 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00888 } 00889 } 00890 } 00891 ast_free(out); 00892 } 00893 if (title) 00894 ast_free(title); 00895 00896 done: 00897 fclose(ser->f); 00898 ao2_ref(ser, -1); 00899 ser = NULL; 00900 return NULL; 00901 }
| static struct ast_str* httpstatus_callback | ( | struct ast_tcptls_session_instance * | ser, | |
| const char * | uri, | |||
| struct ast_variable * | vars, | |||
| int * | status, | |||
| char ** | title, | |||
| int * | contentlength | |||
| ) | [static, read] |
Definition at line 236 of file http.c.
References ast_inet_ntoa(), ast_str_append(), ast_str_create(), ast_tls_config::enabled, http_tls_cfg, ast_variable::name, ast_variable::next, server_args::oldsin, prefix, and ast_variable::value.
00237 { 00238 struct ast_str *out = ast_str_create(512); 00239 struct ast_variable *v; 00240 00241 if (out == NULL) 00242 return out; 00243 00244 ast_str_append(&out, 0, 00245 "\r\n" 00246 "<title>Asterisk HTTP Status</title>\r\n" 00247 "<body bgcolor=\"#ffffff\">\r\n" 00248 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n" 00249 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n"); 00250 00251 ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); 00252 ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", 00253 ast_inet_ntoa(http_desc.oldsin.sin_addr)); 00254 ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n", 00255 ntohs(http_desc.oldsin.sin_port)); 00256 if (http_tls_cfg.enabled) 00257 ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n", 00258 ntohs(https_desc.oldsin.sin_port)); 00259 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00260 for (v = vars; v; v = v->next) { 00261 if (strncasecmp(v->name, "cookie_", 7)) 00262 ast_str_append(&out, 0, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00263 } 00264 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00265 for (v = vars; v; v = v->next) { 00266 if (!strncasecmp(v->name, "cookie_", 7)) 00267 ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00268 } 00269 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"); 00270 return out; 00271 }
| static uint32_t manid_from_vars | ( | struct ast_variable * | sid | ) | [static] |
Definition at line 148 of file http.c.
References ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by static_callback().
00148 { 00149 uint32_t mngid; 00150 00151 while (sid && strcmp(sid->name, "mansession_id")) 00152 sid = sid->next; 00153 00154 if (!sid || sscanf(sid->value, "%30x", &mngid) != 1) 00155 return 0; 00156 00157 return mngid; 00158 }
| static struct ast_variable* parse_cookies | ( | char * | cookies | ) | [static, read] |
Definition at line 741 of file http.c.
References ast_log(), ast_strip(), ast_strip_quoted(), ast_strlen_zero(), ast_variable_new(), LOG_DEBUG, name, option_debug, and strsep().
Referenced by httpd_helper_thread().
00742 { 00743 char *cur; 00744 struct ast_variable *vars = NULL, *var; 00745 00746 /* Skip Cookie: */ 00747 cookies += 8; 00748 00749 while ((cur = strsep(&cookies, ";"))) { 00750 char *name, *val; 00751 00752 name = val = cur; 00753 strsep(&val, "="); 00754 00755 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00756 continue; 00757 } 00758 00759 name = ast_strip(name); 00760 val = ast_strip_quoted(val, "\"", "\""); 00761 00762 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00763 continue; 00764 } 00765 00766 if (option_debug) { 00767 ast_log(LOG_DEBUG, "mmm ... cookie! Name: '%s' Value: '%s'\n", name, val); 00768 } 00769 00770 var = ast_variable_new(name, val, __FILE__); 00771 var->next = vars; 00772 vars = var; 00773 } 00774 00775 return vars; 00776 }
| static struct ast_str* static_callback | ( | struct ast_tcptls_session_instance * | ser, | |
| const char * | uri, | |||
| struct ast_variable * | vars, | |||
| int * | status, | |||
| char ** | title, | |||
| int * | contentlength | |||
| ) | [static, read] |
Definition at line 160 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, enablestatic, errno, ast_tcptls_session_instance::f, ftype2mtype(), len(), LOG_WARNING, manid_from_vars(), and mtype.
00161 { 00162 char *path; 00163 char *ftype; 00164 const char *mtype; 00165 char wkspace[80]; 00166 struct stat st; 00167 int len; 00168 int fd; 00169 struct timeval tv = ast_tvnow(); 00170 char buf[256]; 00171 struct ast_tm tm; 00172 00173 /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration 00174 substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */ 00175 if (!enablestatic || ast_strlen_zero(uri)) 00176 goto out403; 00177 /* Disallow any funny filenames at all */ 00178 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) 00179 goto out403; 00180 if (strstr(uri, "/..")) 00181 goto out403; 00182 00183 if ((ftype = strrchr(uri, '.'))) 00184 ftype++; 00185 mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace)); 00186 00187 /* Cap maximum length */ 00188 len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5; 00189 if (len > 1024) 00190 goto out403; 00191 00192 path = alloca(len); 00193 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri); 00194 if (stat(path, &st)) 00195 goto out404; 00196 if (S_ISDIR(st.st_mode)) 00197 goto out404; 00198 fd = open(path, O_RDONLY); 00199 if (fd < 0) 00200 goto out403; 00201 00202 if (strstr(path, "/private/") && !astman_is_authed(manid_from_vars(vars))) { 00203 goto out403; 00204 } 00205 00206 ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&tv, &tm, "GMT")); 00207 fprintf(ser->f, "HTTP/1.1 200 OK\r\n" 00208 "Server: Asterisk/%s\r\n" 00209 "Date: %s\r\n" 00210 "Connection: close\r\n" 00211 "Cache-Control: private\r\n" 00212 "Content-Length: %d\r\n" 00213 "Content-type: %s\r\n\r\n", 00214 ast_get_version(), buf, (int) st.st_size, mtype); 00215 00216 while ((len = read(fd, buf, sizeof(buf))) > 0) 00217 if (fwrite(buf, 1, len, ser->f) != len) { 00218 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00219 } 00220 00221 close(fd); 00222 return NULL; 00223 00224 out404: 00225 return ast_http_error((*status = 404), 00226 (*title = ast_strdup("Not Found")), 00227 NULL, "The requested URL was not found on this server."); 00228 00229 out403: 00230 return ast_http_error((*status = 403), 00231 (*title = ast_strdup("Access Denied")), 00232 NULL, "You do not have permission to access the requested URL."); 00233 }
struct ast_cli_entry cli_http[] [static] |
Initial value:
{
AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
}
Definition at line 1184 of file http.c.
Referenced by ast_http_init().
int enablestatic [static] |
| const char* ext |
Definition at line 114 of file http.c.
Referenced by ast_filehelper(), ast_rtp_read(), cli_console_dial(), common_exec(), console_transfer(), do_directory(), exts_compare(), ftype2mtype(), iax_park_thread(), misdn_call(), misdn_request(), mixmonitor_thread(), moh_scan_files(), oh323_request(), pbx_load_config(), record_exec(), register_exten(), register_peer_exten(), sip_park_thread(), sip_request_call(), and unregister_exten().
struct server_args http_desc [static] |
struct ast_tls_config http_tls_cfg [static] |
Definition at line 64 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct server_args https_desc [static] |
struct { ... } mimetypes[] [static] |
| const char* mtype |
char prefix[MAX_PREFIX] [static] |
list of supported handlers
Definition at line 91 of file http.c.
Referenced by __ast_http_load(), _while_exec(), ast_db_deltree(), ast_db_gettree(), exec_clearhash(), handle_cli_database_show(), handle_show_http(), handle_uri(), hashkeys_read(), httpstatus_callback(), 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] |
1.5.6