#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/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"
#include "asterisk/netsock2.h"

Go to the source code of this file.
Data Structures | |
| struct | ast_cfhttp_methods_text |
| struct | http_uri_redirect |
| struct | uri_redirects |
| struct | uris |
Defines | |
| #define | DEFAULT_PORT 8088 |
| #define | DEFAULT_SESSION_LIMIT 100 |
| #define | DEFAULT_TLS_PORT 8089 |
| #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. | |
| const char * | ast_get_http_method (enum ast_http_method method) |
| Return http method name string. | |
| void | ast_http_auth (struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text) |
| Send http "401 Unauthorized" response and close socket. | |
| void | ast_http_error (struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text) |
| Send HTTP error message and close socket. | |
| const char * | ast_http_ftype2mtype (const char *ftype) |
| Return mime type based on extension. | |
| struct ast_variable * | ast_http_get_cookies (struct ast_variable *headers) |
| Get cookie from Request headers. | |
| struct ast_variable * | ast_http_get_post_vars (struct ast_tcptls_session_instance *ser, struct ast_variable *headers) |
| Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded. | |
| int | ast_http_init (void) |
| uint32_t | ast_http_manid_from_vars (struct ast_variable *headers) |
| Return manager id, if exist, from request headers. | |
| void | ast_http_prefix (char *buf, int len) |
| Return the current prefix. | |
| int | ast_http_reload (void) |
| void | ast_http_send (struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content) |
| Generic function for sending http/1.1 response. | |
| 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) |
| Unregister a URI handler. | |
| void | ast_http_uri_unlink_all_with_key (const char *key) |
| Unregister all handlers with matching key. | |
| static char * | handle_show_http (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | handle_uri (struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method, struct ast_variable *headers) |
| static void * | httpd_helper_thread (void *arg) |
| static int | httpstatus_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) |
| static struct ast_variable * | parse_cookies (char *cookies) |
| static int | static_callback (struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) |
Variables | |
| static struct ast_cfhttp_methods_text | ast_http_methods_text [] |
| 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 int | session_count = 0 |
| static int | session_limit = DEFAULT_SESSION_LIMIT |
| 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 DEFAULT_PORT 8088 |
| #define DEFAULT_SESSION_LIMIT 100 |
| #define DEFAULT_TLS_PORT 8089 |
| #define MAX_PREFIX 80 |
| static int __ast_http_load | ( | int | reload | ) | [static] |
Definition at line 996 of file http.c.
References ast_tcptls_session_args::accept_fd, add_redirect(), AST_AF_UNSPEC, AST_CERTFILE, ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_free, ast_log(), ast_parse_arg(), AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sockaddr_copy(), ast_sockaddr_isnull(), ast_sockaddr_port, ast_sockaddr_resolve(), ast_sockaddr_set_port, ast_sockaddr_setnull(), ast_sockaddr_stringify(), ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_tcptls_server_stop(), ast_tls_read_conf(), ast_true(), ast_variable_browse(), ast_verb, ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_PORT, DEFAULT_SESSION_LIMIT, DEFAULT_TLS_PORT, ast_tls_config::enabled, enabled, http_uri_redirect::entry, http_tls_cfg, ast_variable::lineno, ast_tcptls_session_args::local_address, LOG_WARNING, MAX_PREFIX, ast_variable::name, ast_variable::next, PARSE_DEFAULT, PARSE_IN_RANGE, PARSE_INT32, PARSE_UINT32, ast_tls_config::pvtfile, ast_tcptls_session_args::tls_cfg, and ast_variable::value.
Referenced by ast_http_init(), and ast_http_reload().
00997 { 00998 struct ast_config *cfg; 00999 struct ast_variable *v; 01000 int enabled=0; 01001 int newenablestatic=0; 01002 char newprefix[MAX_PREFIX] = ""; 01003 struct http_uri_redirect *redirect; 01004 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01005 uint32_t bindport = DEFAULT_PORT; 01006 struct ast_sockaddr *addrs = NULL; 01007 int num_addrs = 0; 01008 int http_tls_was_enabled = 0; 01009 01010 cfg = ast_config_load2("http.conf", "http", config_flags); 01011 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 01012 return 0; 01013 } 01014 01015 http_tls_was_enabled = (reload && http_tls_cfg.enabled); 01016 01017 http_tls_cfg.enabled = 0; 01018 if (http_tls_cfg.certfile) { 01019 ast_free(http_tls_cfg.certfile); 01020 } 01021 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE); 01022 01023 if (http_tls_cfg.pvtfile) { 01024 ast_free(http_tls_cfg.pvtfile); 01025 } 01026 http_tls_cfg.pvtfile = ast_strdup(""); 01027 01028 if (http_tls_cfg.cipher) { 01029 ast_free(http_tls_cfg.cipher); 01030 } 01031 http_tls_cfg.cipher = ast_strdup(""); 01032 01033 AST_RWLIST_WRLOCK(&uri_redirects); 01034 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) { 01035 ast_free(redirect); 01036 } 01037 AST_RWLIST_UNLOCK(&uri_redirects); 01038 01039 ast_sockaddr_setnull(&https_desc.local_address); 01040 01041 if (cfg) { 01042 v = ast_variable_browse(cfg, "general"); 01043 for (; v; v = v->next) { 01044 01045 /* handle tls conf */ 01046 if (!ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) { 01047 continue; 01048 } 01049 01050 if (!strcasecmp(v->name, "enabled")) { 01051 enabled = ast_true(v->value); 01052 } else if (!strcasecmp(v->name, "enablestatic")) { 01053 newenablestatic = ast_true(v->value); 01054 } else if (!strcasecmp(v->name, "bindport")) { 01055 if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE | PARSE_DEFAULT, &bindport, DEFAULT_PORT, 0, 65535)) { 01056 ast_log(LOG_WARNING, "Invalid port %s specified. Using default port %"PRId32, v->value, DEFAULT_PORT); 01057 } 01058 } else if (!strcasecmp(v->name, "bindaddr")) { 01059 if (!(num_addrs = ast_sockaddr_resolve(&addrs, v->value, 0, AST_AF_UNSPEC))) { 01060 ast_log(LOG_WARNING, "Invalid bind address %s\n", v->value); 01061 } else { 01062 ast_log(LOG_WARNING, "Got %d addresses\n", num_addrs); 01063 } 01064 } else if (!strcasecmp(v->name, "prefix")) { 01065 if (!ast_strlen_zero(v->value)) { 01066 newprefix[0] = '/'; 01067 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1); 01068 } else { 01069 newprefix[0] = '\0'; 01070 } 01071 } else if (!strcasecmp(v->name, "redirect")) { 01072 add_redirect(v->value); 01073 } else if (!strcasecmp(v->name, "sessionlimit")) { 01074 if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE, 01075 &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) { 01076 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n", 01077 v->name, v->value, v->lineno); 01078 } 01079 } else { 01080 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name); 01081 } 01082 } 01083 01084 ast_config_destroy(cfg); 01085 } 01086 01087 if (strcmp(prefix, newprefix)) { 01088 ast_copy_string(prefix, newprefix, sizeof(prefix)); 01089 } 01090 enablestatic = newenablestatic; 01091 01092 if (num_addrs && enabled) { 01093 int i; 01094 for (i = 0; i < num_addrs; ++i) { 01095 ast_sockaddr_copy(&http_desc.local_address, &addrs[i]); 01096 if (!ast_sockaddr_port(&http_desc.local_address)) { 01097 ast_sockaddr_set_port(&http_desc.local_address, bindport); 01098 } 01099 ast_tcptls_server_start(&http_desc); 01100 if (http_desc.accept_fd == -1) { 01101 ast_log(LOG_WARNING, "Failed to start HTTP server for address %s\n", ast_sockaddr_stringify(&addrs[i])); 01102 ast_sockaddr_setnull(&http_desc.local_address); 01103 } else { 01104 ast_verb(1, "Bound HTTP server to address %s\n", ast_sockaddr_stringify(&addrs[i])); 01105 break; 01106 } 01107 } 01108 /* When no specific TLS bindaddr is specified, we just use 01109 * the non-TLS bindaddress here. 01110 */ 01111 if (ast_sockaddr_isnull(&https_desc.local_address) && http_desc.accept_fd != -1) { 01112 ast_sockaddr_copy(&https_desc.local_address, &https_desc.local_address); 01113 /* Of course, we can't use the same port though. 01114 * Since no bind address was specified, we just use the 01115 * default TLS port 01116 */ 01117 ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT); 01118 } 01119 } 01120 if (http_tls_was_enabled && !http_tls_cfg.enabled) { 01121 ast_tcptls_server_stop(&https_desc); 01122 } else if (http_tls_cfg.enabled && !ast_sockaddr_isnull(&https_desc.local_address)) { 01123 /* We can get here either because a TLS-specific address was specified 01124 * or because we copied the non-TLS address here. In the case where 01125 * we read an explicit address from the config, there may have been 01126 * no port specified, so we'll just use the default TLS port. 01127 */ 01128 if (!ast_sockaddr_port(&https_desc.local_address)) { 01129 ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT); 01130 } 01131 if (ast_ssl_setup(https_desc.tls_cfg)) { 01132 ast_tcptls_server_start(&https_desc); 01133 } 01134 } 01135 01136 return 0; 01137 }
| 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 943 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().
00944 { 00945 char *target, *dest; 00946 struct http_uri_redirect *redirect, *cur; 00947 unsigned int target_len; 00948 unsigned int total_len; 00949 00950 dest = ast_strdupa(value); 00951 dest = ast_skip_blanks(dest); 00952 target = strsep(&dest, " "); 00953 target = ast_skip_blanks(target); 00954 target = strsep(&target, " "); /* trim trailing whitespace */ 00955 00956 if (!dest) { 00957 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value); 00958 return; 00959 } 00960 00961 target_len = strlen(target) + 1; 00962 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1; 00963 00964 if (!(redirect = ast_calloc(1, total_len))) { 00965 return; 00966 } 00967 redirect->dest = redirect->target + target_len; 00968 strcpy(redirect->target, target); 00969 strcpy(redirect->dest, dest); 00970 00971 AST_RWLIST_WRLOCK(&uri_redirects); 00972 00973 target_len--; /* So we can compare directly with strlen() */ 00974 if (AST_RWLIST_EMPTY(&uri_redirects) 00975 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) { 00976 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry); 00977 AST_RWLIST_UNLOCK(&uri_redirects); 00978 00979 return; 00980 } 00981 00982 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) { 00983 if (AST_RWLIST_NEXT(cur, entry) 00984 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) { 00985 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry); 00986 AST_RWLIST_UNLOCK(&uri_redirects); 00987 return; 00988 } 00989 } 00990 00991 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry); 00992 00993 AST_RWLIST_UNLOCK(&uri_redirects); 00994 }
| const char* ast_get_http_method | ( | enum ast_http_method | method | ) |
Return http method name string.
Definition at line 150 of file http.c.
References ARRAY_LEN, ast_http_methods_text, and ast_cfhttp_methods_text::text.
Referenced by auth_http_callback().
00151 { 00152 int x; 00153 00154 for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) { 00155 if (ast_http_methods_text[x].method == method) { 00156 return ast_http_methods_text[x].text; 00157 } 00158 } 00159 00160 return NULL; 00161 }
| void ast_http_auth | ( | struct ast_tcptls_session_instance * | ser, | |
| const char * | realm, | |||
| const unsigned long | nonce, | |||
| const unsigned long | opaque, | |||
| int | stale, | |||
| const char * | text | |||
| ) |
Send http "401 Unauthorized" response and close socket.
Definition at line 464 of file http.c.
References ast_free, ast_http_send(), AST_HTTP_UNKNOWN, ast_str_create(), and ast_str_set().
Referenced by auth_http_callback().
00467 { 00468 struct ast_str *http_headers = ast_str_create(128); 00469 struct ast_str *out = ast_str_create(512); 00470 00471 if (!http_headers || !out) { 00472 ast_free(http_headers); 00473 ast_free(out); 00474 return; 00475 } 00476 00477 ast_str_set(&http_headers, 0, 00478 "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n" 00479 "Content-type: text/html\r\n", 00480 realm ? realm : "Asterisk", 00481 nonce, 00482 opaque, 00483 stale ? ", stale=true" : ""); 00484 00485 ast_str_set(&out, 0, 00486 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00487 "<html><head>\r\n" 00488 "<title>401 Unauthorized</title>\r\n" 00489 "</head><body>\r\n" 00490 "<h1>401 Unauthorized</h1>\r\n" 00491 "<p>%s</p>\r\n" 00492 "<hr />\r\n" 00493 "<address>Asterisk Server</address>\r\n" 00494 "</body></html>\r\n", 00495 text ? text : ""); 00496 00497 ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0); 00498 return; 00499 }
| void ast_http_error | ( | struct ast_tcptls_session_instance * | ser, | |
| int | status_code, | |||
| const char * | status_title, | |||
| const char * | text | |||
| ) |
Send HTTP error message and close socket.
Definition at line 502 of file http.c.
References ast_free, ast_http_send(), AST_HTTP_UNKNOWN, ast_str_create(), and ast_str_set().
Referenced by auth_http_callback(), generic_http_callback(), handle_uri(), http_post_callback(), httpd_helper_thread(), httpstatus_callback(), phoneprov_callback(), and static_callback().
00503 { 00504 struct ast_str *http_headers = ast_str_create(40); 00505 struct ast_str *out = ast_str_create(256); 00506 00507 if (!http_headers || !out) { 00508 ast_free(http_headers); 00509 ast_free(out); 00510 return; 00511 } 00512 00513 ast_str_set(&http_headers, 0, "Content-type: text/html\r\n"); 00514 00515 ast_str_set(&out, 0, 00516 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 00517 "<html><head>\r\n" 00518 "<title>%d %s</title>\r\n" 00519 "</head><body>\r\n" 00520 "<h1>%s</h1>\r\n" 00521 "<p>%s</p>\r\n" 00522 "<hr />\r\n" 00523 "<address>Asterisk Server</address>\r\n" 00524 "</body></html>\r\n", 00525 status_code, status_title, status_title, text); 00526 00527 ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0); 00528 return; 00529 }
| const char* ast_http_ftype2mtype | ( | const char * | ftype | ) |
Return mime type based on extension.
| ftype | filename extension |
Definition at line 163 of file http.c.
References ARRAY_LEN, ext, and mimetypes.
Referenced by build_profile(), and static_callback().
00164 { 00165 int x; 00166 00167 if (ftype) { 00168 for (x = 0; x < ARRAY_LEN(mimetypes); x++) { 00169 if (!strcasecmp(ftype, mimetypes[x].ext)) { 00170 return mimetypes[x].mtype; 00171 } 00172 } 00173 } 00174 return NULL; 00175 }
| struct ast_variable* ast_http_get_cookies | ( | struct ast_variable * | headers | ) | [read] |
Get cookie from Request headers.
Definition at line 820 of file http.c.
References ast_strdupa, ast_variables_destroy(), ast_variable::name, ast_variable::next, parse_cookies(), and ast_variable::value.
Referenced by ast_http_manid_from_vars(), generic_http_callback(), http_post_callback(), and httpstatus_callback().
00821 { 00822 struct ast_variable *v, *cookies=NULL; 00823 00824 for (v = headers; v; v = v->next) { 00825 if (!strncasecmp(v->name, "Cookie", 6)) { 00826 char *tmp = ast_strdupa(v->value); 00827 if (cookies) { 00828 ast_variables_destroy(cookies); 00829 } 00830 00831 cookies = parse_cookies(tmp); 00832 } 00833 } 00834 return cookies; 00835 }
| struct ast_variable* ast_http_get_post_vars | ( | struct ast_tcptls_session_instance * | ser, | |
| struct ast_variable * | headers | |||
| ) | [read] |
Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
| ser | TCP/TLS session object | |
| headers | List of HTTP headers |
Definition at line 600 of file http.c.
References ast_uri_decode(), ast_uri_http_legacy, ast_variable_new(), ast_tcptls_session_instance::f, ast_variable::name, ast_variable::next, strsep(), ast_variable::value, and var.
Referenced by auth_http_callback(), and generic_http_callback().
00602 { 00603 int content_length = 0; 00604 struct ast_variable *v, *post_vars=NULL, *prev = NULL; 00605 char *buf, *var, *val; 00606 00607 for (v = headers; v; v = v->next) { 00608 if (!strcasecmp(v->name, "Content-Type")) { 00609 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) { 00610 return NULL; 00611 } 00612 break; 00613 } 00614 } 00615 00616 for (v = headers; v; v = v->next) { 00617 if (!strcasecmp(v->name, "Content-Length")) { 00618 content_length = atoi(v->value) + 1; 00619 break; 00620 } 00621 } 00622 00623 if (!content_length) { 00624 return NULL; 00625 } 00626 00627 if (!(buf = alloca(content_length))) { 00628 return NULL; 00629 } 00630 if (!fgets(buf, content_length, ser->f)) { 00631 return NULL; 00632 } 00633 00634 while ((val = strsep(&buf, "&"))) { 00635 var = strsep(&val, "="); 00636 if (val) { 00637 ast_uri_decode(val, ast_uri_http_legacy); 00638 } else { 00639 val = ""; 00640 } 00641 ast_uri_decode(var, ast_uri_http_legacy); 00642 if ((v = ast_variable_new(var, val, ""))) { 00643 if (post_vars) { 00644 prev->next = v; 00645 } else { 00646 post_vars = v; 00647 } 00648 prev = v; 00649 } 00650 } 00651 return post_vars; 00652 }
| int ast_http_init | ( | void | ) |
Provided by http.c
Definition at line 1202 of file http.c.
References __ast_http_load(), ARRAY_LEN, ast_cli_register_multiple(), ast_http_uri_link(), cli_http, staticuri, and statusuri.
Referenced by main().
01203 { 01204 ast_http_uri_link(&statusuri); 01205 ast_http_uri_link(&staticuri); 01206 ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http)); 01207 01208 return __ast_http_load(0); 01209 }
| uint32_t ast_http_manid_from_vars | ( | struct ast_variable * | headers | ) |
Return manager id, if exist, from request headers.
| headers | List of HTTP headers |
Definition at line 177 of file http.c.
References ast_http_get_cookies(), ast_variables_destroy(), ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by http_post_callback(), and static_callback().
00178 { 00179 uint32_t mngid = 0; 00180 struct ast_variable *v, *cookies; 00181 00182 cookies = ast_http_get_cookies(headers); 00183 for (v = cookies; v; v = v->next) { 00184 if (!strcasecmp(v->name, "mansession_id")) { 00185 sscanf(v->value, "%30x", &mngid); 00186 break; 00187 } 00188 } 00189 if (cookies) { 00190 ast_variables_destroy(cookies); 00191 } 00192 return mngid; 00193 }
| void ast_http_prefix | ( | char * | buf, | |
| int | len | |||
| ) |
Return the current prefix.
| [out] | buf | destination buffer for previous |
| [in] | len | length of prefix to copy |
Definition at line 195 of file http.c.
References ast_copy_string().
00196 { 00197 if (buf) { 00198 ast_copy_string(buf, prefix, len); 00199 } 00200 }
| int ast_http_reload | ( | void | ) |
Provided by http.c
Definition at line 1193 of file http.c.
References __ast_http_load().
01194 { 01195 return __ast_http_load(1); 01196 }
| void ast_http_send | ( | struct ast_tcptls_session_instance * | ser, | |
| enum ast_http_method | method, | |||
| int | status_code, | |||
| const char * | status_title, | |||
| struct ast_str * | http_header, | |||
| struct ast_str * | out, | |||
| const int | fd, | |||
| unsigned int | static_content | |||
| ) |
Generic function for sending http/1.1 response.
| ser | TCP/TLS session object | |
| method | GET/POST/HEAD | |
| status_code | HTTP response code (200/401/403/404/500) | |
| status_title | English equivalent to the status_code parameter | |
| http_header | An ast_str object containing all headers | |
| out | An ast_str object containing the body of the response | |
| fd | If out is NULL, a file descriptor where the body of the response is held (otherwise -1) | |
| static_content | Zero if the content is dynamically generated and should not be cached; nonzero otherwise |
HTTP content can be constructed from the argument "out", if it is not NULL; otherwise, the function will read content from FD.
This function calculates the content-length http header itself.
Both the http_header and out arguments will be freed by this function; however, if FD is open, it will remain open.
Definition at line 390 of file http.c.
References ast_free, ast_get_version(), AST_HTTP_HEAD, ast_localtime(), ast_log(), ast_str_buffer(), ast_strftime(), ast_tvnow(), errno, ast_tcptls_session_instance::f, len(), and LOG_WARNING.
Referenced by ast_http_auth(), ast_http_error(), auth_http_callback(), generic_http_callback(), handle_uri(), httpstatus_callback(), phoneprov_callback(), and static_callback().
00394 { 00395 struct timeval now = ast_tvnow(); 00396 struct ast_tm tm; 00397 char timebuf[80]; 00398 int content_length = 0; 00399 00400 if (!ser || 0 == ser->f) { 00401 return; 00402 } 00403 00404 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT")); 00405 00406 /* calc content length */ 00407 if (out) { 00408 content_length += strlen(ast_str_buffer(out)); 00409 } 00410 00411 if (fd) { 00412 content_length += lseek(fd, 0, SEEK_END); 00413 lseek(fd, 0, SEEK_SET); 00414 } 00415 00416 /* send http header */ 00417 fprintf(ser->f, "HTTP/1.1 %d %s\r\n" 00418 "Server: Asterisk/%s\r\n" 00419 "Date: %s\r\n" 00420 "Connection: close\r\n" 00421 "%s" 00422 "Content-Length: %d\r\n" 00423 "%s" 00424 "\r\n", 00425 status_code, status_title ? status_title : "OK", 00426 ast_get_version(), 00427 timebuf, 00428 static_content ? "" : "Cache-Control: no-cache, no-store\r\n", 00429 content_length, 00430 http_header ? ast_str_buffer(http_header) : "" 00431 ); 00432 00433 /* send content */ 00434 if (method != AST_HTTP_HEAD || status_code >= 400) { 00435 if (out) { 00436 fprintf(ser->f, "%s", ast_str_buffer(out)); 00437 } 00438 00439 if (fd) { 00440 char buf[256]; 00441 int len; 00442 while ((len = read(fd, buf, sizeof(buf))) > 0) { 00443 if (fwrite(buf, len, 1, ser->f) != 1) { 00444 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00445 break; 00446 } 00447 } 00448 } 00449 } 00450 00451 if (http_header) { 00452 ast_free(http_header); 00453 } 00454 if (out) { 00455 ast_free(out); 00456 } 00457 00458 fclose(ser->f); 00459 ser->f = 0; 00460 return; 00461 }
| int ast_http_uri_link | ( | struct ast_http_uri * | urih | ) |
Link the new uri into the list.
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 540 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, http_uri_redirect::entry, len(), and ast_http_uri::uri.
Referenced by __ast_http_post_load(), __init_manager(), ast_http_init(), and load_module().
00541 { 00542 struct ast_http_uri *uri; 00543 int len = strlen(urih->uri); 00544 00545 AST_RWLIST_WRLOCK(&uris); 00546 00547 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) { 00548 AST_RWLIST_INSERT_HEAD(&uris, urih, entry); 00549 AST_RWLIST_UNLOCK(&uris); 00550 return 0; 00551 } 00552 00553 AST_RWLIST_TRAVERSE(&uris, uri, entry) { 00554 if (AST_RWLIST_NEXT(uri, entry) && 00555 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) { 00556 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry); 00557 AST_RWLIST_UNLOCK(&uris); 00558 00559 return 0; 00560 } 00561 } 00562 00563 AST_RWLIST_INSERT_TAIL(&uris, urih, entry); 00564 00565 AST_RWLIST_UNLOCK(&uris); 00566 00567 return 0; 00568 }
| void ast_http_uri_unlink | ( | struct ast_http_uri * | urih | ) |
Unregister a URI handler.
Definition at line 570 of file http.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and http_uri_redirect::entry.
Referenced by __init_manager(), and unload_module().
00571 { 00572 AST_RWLIST_WRLOCK(&uris); 00573 AST_RWLIST_REMOVE(&uris, urih, entry); 00574 AST_RWLIST_UNLOCK(&uris); 00575 }
| void ast_http_uri_unlink_all_with_key | ( | const char * | key | ) |
Unregister all handlers with matching key.
Definition at line 577 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, http_uri_redirect::entry, ast_http_uri::key, and ast_http_uri::mallocd.
Referenced by __ast_http_post_load(), and unload_module().
00578 { 00579 struct ast_http_uri *urih; 00580 AST_RWLIST_WRLOCK(&uris); 00581 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) { 00582 if (!strcmp(urih->key, key)) { 00583 AST_RWLIST_REMOVE_CURRENT(entry); 00584 } 00585 if (urih->dmallocd) { 00586 ast_free(urih->data); 00587 } 00588 if (urih->mallocd) { 00589 ast_free(urih); 00590 } 00591 } 00592 AST_RWLIST_TRAVERSE_SAFE_END; 00593 AST_RWLIST_UNLOCK(&uris); 00594 }
| static char* handle_show_http | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1139 of file http.c.
References ast_cli_args::argc, ast_cli(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sockaddr_isnull(), ast_sockaddr_stringify(), 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_tls_cfg, ast_tcptls_session_args::old_address, http_uri_redirect::target, ast_http_uri::uri, and ast_cli_entry::usage.
01140 { 01141 struct ast_http_uri *urih; 01142 struct http_uri_redirect *redirect; 01143 01144 switch (cmd) { 01145 case CLI_INIT: 01146 e->command = "http show status"; 01147 e->usage = 01148 "Usage: http show status\n" 01149 " Lists status of internal HTTP engine\n"; 01150 return NULL; 01151 case CLI_GENERATE: 01152 return NULL; 01153 } 01154 01155 if (a->argc != 3) { 01156 return CLI_SHOWUSAGE; 01157 } 01158 ast_cli(a->fd, "HTTP Server Status:\n"); 01159 ast_cli(a->fd, "Prefix: %s\n", prefix); 01160 if (ast_sockaddr_isnull(&http_desc.old_address)) { 01161 ast_cli(a->fd, "Server Disabled\n\n"); 01162 } else { 01163 ast_cli(a->fd, "Server Enabled and Bound to %s\n\n", 01164 ast_sockaddr_stringify(&http_desc.old_address)); 01165 if (http_tls_cfg.enabled) { 01166 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s\n\n", 01167 ast_sockaddr_stringify(&https_desc.old_address)); 01168 } 01169 } 01170 01171 ast_cli(a->fd, "Enabled URI's:\n"); 01172 AST_RWLIST_RDLOCK(&uris); 01173 if (AST_RWLIST_EMPTY(&uris)) { 01174 ast_cli(a->fd, "None.\n"); 01175 } else { 01176 AST_RWLIST_TRAVERSE(&uris, urih, entry) 01177 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description); 01178 } 01179 AST_RWLIST_UNLOCK(&uris); 01180 01181 ast_cli(a->fd, "\nEnabled Redirects:\n"); 01182 AST_RWLIST_RDLOCK(&uri_redirects); 01183 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) 01184 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest); 01185 if (AST_RWLIST_EMPTY(&uri_redirects)) { 01186 ast_cli(a->fd, " None.\n"); 01187 } 01188 AST_RWLIST_UNLOCK(&uri_redirects); 01189 01190 return CLI_SUCCESS; 01191 }
| static int handle_uri | ( | struct ast_tcptls_session_instance * | ser, | |
| char * | uri, | |||
| enum ast_http_method | method, | |||
| struct ast_variable * | headers | |||
| ) | [static] |
Definition at line 654 of file http.c.
References ast_debug, ast_http_error(), ast_http_send(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_str_create(), ast_str_set(), ast_uri_decode(), ast_uri_http_legacy, ast_variable_new(), ast_variables_destroy(), ast_http_uri::callback, cleanup(), http_uri_redirect::dest, http_uri_redirect::entry, ast_http_uri::has_subtree, strsep(), http_uri_redirect::target, ast_http_uri::uri, and var.
Referenced by httpd_helper_thread().
00656 { 00657 char *c; 00658 int res = -1; 00659 char *params = uri; 00660 struct ast_http_uri *urih = NULL; 00661 int l; 00662 struct ast_variable *get_vars = NULL, *v, *prev = NULL; 00663 struct http_uri_redirect *redirect; 00664 00665 ast_debug(2, "HTTP Request URI is %s \n", uri); 00666 00667 strsep(¶ms, "?"); 00668 /* Extract arguments from the request and store them in variables. */ 00669 if (params) { 00670 char *var, *val; 00671 00672 while ((val = strsep(¶ms, "&"))) { 00673 var = strsep(&val, "="); 00674 if (val) { 00675 ast_uri_decode(val, ast_uri_http_legacy); 00676 } else { 00677 val = ""; 00678 } 00679 ast_uri_decode(var, ast_uri_http_legacy); 00680 if ((v = ast_variable_new(var, val, ""))) { 00681 if (get_vars) { 00682 prev->next = v; 00683 } else { 00684 get_vars = v; 00685 } 00686 prev = v; 00687 } 00688 } 00689 } 00690 ast_uri_decode(uri, ast_uri_http_legacy); 00691 00692 AST_RWLIST_RDLOCK(&uri_redirects); 00693 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) { 00694 if (!strcasecmp(uri, redirect->target)) { 00695 struct ast_str *http_header = ast_str_create(128); 00696 ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest); 00697 ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0); 00698 00699 break; 00700 } 00701 } 00702 AST_RWLIST_UNLOCK(&uri_redirects); 00703 if (redirect) { 00704 goto cleanup; 00705 } 00706 00707 /* We want requests to start with the (optional) prefix and '/' */ 00708 l = strlen(prefix); 00709 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') { 00710 uri += l + 1; 00711 /* scan registered uris to see if we match one. */ 00712 AST_RWLIST_RDLOCK(&uris); 00713 AST_RWLIST_TRAVERSE(&uris, urih, entry) { 00714 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l); 00715 l = strlen(urih->uri); 00716 c = uri + l; /* candidate */ 00717 if (strncasecmp(urih->uri, uri, l) /* no match */ 00718 || (*c && *c != '/')) { /* substring */ 00719 continue; 00720 } 00721 if (*c == '/') { 00722 c++; 00723 } 00724 if (!*c || urih->has_subtree) { 00725 uri = c; 00726 break; 00727 } 00728 } 00729 AST_RWLIST_UNLOCK(&uris); 00730 } 00731 if (urih) { 00732 res = urih->callback(ser, urih, uri, method, get_vars, headers); 00733 } else { 00734 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server."); 00735 } 00736 00737 cleanup: 00738 ast_variables_destroy(get_vars); 00739 return res; 00740 }
| static void * httpd_helper_thread | ( | void * | arg | ) | [static] |
Definition at line 838 of file http.c.
References ao2_ref, ast_atomic_fetchadd_int(), ast_http_error(), AST_HTTP_GET, AST_HTTP_HEAD, AST_HTTP_POST, AST_HTTP_PUT, AST_HTTP_UNKNOWN, ast_skip_blanks(), ast_skip_nonblanks(), ast_strlen_zero(), ast_trim_blanks(), ast_variable_new(), ast_variables_destroy(), ast_tcptls_session_instance::f, handle_uri(), name, ast_variable::next, strsep(), and value.
00839 { 00840 char buf[4096]; 00841 char header_line[4096]; 00842 struct ast_tcptls_session_instance *ser = data; 00843 struct ast_variable *headers = NULL; 00844 struct ast_variable *tail = headers; 00845 char *uri, *method; 00846 enum ast_http_method http_method = AST_HTTP_UNKNOWN; 00847 00848 if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) { 00849 goto done; 00850 } 00851 00852 if (!fgets(buf, sizeof(buf), ser->f)) { 00853 goto done; 00854 } 00855 00856 /* Get method */ 00857 method = ast_skip_blanks(buf); 00858 uri = ast_skip_nonblanks(method); 00859 if (*uri) { 00860 *uri++ = '\0'; 00861 } 00862 00863 if (!strcasecmp(method,"GET")) { 00864 http_method = AST_HTTP_GET; 00865 } else if (!strcasecmp(method,"POST")) { 00866 http_method = AST_HTTP_POST; 00867 } else if (!strcasecmp(method,"HEAD")) { 00868 http_method = AST_HTTP_HEAD; 00869 } else if (!strcasecmp(method,"PUT")) { 00870 http_method = AST_HTTP_PUT; 00871 } 00872 00873 uri = ast_skip_blanks(uri); /* Skip white space */ 00874 00875 if (*uri) { /* terminate at the first blank */ 00876 char *c = ast_skip_nonblanks(uri); 00877 00878 if (*c) { 00879 *c = '\0'; 00880 } 00881 } 00882 00883 /* process "Request Headers" lines */ 00884 while (fgets(header_line, sizeof(header_line), ser->f)) { 00885 char *name, *value; 00886 00887 /* Trim trailing characters */ 00888 ast_trim_blanks(header_line); 00889 if (ast_strlen_zero(header_line)) { 00890 break; 00891 } 00892 00893 value = header_line; 00894 name = strsep(&value, ":"); 00895 if (!value) { 00896 continue; 00897 } 00898 00899 value = ast_skip_blanks(value); 00900 if (ast_strlen_zero(value) || ast_strlen_zero(name)) { 00901 continue; 00902 } 00903 00904 ast_trim_blanks(name); 00905 00906 if (!headers) { 00907 headers = ast_variable_new(name, value, __FILE__); 00908 tail = headers; 00909 } else { 00910 tail->next = ast_variable_new(name, value, __FILE__); 00911 tail = tail->next; 00912 } 00913 } 00914 00915 if (!*uri) { 00916 ast_http_error(ser, 400, "Bad Request", "Invalid Request"); 00917 goto done; 00918 } 00919 00920 handle_uri(ser, uri, http_method, headers); 00921 00922 done: 00923 ast_atomic_fetchadd_int(&session_count, -1); 00924 00925 /* clean up all the header information */ 00926 if (headers) { 00927 ast_variables_destroy(headers); 00928 } 00929 00930 if (ser->f) { 00931 fclose(ser->f); 00932 } 00933 ao2_ref(ser, -1); 00934 ser = NULL; 00935 return NULL; 00936 }
| static int httpstatus_callback | ( | struct ast_tcptls_session_instance * | ser, | |
| const struct ast_http_uri * | urih, | |||
| const char * | uri, | |||
| enum ast_http_method | method, | |||
| struct ast_variable * | get_vars, | |||
| struct ast_variable * | headers | |||
| ) | [static] |
Definition at line 320 of file http.c.
References ast_http_error(), AST_HTTP_GET, ast_http_get_cookies(), AST_HTTP_HEAD, ast_http_send(), ast_sockaddr_stringify_addr(), ast_sockaddr_stringify_port(), ast_str_append(), ast_str_create(), ast_variables_destroy(), ast_tls_config::enabled, http_tls_cfg, ast_variable::name, ast_variable::next, ast_tcptls_session_args::old_address, and ast_variable::value.
00324 { 00325 struct ast_str *out; 00326 struct ast_variable *v, *cookies = NULL; 00327 00328 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) { 00329 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 00330 return -1; 00331 } 00332 00333 if ( (out = ast_str_create(512)) == NULL) { 00334 return -1; 00335 } 00336 00337 ast_str_append(&out, 0, 00338 "<title>Asterisk HTTP Status</title>\r\n" 00339 "<body bgcolor=\"#ffffff\">\r\n" 00340 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n" 00341 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n"); 00342 00343 ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); 00344 ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", 00345 ast_sockaddr_stringify_addr(&http_desc.old_address)); 00346 ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n", 00347 ast_sockaddr_stringify_port(&http_desc.old_address)); 00348 if (http_tls_cfg.enabled) { 00349 ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n", 00350 ast_sockaddr_stringify_port(&https_desc.old_address)); 00351 } 00352 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00353 for (v = get_vars; v; v = v->next) { 00354 ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00355 } 00356 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); 00357 00358 cookies = ast_http_get_cookies(headers); 00359 for (v = cookies; v; v = v->next) { 00360 ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value); 00361 } 00362 ast_variables_destroy(cookies); 00363 00364 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"); 00365 ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0); 00366 return 0; 00367 }
| static struct ast_variable* parse_cookies | ( | char * | cookies | ) | [static, read] |
Definition at line 787 of file http.c.
References ast_debug, ast_strip(), ast_strip_quoted(), ast_strlen_zero(), ast_variable_new(), name, strsep(), and var.
Referenced by ast_http_get_cookies().
00788 { 00789 char *cur; 00790 struct ast_variable *vars = NULL, *var; 00791 00792 while ((cur = strsep(&cookies, ";"))) { 00793 char *name, *val; 00794 00795 name = val = cur; 00796 strsep(&val, "="); 00797 00798 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00799 continue; 00800 } 00801 00802 name = ast_strip(name); 00803 val = ast_strip_quoted(val, "\"", "\""); 00804 00805 if (ast_strlen_zero(name) || ast_strlen_zero(val)) { 00806 continue; 00807 } 00808 00809 ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val); 00810 00811 var = ast_variable_new(name, val, __FILE__); 00812 var->next = vars; 00813 vars = var; 00814 } 00815 00816 return vars; 00817 }
| static int static_callback | ( | struct ast_tcptls_session_instance * | ser, | |
| const struct ast_http_uri * | urih, | |||
| const char * | uri, | |||
| enum ast_http_method | method, | |||
| struct ast_variable * | get_vars, | |||
| struct ast_variable * | headers | |||
| ) | [static] |
Definition at line 202 of file http.c.
References ast_config_AST_DATA_DIR, ast_http_error(), ast_http_ftype2mtype(), AST_HTTP_GET, AST_HTTP_HEAD, ast_http_manid_from_vars(), ast_http_send(), ast_localtime(), ast_str_create(), ast_str_set(), ast_strftime(), ast_strlen_zero(), astman_is_authed(), len(), mtype, ast_variable::name, ast_variable::next, S_OR, and ast_variable::value.
00206 { 00207 char *path; 00208 const char *ftype; 00209 const char *mtype; 00210 char wkspace[80]; 00211 struct stat st; 00212 int len; 00213 int fd; 00214 struct ast_str *http_header; 00215 struct timeval tv; 00216 struct ast_tm tm; 00217 char timebuf[80], etag[23]; 00218 struct ast_variable *v; 00219 int not_modified = 0; 00220 00221 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) { 00222 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 00223 return -1; 00224 } 00225 00226 /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration 00227 substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */ 00228 if (!enablestatic || ast_strlen_zero(uri)) { 00229 goto out403; 00230 } 00231 00232 /* Disallow any funny filenames at all */ 00233 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) { 00234 goto out403; 00235 } 00236 00237 if (strstr(uri, "/..")) { 00238 goto out403; 00239 } 00240 00241 if ((ftype = strrchr(uri, '.'))) { 00242 ftype++; 00243 } 00244 00245 if (!(mtype = ast_http_ftype2mtype(ftype))) { 00246 snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain")); 00247 } 00248 00249 /* Cap maximum length */ 00250 if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) { 00251 goto out403; 00252 } 00253 00254 path = alloca(len); 00255 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri); 00256 if (stat(path, &st)) { 00257 goto out404; 00258 } 00259 00260 if (S_ISDIR(st.st_mode)) { 00261 goto out404; 00262 } 00263 00264 fd = open(path, O_RDONLY); 00265 if (fd < 0) { 00266 goto out403; 00267 } 00268 00269 if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) { 00270 goto out403; 00271 } 00272 00273 /* make "Etag:" http header value */ 00274 snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime); 00275 00276 /* make "Last-Modified:" http header value */ 00277 tv.tv_sec = st.st_mtime; 00278 tv.tv_usec = 0; 00279 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT")); 00280 00281 /* check received "If-None-Match" request header and Etag value for file */ 00282 for (v = headers; v; v = v->next) { 00283 if (!strcasecmp(v->name, "If-None-Match")) { 00284 if (!strcasecmp(v->value, etag)) { 00285 not_modified = 1; 00286 } 00287 break; 00288 } 00289 } 00290 00291 if ( (http_header = ast_str_create(255)) == NULL) { 00292 return -1; 00293 } 00294 00295 ast_str_set(&http_header, 0, "Content-type: %s\r\n" 00296 "ETag: %s\r\n" 00297 "Last-Modified: %s\r\n", 00298 mtype, 00299 etag, 00300 timebuf); 00301 00302 /* ast_http_send() frees http_header, so we don't need to do it before returning */ 00303 if (not_modified) { 00304 ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1); 00305 } else { 00306 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1); /* static content flag is set */ 00307 } 00308 close(fd); 00309 return 0; 00310 00311 out404: 00312 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server."); 00313 return -1; 00314 00315 out403: 00316 ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL."); 00317 return -1; 00318 }
struct ast_cfhttp_methods_text ast_http_methods_text[] [static] |
Referenced by ast_get_http_method().
struct ast_cli_entry cli_http[] [static] |
Initial value:
{
AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
}
Definition at line 1198 of file http.c.
Referenced by ast_http_init().
int enablestatic [static] |
| const char* ext |
Definition at line 109 of file http.c.
Referenced by ast_http_ftype2mtype(), ast_rtp_read(), cli_console_dial(), common_exec(), console_transfer(), dahdi_call(), do_directory(), exts_compare(), filehelper(), handle_cli_dialplan_save(), hintdevice_cmp_multiple(), hintdevice_hash_cb(), iax_park_thread(), misdn_call(), misdn_request(), mixmonitor_save_prep(), moh_scan_files(), oh323_request(), pbx_load_config(), pbx_load_users(), pvalGotoSetTarget(), record_exec(), register_exten(), register_peer_exten(), sip_park_thread(), sip_request_call(), and unregister_exten().
struct ast_tcptls_session_args http_desc [static] |
struct ast_tls_config http_tls_cfg [static] |
Definition at line 74 of file http.c.
Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().
struct ast_tcptls_session_args https_desc [static] |
struct { ... } mimetypes[] [static] |
| const char* mtype |
char prefix[MAX_PREFIX] [static] |
list of supported handlers
Definition at line 101 of file http.c.
Referenced by _while_exec(), aoc_d_event(), aoc_e_event(), aoc_s_event(), ast_db_deltree(), ast_db_gettree(), ast_remotecontrol(), exec_clearhash(), handle_cli_database_show(), hashkeys_read(), hashkeys_read2(), shared_read(), shared_write(), sip_show_settings(), and while_continue_exec().
int session_count = 0 [static] |
int session_limit = DEFAULT_SESSION_LIMIT [static] |
struct ast_http_uri staticuri [static] |
struct ast_http_uri statusuri [static] |
1.5.6