#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 | 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) |
int | ast_http_reload (void) |
int | ast_http_uri_link (struct ast_http_uri *urih) |
Link into the Asterisk HTTP server. | |
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 |
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 ahp, AST_CERTFILE, ast_config_load, ast_free, ast_gethostbyname(), 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_STATUS_FILEUNCHANGED, ast_tls_config::enabled, enabled, hp, http_desc, http_tls_cfg, https_desc, MAX_PREFIX, ast_variable::name, ast_variable::next, server_args::sin, 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, strsep(), and http_uri_redirect::target.
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 | |||
) |
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 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 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 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 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 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_desc, http_tls_cfg, https_desc, server_args::oldsin, 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] |
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, ast_http_uri::uri, val, and var.
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(), name, parse_cookies(), ast_str::str, strsep(), and var.
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] |
Definition at line 236 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, 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, "%x", &mngid) != 1) 00155 return 0; 00156 00157 return mngid; 00158 }
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 741 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().
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] |
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:
{ { .handler = handle_show_http , .summary = "Display HTTP server status" ,__VA_ARGS__ }, }
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] |
we have up to two accepting threads, one for http, one for https
Definition at line 71 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 64 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct server_args https_desc [static] |
Definition at line 81 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 109 of file http.c.
Referenced by _while_exec(), ast_db_deltree(), ast_db_gettree(), exec_clearhash(), handle_cli_database_show(), 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] |