00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
00040
00041 #include <time.h>
00042 #include <sys/time.h>
00043 #include <sys/stat.h>
00044 #include <sys/signal.h>
00045 #include <fcntl.h>
00046
00047 #include "asterisk/paths.h"
00048 #include "asterisk/network.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/tcptls.h"
00051 #include "asterisk/http.h"
00052 #include "asterisk/utils.h"
00053 #include "asterisk/strings.h"
00054 #include "asterisk/config.h"
00055 #include "asterisk/stringfields.h"
00056 #include "asterisk/ast_version.h"
00057 #include "asterisk/manager.h"
00058 #include "asterisk/_private.h"
00059 #include "asterisk/astobj2.h"
00060
00061 #define MAX_PREFIX 80
00062 #define DEFAULT_SESSION_LIMIT 100
00063
00064 #define DEFAULT_HTTP_PORT 8088
00065 #define DEFAULT_HTTPS_PORT 8089
00066
00067
00068 #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
00069 #define DO_SSL
00070 #endif
00071
00072 static int session_limit = DEFAULT_SESSION_LIMIT;
00073 static int session_count = 0;
00074
00075 static struct ast_tls_config http_tls_cfg;
00076
00077 static void *httpd_helper_thread(void *arg);
00078
00079
00080
00081
00082 static struct ast_tcptls_session_args http_desc = {
00083 .accept_fd = -1,
00084 .master = AST_PTHREADT_NULL,
00085 .tls_cfg = NULL,
00086 .poll_timeout = -1,
00087 .name = "http server",
00088 .accept_fn = ast_tcptls_server_root,
00089 .worker_fn = httpd_helper_thread,
00090 };
00091
00092 static struct ast_tcptls_session_args https_desc = {
00093 .accept_fd = -1,
00094 .master = AST_PTHREADT_NULL,
00095 .tls_cfg = &http_tls_cfg,
00096 .poll_timeout = -1,
00097 .name = "https server",
00098 .accept_fn = ast_tcptls_server_root,
00099 .worker_fn = httpd_helper_thread,
00100 };
00101
00102 static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri);
00103
00104
00105 static char prefix[MAX_PREFIX];
00106 static int enablestatic;
00107
00108
00109 static struct {
00110 const char *ext;
00111 const char *mtype;
00112 } mimetypes[] = {
00113 { "png", "image/png" },
00114 { "xml", "text/xml" },
00115 { "jpg", "image/jpeg" },
00116 { "js", "application/x-javascript" },
00117 { "wav", "audio/x-wav" },
00118 { "mp3", "audio/mpeg" },
00119 { "svg", "image/svg+xml" },
00120 { "svgz", "image/svg+xml" },
00121 { "gif", "image/gif" },
00122 { "html", "text/html" },
00123 { "htm", "text/html" },
00124 { "css", "text/css" },
00125 { "cnf", "text/plain" },
00126 { "cfg", "text/plain" },
00127 { "bin", "application/octet-stream" },
00128 { "sbn", "application/octet-stream" },
00129 { "ld", "application/octet-stream" },
00130 };
00131
00132 struct http_uri_redirect {
00133 AST_LIST_ENTRY(http_uri_redirect) entry;
00134 char *dest;
00135 char target[0];
00136 };
00137
00138 static AST_RWLIST_HEAD_STATIC(uri_redirects, http_uri_redirect);
00139
00140 static const struct ast_cfhttp_methods_text {
00141 enum ast_http_method method;
00142 const char *text;
00143 } ast_http_methods_text[] = {
00144 { AST_HTTP_UNKNOWN, "UNKNOWN" },
00145 { AST_HTTP_GET, "GET" },
00146 { AST_HTTP_POST, "POST" },
00147 { AST_HTTP_HEAD, "HEAD" },
00148 { AST_HTTP_PUT, "PUT" },
00149 };
00150
00151 const char *ast_get_http_method(enum ast_http_method method)
00152 {
00153 int x;
00154
00155 for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) {
00156 if (ast_http_methods_text[x].method == method) {
00157 return ast_http_methods_text[x].text;
00158 }
00159 }
00160
00161 return NULL;
00162 }
00163
00164 const char *ast_http_ftype2mtype(const char *ftype)
00165 {
00166 int x;
00167
00168 if (ftype) {
00169 for (x = 0; x < ARRAY_LEN(mimetypes); x++) {
00170 if (!strcasecmp(ftype, mimetypes[x].ext)) {
00171 return mimetypes[x].mtype;
00172 }
00173 }
00174 }
00175 return NULL;
00176 }
00177
00178 uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
00179 {
00180 uint32_t mngid = 0;
00181 struct ast_variable *v, *cookies;
00182
00183 cookies = ast_http_get_cookies(headers);
00184 for (v = cookies; v; v = v->next) {
00185 if (!strcasecmp(v->name, "mansession_id")) {
00186 sscanf(v->value, "%30x", &mngid);
00187 break;
00188 }
00189 }
00190 if (cookies) {
00191 ast_variables_destroy(cookies);
00192 }
00193 return mngid;
00194 }
00195
00196 void ast_http_prefix(char *buf, int len)
00197 {
00198 if (buf) {
00199 ast_copy_string(buf, prefix, len);
00200 }
00201 }
00202
00203 static int static_callback(struct ast_tcptls_session_instance *ser,
00204 const struct ast_http_uri *urih, const char *uri,
00205 enum ast_http_method method, struct ast_variable *get_vars,
00206 struct ast_variable *headers)
00207 {
00208 char *path;
00209 const char *ftype;
00210 const char *mtype;
00211 char wkspace[80];
00212 struct stat st;
00213 int len;
00214 int fd;
00215 struct ast_str *http_header;
00216 struct timeval tv;
00217 struct ast_tm tm;
00218 char timebuf[80], etag[23];
00219 struct ast_variable *v;
00220 int not_modified = 0;
00221
00222 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
00223 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
00224 return -1;
00225 }
00226
00227
00228
00229 if (!enablestatic || ast_strlen_zero(uri)) {
00230 goto out403;
00231 }
00232
00233
00234 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) {
00235 goto out403;
00236 }
00237
00238 if (strstr(uri, "/..")) {
00239 goto out403;
00240 }
00241
00242 if ((ftype = strrchr(uri, '.'))) {
00243 ftype++;
00244 }
00245
00246 if (!(mtype = ast_http_ftype2mtype(ftype))) {
00247 snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain"));
00248 }
00249
00250
00251 if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
00252 goto out403;
00253 }
00254
00255 path = ast_alloca(len);
00256 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00257 if (stat(path, &st)) {
00258 goto out404;
00259 }
00260
00261 if (S_ISDIR(st.st_mode)) {
00262 goto out404;
00263 }
00264
00265 fd = open(path, O_RDONLY);
00266 if (fd < 0) {
00267 goto out403;
00268 }
00269
00270 if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
00271 goto out403;
00272 }
00273
00274
00275 snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
00276
00277
00278 tv.tv_sec = st.st_mtime;
00279 tv.tv_usec = 0;
00280 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
00281
00282
00283 for (v = headers; v; v = v->next) {
00284 if (!strcasecmp(v->name, "If-None-Match")) {
00285 if (!strcasecmp(v->value, etag)) {
00286 not_modified = 1;
00287 }
00288 break;
00289 }
00290 }
00291
00292 if ( (http_header = ast_str_create(255)) == NULL) {
00293 return -1;
00294 }
00295
00296 ast_str_set(&http_header, 0, "Content-type: %s\r\n"
00297 "ETag: %s\r\n"
00298 "Last-Modified: %s\r\n",
00299 mtype,
00300 etag,
00301 timebuf);
00302
00303
00304 if (not_modified) {
00305 ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
00306 } else {
00307 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1);
00308 }
00309 close(fd);
00310 return 0;
00311
00312 out404:
00313 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00314 return -1;
00315
00316 out403:
00317 ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
00318 return -1;
00319 }
00320
00321 static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
00322 const struct ast_http_uri *urih, const char *uri,
00323 enum ast_http_method method, struct ast_variable *get_vars,
00324 struct ast_variable *headers)
00325 {
00326 struct ast_str *out;
00327 struct ast_variable *v, *cookies = NULL;
00328
00329 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
00330 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
00331 return -1;
00332 }
00333
00334 if ( (out = ast_str_create(512)) == NULL) {
00335 return -1;
00336 }
00337
00338 ast_str_append(&out, 0,
00339 "<title>Asterisk HTTP Status</title>\r\n"
00340 "<body bgcolor=\"#ffffff\">\r\n"
00341 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
00342 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n");
00343
00344 ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
00345 ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
00346 ast_sockaddr_stringify_addr(&http_desc.old_address));
00347 ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
00348 ast_sockaddr_stringify_port(&http_desc.old_address));
00349 if (http_tls_cfg.enabled) {
00350 ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
00351 ast_sockaddr_stringify_port(&https_desc.old_address));
00352 }
00353 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00354 for (v = get_vars; v; v = v->next) {
00355 ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00356 }
00357 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00358
00359 cookies = ast_http_get_cookies(headers);
00360 for (v = cookies; v; v = v->next) {
00361 ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00362 }
00363 ast_variables_destroy(cookies);
00364
00365 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");
00366 ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
00367 return 0;
00368 }
00369
00370 static struct ast_http_uri statusuri = {
00371 .callback = httpstatus_callback,
00372 .description = "Asterisk HTTP General Status",
00373 .uri = "httpstatus",
00374 .has_subtree = 0,
00375 .data = NULL,
00376 .key = __FILE__,
00377 };
00378
00379 static struct ast_http_uri staticuri = {
00380 .callback = static_callback,
00381 .description = "Asterisk HTTP Static Delivery",
00382 .uri = "static",
00383 .has_subtree = 1,
00384 .data = NULL,
00385 .key= __FILE__,
00386 };
00387
00388
00389
00390
00391 void ast_http_send(struct ast_tcptls_session_instance *ser,
00392 enum ast_http_method method, int status_code, const char *status_title,
00393 struct ast_str *http_header, struct ast_str *out, const int fd,
00394 unsigned int static_content)
00395 {
00396 struct timeval now = ast_tvnow();
00397 struct ast_tm tm;
00398 char timebuf[80];
00399 int content_length = 0;
00400
00401 if (!ser || 0 == ser->f) {
00402 return;
00403 }
00404
00405 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
00406
00407
00408 if (out) {
00409 content_length += strlen(ast_str_buffer(out));
00410 }
00411
00412 if (fd) {
00413 content_length += lseek(fd, 0, SEEK_END);
00414 lseek(fd, 0, SEEK_SET);
00415 }
00416
00417
00418 fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
00419 "Server: Asterisk/%s\r\n"
00420 "Date: %s\r\n"
00421 "Connection: close\r\n"
00422 "%s"
00423 "Content-Length: %d\r\n"
00424 "%s"
00425 "\r\n",
00426 status_code, status_title ? status_title : "OK",
00427 ast_get_version(),
00428 timebuf,
00429 static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
00430 content_length,
00431 http_header ? ast_str_buffer(http_header) : ""
00432 );
00433
00434
00435 if (method != AST_HTTP_HEAD || status_code >= 400) {
00436 if (out) {
00437 fprintf(ser->f, "%s", ast_str_buffer(out));
00438 }
00439
00440 if (fd) {
00441 char buf[256];
00442 int len;
00443 while ((len = read(fd, buf, sizeof(buf))) > 0) {
00444 if (fwrite(buf, len, 1, ser->f) != 1) {
00445 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00446 break;
00447 }
00448 }
00449 }
00450 }
00451
00452 if (http_header) {
00453 ast_free(http_header);
00454 }
00455 if (out) {
00456 ast_free(out);
00457 }
00458
00459 fclose(ser->f);
00460 ser->f = 0;
00461 return;
00462 }
00463
00464
00465 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
00466 const unsigned long nonce, const unsigned long opaque, int stale,
00467 const char *text)
00468 {
00469 struct ast_str *http_headers = ast_str_create(128);
00470 struct ast_str *out = ast_str_create(512);
00471
00472 if (!http_headers || !out) {
00473 ast_free(http_headers);
00474 ast_free(out);
00475 return;
00476 }
00477
00478 ast_str_set(&http_headers, 0,
00479 "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
00480 "Content-type: text/html\r\n",
00481 realm ? realm : "Asterisk",
00482 nonce,
00483 opaque,
00484 stale ? ", stale=true" : "");
00485
00486 ast_str_set(&out, 0,
00487 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00488 "<html><head>\r\n"
00489 "<title>401 Unauthorized</title>\r\n"
00490 "</head><body>\r\n"
00491 "<h1>401 Unauthorized</h1>\r\n"
00492 "<p>%s</p>\r\n"
00493 "<hr />\r\n"
00494 "<address>Asterisk Server</address>\r\n"
00495 "</body></html>\r\n",
00496 text ? text : "");
00497
00498 ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
00499 return;
00500 }
00501
00502
00503 void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
00504 {
00505 struct ast_str *http_headers = ast_str_create(40);
00506 struct ast_str *out = ast_str_create(256);
00507
00508 if (!http_headers || !out) {
00509 ast_free(http_headers);
00510 ast_free(out);
00511 return;
00512 }
00513
00514 ast_str_set(&http_headers, 0, "Content-type: text/html\r\n");
00515
00516 ast_str_set(&out, 0,
00517 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00518 "<html><head>\r\n"
00519 "<title>%d %s</title>\r\n"
00520 "</head><body>\r\n"
00521 "<h1>%s</h1>\r\n"
00522 "<p>%s</p>\r\n"
00523 "<hr />\r\n"
00524 "<address>Asterisk Server</address>\r\n"
00525 "</body></html>\r\n",
00526 status_code, status_title, status_title, text);
00527
00528 ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
00529 return;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 int ast_http_uri_link(struct ast_http_uri *urih)
00542 {
00543 struct ast_http_uri *uri;
00544 int len = strlen(urih->uri);
00545
00546 AST_RWLIST_WRLOCK(&uris);
00547
00548 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
00549 AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
00550 AST_RWLIST_UNLOCK(&uris);
00551 return 0;
00552 }
00553
00554 AST_RWLIST_TRAVERSE(&uris, uri, entry) {
00555 if (AST_RWLIST_NEXT(uri, entry) &&
00556 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
00557 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
00558 AST_RWLIST_UNLOCK(&uris);
00559
00560 return 0;
00561 }
00562 }
00563
00564 AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
00565
00566 AST_RWLIST_UNLOCK(&uris);
00567
00568 return 0;
00569 }
00570
00571 void ast_http_uri_unlink(struct ast_http_uri *urih)
00572 {
00573 AST_RWLIST_WRLOCK(&uris);
00574 AST_RWLIST_REMOVE(&uris, urih, entry);
00575 AST_RWLIST_UNLOCK(&uris);
00576 }
00577
00578 void ast_http_uri_unlink_all_with_key(const char *key)
00579 {
00580 struct ast_http_uri *urih;
00581 AST_RWLIST_WRLOCK(&uris);
00582 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) {
00583 if (!strcmp(urih->key, key)) {
00584 AST_RWLIST_REMOVE_CURRENT(entry);
00585 if (urih->dmallocd) {
00586 ast_free(urih->data);
00587 }
00588 if (urih->mallocd) {
00589 ast_free(urih);
00590 }
00591 }
00592 }
00593 AST_RWLIST_TRAVERSE_SAFE_END;
00594 AST_RWLIST_UNLOCK(&uris);
00595 }
00596
00597
00598
00599
00600
00601
00602 static void http_decode(char *s)
00603 {
00604 char *t;
00605
00606 for (t = s; *t; t++) {
00607 if (*t == '+') {
00608 *t = ' ';
00609 }
00610 }
00611
00612 ast_uri_decode(s);
00613 }
00614
00615
00616
00617
00618
00619 struct ast_variable *ast_http_get_post_vars(
00620 struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
00621 {
00622 int content_length = 0;
00623 struct ast_variable *v, *post_vars=NULL, *prev = NULL;
00624 char *buf, *var, *val;
00625
00626 for (v = headers; v; v = v->next) {
00627 if (!strcasecmp(v->name, "Content-Type")) {
00628 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
00629 return NULL;
00630 }
00631 break;
00632 }
00633 }
00634
00635 for (v = headers; v; v = v->next) {
00636 if (!strcasecmp(v->name, "Content-Length")) {
00637 content_length = atoi(v->value) + 1;
00638 break;
00639 }
00640 }
00641
00642 if (!content_length) {
00643 return NULL;
00644 }
00645
00646 buf = ast_alloca(content_length);
00647 if (!fgets(buf, content_length, ser->f)) {
00648 return NULL;
00649 }
00650
00651 while ((val = strsep(&buf, "&"))) {
00652 var = strsep(&val, "=");
00653 if (val) {
00654 http_decode(val);
00655 } else {
00656 val = "";
00657 }
00658 http_decode(var);
00659 if ((v = ast_variable_new(var, val, ""))) {
00660 if (post_vars) {
00661 prev->next = v;
00662 } else {
00663 post_vars = v;
00664 }
00665 prev = v;
00666 }
00667 }
00668 return post_vars;
00669 }
00670
00671 static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
00672 enum ast_http_method method, struct ast_variable *headers)
00673 {
00674 char *c;
00675 int res = -1;
00676 char *params = uri;
00677 struct ast_http_uri *urih = NULL;
00678 int l;
00679 struct ast_variable *get_vars = NULL, *v, *prev = NULL;
00680 struct http_uri_redirect *redirect;
00681
00682 ast_debug(2, "HTTP Request URI is %s \n", uri);
00683
00684 strsep(¶ms, "?");
00685
00686 if (params) {
00687 char *var, *val;
00688
00689 while ((val = strsep(¶ms, "&"))) {
00690 var = strsep(&val, "=");
00691 if (val) {
00692 http_decode(val);
00693 } else {
00694 val = "";
00695 }
00696 http_decode(var);
00697 if ((v = ast_variable_new(var, val, ""))) {
00698 if (get_vars) {
00699 prev->next = v;
00700 } else {
00701 get_vars = v;
00702 }
00703 prev = v;
00704 }
00705 }
00706 }
00707 http_decode(uri);
00708
00709 AST_RWLIST_RDLOCK(&uri_redirects);
00710 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
00711 if (!strcasecmp(uri, redirect->target)) {
00712 struct ast_str *http_header = ast_str_create(128);
00713 ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
00714 ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
00715
00716 break;
00717 }
00718 }
00719 AST_RWLIST_UNLOCK(&uri_redirects);
00720 if (redirect) {
00721 goto cleanup;
00722 }
00723
00724
00725 l = strlen(prefix);
00726 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
00727 uri += l + 1;
00728
00729 AST_RWLIST_RDLOCK(&uris);
00730 AST_RWLIST_TRAVERSE(&uris, urih, entry) {
00731 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
00732 l = strlen(urih->uri);
00733 c = uri + l;
00734 if (strncasecmp(urih->uri, uri, l)
00735 || (*c && *c != '/')) {
00736 continue;
00737 }
00738 if (*c == '/') {
00739 c++;
00740 }
00741 if (!*c || urih->has_subtree) {
00742 uri = c;
00743 break;
00744 }
00745 }
00746 AST_RWLIST_UNLOCK(&uris);
00747 }
00748 if (urih) {
00749 res = urih->callback(ser, urih, uri, method, get_vars, headers);
00750 } else {
00751 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00752 }
00753
00754 cleanup:
00755 ast_variables_destroy(get_vars);
00756 return res;
00757 }
00758
00759 #ifdef DO_SSL
00760 #if defined(HAVE_FUNOPEN)
00761 #define HOOK_T int
00762 #define LEN_T int
00763 #else
00764 #define HOOK_T ssize_t
00765 #define LEN_T size_t
00766 #endif
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 #endif
00803
00804 static struct ast_variable *parse_cookies(char *cookies)
00805 {
00806 char *cur;
00807 struct ast_variable *vars = NULL, *var;
00808
00809 while ((cur = strsep(&cookies, ";"))) {
00810 char *name, *val;
00811
00812 name = val = cur;
00813 strsep(&val, "=");
00814
00815 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00816 continue;
00817 }
00818
00819 name = ast_strip(name);
00820 val = ast_strip_quoted(val, "\"", "\"");
00821
00822 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00823 continue;
00824 }
00825
00826 ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val);
00827
00828 var = ast_variable_new(name, val, __FILE__);
00829 var->next = vars;
00830 vars = var;
00831 }
00832
00833 return vars;
00834 }
00835
00836
00837 struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
00838 {
00839 struct ast_variable *v, *cookies=NULL;
00840
00841 for (v = headers; v; v = v->next) {
00842 if (!strncasecmp(v->name, "Cookie", 6)) {
00843 char *tmp = ast_strdupa(v->value);
00844 if (cookies) {
00845 ast_variables_destroy(cookies);
00846 }
00847
00848 cookies = parse_cookies(tmp);
00849 }
00850 }
00851 return cookies;
00852 }
00853
00854
00855 static void *httpd_helper_thread(void *data)
00856 {
00857 char buf[4096];
00858 char header_line[4096];
00859 struct ast_tcptls_session_instance *ser = data;
00860 struct ast_variable *headers = NULL;
00861 struct ast_variable *tail = headers;
00862 char *uri, *method;
00863 enum ast_http_method http_method = AST_HTTP_UNKNOWN;
00864
00865 if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
00866 goto done;
00867 }
00868
00869 if (!fgets(buf, sizeof(buf), ser->f)) {
00870 goto done;
00871 }
00872
00873
00874 method = ast_skip_blanks(buf);
00875 uri = ast_skip_nonblanks(method);
00876 if (*uri) {
00877 *uri++ = '\0';
00878 }
00879
00880 if (!strcasecmp(method,"GET")) {
00881 http_method = AST_HTTP_GET;
00882 } else if (!strcasecmp(method,"POST")) {
00883 http_method = AST_HTTP_POST;
00884 } else if (!strcasecmp(method,"HEAD")) {
00885 http_method = AST_HTTP_HEAD;
00886 } else if (!strcasecmp(method,"PUT")) {
00887 http_method = AST_HTTP_PUT;
00888 }
00889
00890 uri = ast_skip_blanks(uri);
00891
00892 if (*uri) {
00893 char *c = ast_skip_nonblanks(uri);
00894
00895 if (*c) {
00896 *c = '\0';
00897 }
00898 }
00899
00900
00901 while (fgets(header_line, sizeof(header_line), ser->f)) {
00902 char *name, *value;
00903
00904
00905 ast_trim_blanks(header_line);
00906 if (ast_strlen_zero(header_line)) {
00907 break;
00908 }
00909
00910 value = header_line;
00911 name = strsep(&value, ":");
00912 if (!value) {
00913 continue;
00914 }
00915
00916 value = ast_skip_blanks(value);
00917 if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
00918 continue;
00919 }
00920
00921 ast_trim_blanks(name);
00922
00923 if (!headers) {
00924 headers = ast_variable_new(name, value, __FILE__);
00925 tail = headers;
00926 } else {
00927 tail->next = ast_variable_new(name, value, __FILE__);
00928 tail = tail->next;
00929 }
00930 }
00931
00932 if (!*uri) {
00933 ast_http_error(ser, 400, "Bad Request", "Invalid Request");
00934 goto done;
00935 }
00936
00937 handle_uri(ser, uri, http_method, headers);
00938
00939 done:
00940 ast_atomic_fetchadd_int(&session_count, -1);
00941
00942
00943 if (headers) {
00944 ast_variables_destroy(headers);
00945 }
00946
00947 if (ser->f) {
00948 fclose(ser->f);
00949 }
00950 ao2_ref(ser, -1);
00951 ser = NULL;
00952 return NULL;
00953 }
00954
00955
00956
00957
00958
00959
00960 static void add_redirect(const char *value)
00961 {
00962 char *target, *dest;
00963 struct http_uri_redirect *redirect, *cur;
00964 unsigned int target_len;
00965 unsigned int total_len;
00966
00967 dest = ast_strdupa(value);
00968 dest = ast_skip_blanks(dest);
00969 target = strsep(&dest, " ");
00970 target = ast_skip_blanks(target);
00971 target = strsep(&target, " ");
00972
00973 if (!dest) {
00974 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
00975 return;
00976 }
00977
00978 target_len = strlen(target) + 1;
00979 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
00980
00981 if (!(redirect = ast_calloc(1, total_len))) {
00982 return;
00983 }
00984 redirect->dest = redirect->target + target_len;
00985 strcpy(redirect->target, target);
00986 strcpy(redirect->dest, dest);
00987
00988 AST_RWLIST_WRLOCK(&uri_redirects);
00989
00990 target_len--;
00991 if (AST_RWLIST_EMPTY(&uri_redirects)
00992 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
00993 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
00994 AST_RWLIST_UNLOCK(&uri_redirects);
00995
00996 return;
00997 }
00998
00999 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
01000 if (AST_RWLIST_NEXT(cur, entry)
01001 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
01002 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
01003 AST_RWLIST_UNLOCK(&uri_redirects);
01004 return;
01005 }
01006 }
01007
01008 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
01009
01010 AST_RWLIST_UNLOCK(&uri_redirects);
01011 }
01012
01013 static int __ast_http_load(int reload)
01014 {
01015 struct ast_config *cfg;
01016 struct ast_variable *v;
01017 int enabled=0;
01018 int newenablestatic=0;
01019 struct hostent *hp;
01020 struct ast_hostent ahp;
01021 char newprefix[MAX_PREFIX] = "";
01022 struct http_uri_redirect *redirect;
01023 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01024 struct sockaddr_in tmp = {0,};
01025 struct sockaddr_in tmp2 = {0,};
01026 int http_tls_was_enabled = 0;
01027
01028 cfg = ast_config_load2("http.conf", "http", config_flags);
01029 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01030 return 0;
01031 }
01032
01033 http_tls_was_enabled = (reload && http_tls_cfg.enabled);
01034
01035 tmp.sin_family = AF_INET;
01036 tmp.sin_port = htons(DEFAULT_HTTP_PORT);
01037 ast_sockaddr_from_sin(&http_desc.local_address, &tmp);
01038
01039 http_tls_cfg.enabled = 0;
01040 if (http_tls_cfg.certfile) {
01041 ast_free(http_tls_cfg.certfile);
01042 }
01043 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
01044
01045 if (http_tls_cfg.pvtfile) {
01046 ast_free(http_tls_cfg.pvtfile);
01047 }
01048 http_tls_cfg.pvtfile = ast_strdup("");
01049
01050 if (http_tls_cfg.cipher) {
01051 ast_free(http_tls_cfg.cipher);
01052 }
01053 http_tls_cfg.cipher = ast_strdup("");
01054
01055 AST_RWLIST_WRLOCK(&uri_redirects);
01056 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01057 ast_free(redirect);
01058 }
01059 AST_RWLIST_UNLOCK(&uri_redirects);
01060
01061 ast_sockaddr_setnull(&https_desc.local_address);
01062
01063 if (cfg) {
01064 v = ast_variable_browse(cfg, "general");
01065 for (; v; v = v->next) {
01066
01067
01068 if (!ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
01069 continue;
01070 }
01071
01072 if (!strcasecmp(v->name, "enabled")) {
01073 enabled = ast_true(v->value);
01074 } else if (!strcasecmp(v->name, "enablestatic")) {
01075 newenablestatic = ast_true(v->value);
01076 } else if (!strcasecmp(v->name, "bindport")) {
01077 ast_sockaddr_set_port(&http_desc.local_address,
01078 atoi(v->value));
01079 } else if (!strcasecmp(v->name, "bindaddr")) {
01080 if ((hp = ast_gethostbyname(v->value, &ahp))) {
01081 ast_sockaddr_to_sin(&http_desc.local_address,
01082 &tmp);
01083 memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr));
01084 ast_sockaddr_from_sin(&http_desc.local_address,
01085 &tmp);
01086 } else {
01087 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
01088 }
01089 } else if (!strcasecmp(v->name, "prefix")) {
01090 if (!ast_strlen_zero(v->value)) {
01091 newprefix[0] = '/';
01092 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
01093 } else {
01094 newprefix[0] = '\0';
01095 }
01096 } else if (!strcasecmp(v->name, "redirect")) {
01097 add_redirect(v->value);
01098 } else if (!strcasecmp(v->name, "sessionlimit")) {
01099 if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
01100 &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
01101 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
01102 v->name, v->value, v->lineno);
01103 }
01104 } else {
01105 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
01106 }
01107 }
01108
01109 ast_config_destroy(cfg);
01110 }
01111
01112 ast_sockaddr_to_sin(&http_desc.local_address, &tmp);
01113 ast_sockaddr_to_sin(&https_desc.local_address, &tmp2);
01114 if (!tmp2.sin_addr.s_addr) {
01115 tmp2.sin_addr = tmp.sin_addr;
01116 }
01117 if (!tmp2.sin_port) {
01118 tmp2.sin_port = htons(DEFAULT_HTTPS_PORT);
01119 }
01120 ast_sockaddr_from_sin(&https_desc.local_address, &tmp2);
01121 if (!enabled) {
01122 ast_sockaddr_setnull(&http_desc.local_address);
01123 ast_sockaddr_setnull(&https_desc.local_address);
01124 }
01125 if (strcmp(prefix, newprefix)) {
01126 ast_copy_string(prefix, newprefix, sizeof(prefix));
01127 }
01128 enablestatic = newenablestatic;
01129 ast_tcptls_server_start(&http_desc);
01130
01131 if (http_tls_was_enabled && !http_tls_cfg.enabled) {
01132 ast_tcptls_server_stop(&https_desc);
01133 } else if (ast_ssl_setup(https_desc.tls_cfg)) {
01134 ast_tcptls_server_start(&https_desc);
01135 }
01136
01137 return 0;
01138 }
01139
01140 static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01141 {
01142 struct ast_http_uri *urih;
01143 struct http_uri_redirect *redirect;
01144 struct sockaddr_in tmp;
01145
01146 switch (cmd) {
01147 case CLI_INIT:
01148 e->command = "http show status";
01149 e->usage =
01150 "Usage: http show status\n"
01151 " Lists status of internal HTTP engine\n";
01152 return NULL;
01153 case CLI_GENERATE:
01154 return NULL;
01155 }
01156
01157 if (a->argc != 3) {
01158 return CLI_SHOWUSAGE;
01159 }
01160 ast_cli(a->fd, "HTTP Server Status:\n");
01161 ast_cli(a->fd, "Prefix: %s\n", prefix);
01162 ast_sockaddr_to_sin(&http_desc.old_address, &tmp);
01163 if (!tmp.sin_family) {
01164 ast_cli(a->fd, "Server Disabled\n\n");
01165 } else {
01166 ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n",
01167 ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port));
01168 if (http_tls_cfg.enabled) {
01169 ast_sockaddr_to_sin(&https_desc.old_address, &tmp);
01170 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
01171 ast_inet_ntoa(tmp.sin_addr),
01172 ntohs(tmp.sin_port));
01173 }
01174 }
01175
01176 ast_cli(a->fd, "Enabled URI's:\n");
01177 AST_RWLIST_RDLOCK(&uris);
01178 if (AST_RWLIST_EMPTY(&uris)) {
01179 ast_cli(a->fd, "None.\n");
01180 } else {
01181 AST_RWLIST_TRAVERSE(&uris, urih, entry)
01182 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
01183 }
01184 AST_RWLIST_UNLOCK(&uris);
01185
01186 ast_cli(a->fd, "\nEnabled Redirects:\n");
01187 AST_RWLIST_RDLOCK(&uri_redirects);
01188 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
01189 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
01190 if (AST_RWLIST_EMPTY(&uri_redirects)) {
01191 ast_cli(a->fd, " None.\n");
01192 }
01193 AST_RWLIST_UNLOCK(&uri_redirects);
01194
01195 return CLI_SUCCESS;
01196 }
01197
01198 int ast_http_reload(void)
01199 {
01200 return __ast_http_load(1);
01201 }
01202
01203 static struct ast_cli_entry cli_http[] = {
01204 AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
01205 };
01206
01207 int ast_http_init(void)
01208 {
01209 ast_http_uri_link(&statusuri);
01210 ast_http_uri_link(&staticuri);
01211 ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
01212
01213 return __ast_http_load(0);
01214 }