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 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 134983 $")
00034
00035 #include <sys/types.h>
00036 #include <stdio.h>
00037 #include <unistd.h>
00038 #include <stdlib.h>
00039 #include <time.h>
00040 #include <string.h>
00041 #include <netinet/in.h>
00042 #include <sys/time.h>
00043 #include <sys/socket.h>
00044 #include <sys/stat.h>
00045 #include <sys/signal.h>
00046 #include <arpa/inet.h>
00047 #include <errno.h>
00048 #include <fcntl.h>
00049 #include <pthread.h>
00050
00051 #include "asterisk/cli.h"
00052 #include "asterisk/http.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/strings.h"
00055 #include "asterisk/options.h"
00056 #include "asterisk/config.h"
00057 #include "asterisk/version.h"
00058 #include "asterisk/manager.h"
00059
00060 #define MAX_PREFIX 80
00061 #define DEFAULT_PREFIX "/asterisk"
00062
00063 struct ast_http_server_instance {
00064 FILE *f;
00065 int fd;
00066 struct sockaddr_in requestor;
00067 ast_http_callback callback;
00068 };
00069
00070 AST_RWLOCK_DEFINE_STATIC(uris_lock);
00071 static struct ast_http_uri *uris;
00072
00073 static int httpfd = -1;
00074 static pthread_t master = AST_PTHREADT_NULL;
00075 static char prefix[MAX_PREFIX];
00076 static int prefix_len;
00077 static struct sockaddr_in oldsin;
00078 static int enablestatic;
00079
00080
00081 static struct {
00082 const char *ext;
00083 const char *mtype;
00084 } mimetypes[] = {
00085 { "png", "image/png" },
00086 { "jpg", "image/jpeg" },
00087 { "js", "application/x-javascript" },
00088 { "wav", "audio/x-wav" },
00089 { "mp3", "audio/mpeg" },
00090 { "svg", "image/svg+xml" },
00091 { "svgz", "image/svg+xml" },
00092 { "gif", "image/gif" },
00093 };
00094
00095 static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
00096 {
00097 int x;
00098 if (ftype) {
00099 for (x=0;x<sizeof(mimetypes) / sizeof(mimetypes[0]); x++) {
00100 if (!strcasecmp(ftype, mimetypes[x].ext))
00101 return mimetypes[x].mtype;
00102 }
00103 }
00104 snprintf(wkspace, wkspacelen, "text/%s", ftype ? ftype : "plain");
00105 return wkspace;
00106 }
00107
00108 static char *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
00109 {
00110 char result[4096];
00111 char *c=result;
00112 char *path;
00113 char *ftype;
00114 const char *mtype;
00115 char wkspace[80];
00116 struct stat st;
00117 int len;
00118 int fd;
00119 void *blob;
00120
00121
00122
00123 if (!enablestatic || ast_strlen_zero(uri))
00124 goto out403;
00125
00126 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0]))
00127 goto out403;
00128 if (strstr(uri, "/.."))
00129 goto out403;
00130
00131 if ((ftype = strrchr(uri, '.')))
00132 ftype++;
00133 mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace));
00134
00135
00136 len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5;
00137 if (len > 1024)
00138 goto out403;
00139
00140 path = alloca(len);
00141 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00142 if (stat(path, &st))
00143 goto out404;
00144 if (S_ISDIR(st.st_mode))
00145 goto out404;
00146 fd = open(path, O_RDONLY);
00147 if (fd < 0)
00148 goto out403;
00149
00150 len = st.st_size + strlen(mtype) + 40;
00151
00152 blob = malloc(len);
00153 if (blob) {
00154 c = blob;
00155 sprintf(c, "Content-type: %s\r\n\r\n", mtype);
00156 c += strlen(c);
00157 *contentlength = read(fd, c, st.st_size);
00158 if (*contentlength < 0) {
00159 close(fd);
00160 free(blob);
00161 goto out403;
00162 }
00163 }
00164 close(fd);
00165 return blob;
00166
00167 out404:
00168 *status = 404;
00169 *title = strdup("Not Found");
00170 return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
00171
00172 out403:
00173 *status = 403;
00174 *title = strdup("Access Denied");
00175 return ast_http_error(403, "Access Denied", NULL, "You do not have permission to access the requested URL.");
00176 }
00177
00178
00179 static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
00180 {
00181 char result[4096];
00182 size_t reslen = sizeof(result);
00183 char *c=result;
00184 struct ast_variable *v;
00185
00186 ast_build_string(&c, &reslen,
00187 "\r\n"
00188 "<title>Asterisk HTTP Status</title>\r\n"
00189 "<body bgcolor=\"#ffffff\">\r\n"
00190 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
00191 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n");
00192
00193 ast_build_string(&c, &reslen, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
00194 ast_build_string(&c, &reslen, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
00195 ast_inet_ntoa(oldsin.sin_addr));
00196 ast_build_string(&c, &reslen, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
00197 ntohs(oldsin.sin_port));
00198 ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00199 v = vars;
00200 while(v) {
00201 if (strncasecmp(v->name, "cookie_", 7))
00202 ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00203 v = v->next;
00204 }
00205 ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00206 v = vars;
00207 while(v) {
00208 if (!strncasecmp(v->name, "cookie_", 7))
00209 ast_build_string(&c, &reslen, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00210 v = v->next;
00211 }
00212 ast_build_string(&c, &reslen, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
00213 return strdup(result);
00214 }
00215
00216 static struct ast_http_uri statusuri = {
00217 .callback = httpstatus_callback,
00218 .description = "Asterisk HTTP General Status",
00219 .uri = "httpstatus",
00220 .has_subtree = 0,
00221 };
00222
00223 static struct ast_http_uri staticuri = {
00224 .callback = static_callback,
00225 .description = "Asterisk HTTP Static Delivery",
00226 .uri = "static",
00227 .has_subtree = 1,
00228 .static_content = 1,
00229 };
00230
00231 char *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
00232 {
00233 char *c = NULL;
00234 asprintf(&c,
00235 "Content-type: text/html\r\n"
00236 "%s"
00237 "\r\n"
00238 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00239 "<html><head>\r\n"
00240 "<title>%d %s</title>\r\n"
00241 "</head><body>\r\n"
00242 "<h1>%s</h1>\r\n"
00243 "<p>%s</p>\r\n"
00244 "<hr />\r\n"
00245 "<address>Asterisk Server</address>\r\n"
00246 "</body></html>\r\n",
00247 (extra_header ? extra_header : ""), status, title, title, text);
00248 return c;
00249 }
00250
00251 int ast_http_uri_link(struct ast_http_uri *urih)
00252 {
00253 struct ast_http_uri *prev;
00254
00255 ast_rwlock_wrlock(&uris_lock);
00256 prev = uris;
00257 if (!uris || strlen(uris->uri) <= strlen(urih->uri)) {
00258 urih->next = uris;
00259 uris = urih;
00260 } else {
00261 while (prev->next && (strlen(prev->next->uri) > strlen(urih->uri)))
00262 prev = prev->next;
00263
00264 urih->next = prev->next;
00265 prev->next = urih;
00266 }
00267 ast_rwlock_unlock(&uris_lock);
00268
00269 return 0;
00270 }
00271
00272 void ast_http_uri_unlink(struct ast_http_uri *urih)
00273 {
00274 struct ast_http_uri *prev;
00275
00276 ast_rwlock_wrlock(&uris_lock);
00277 if (!uris) {
00278 ast_rwlock_unlock(&uris_lock);
00279 return;
00280 }
00281 prev = uris;
00282 if (uris == urih) {
00283 uris = uris->next;
00284 }
00285 while(prev->next) {
00286 if (prev->next == urih) {
00287 prev->next = urih->next;
00288 break;
00289 }
00290 prev = prev->next;
00291 }
00292 ast_rwlock_unlock(&uris_lock);
00293 }
00294
00295 static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status,
00296 char **title, int *contentlength, struct ast_variable **cookies,
00297 unsigned int *static_content)
00298 {
00299 char *c;
00300 char *turi;
00301 char *params;
00302 char *var;
00303 char *val;
00304 struct ast_http_uri *urih=NULL;
00305 int len;
00306 struct ast_variable *vars=NULL, *v, *prev = NULL;
00307
00308
00309 params = strchr(uri, '?');
00310 if (params) {
00311 *params = '\0';
00312 params++;
00313 while ((var = strsep(¶ms, "&"))) {
00314 val = strchr(var, '=');
00315 if (val) {
00316 *val = '\0';
00317 val++;
00318 ast_uri_decode(val);
00319 } else
00320 val = "";
00321 ast_uri_decode(var);
00322 if ((v = ast_variable_new(var, val))) {
00323 if (vars)
00324 prev->next = v;
00325 else
00326 vars = v;
00327 prev = v;
00328 }
00329 }
00330 }
00331 if (prev)
00332 prev->next = *cookies;
00333 else
00334 vars = *cookies;
00335 *cookies = NULL;
00336 ast_uri_decode(uri);
00337 if (!strncasecmp(uri, prefix, prefix_len)) {
00338 uri += prefix_len;
00339 if (!*uri || (*uri == '/')) {
00340 if (*uri == '/')
00341 uri++;
00342 ast_rwlock_rdlock(&uris_lock);
00343 urih = uris;
00344 while(urih) {
00345 len = strlen(urih->uri);
00346 if (!strncasecmp(urih->uri, uri, len)) {
00347 if (!uri[len] || uri[len] == '/') {
00348 turi = uri + len;
00349 if (*turi == '/')
00350 turi++;
00351 if (!*turi || urih->has_subtree) {
00352 uri = turi;
00353 break;
00354 }
00355 }
00356 }
00357 urih = urih->next;
00358 }
00359 if (!urih)
00360 ast_rwlock_unlock(&uris_lock);
00361 }
00362 }
00363 if (urih) {
00364 if (urih->static_content)
00365 *static_content = 1;
00366 c = urih->callback(sin, uri, vars, status, title, contentlength);
00367 ast_rwlock_unlock(&uris_lock);
00368 } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
00369
00370 c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "Redirecting to /static/index.html.");
00371 *status = 302;
00372 *title = strdup("Moved Temporarily");
00373 } else {
00374 c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
00375 *status = 404;
00376 *title = strdup("Not Found");
00377 }
00378 ast_variables_destroy(vars);
00379 return c;
00380 }
00381
00382 static struct ast_variable *parse_cookies(char *cookies)
00383 {
00384 char *cur;
00385 struct ast_variable *vars = NULL, *var;
00386
00387
00388 cookies += 8;
00389
00390 while ((cur = strsep(&cookies, ";"))) {
00391 char *name, *val;
00392
00393 name = val = cur;
00394 strsep(&val, "=");
00395
00396 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00397 continue;
00398 }
00399
00400 name = ast_strip(name);
00401 val = ast_strip_quoted(val, "\"", "\"");
00402
00403 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00404 continue;
00405 }
00406
00407 if (option_debug) {
00408 ast_log(LOG_DEBUG, "mmm ... cookie! Name: '%s' Value: '%s'\n", name, val);
00409 }
00410
00411 var = ast_variable_new(name, val);
00412 var->next = vars;
00413 vars = var;
00414 }
00415
00416 return vars;
00417 }
00418
00419 static void *ast_httpd_helper_thread(void *data)
00420 {
00421 char buf[4096];
00422 char cookie[4096];
00423 char timebuf[256];
00424 struct ast_http_server_instance *ser = data;
00425 struct ast_variable *vars = NULL;
00426 char *uri, *c, *title=NULL;
00427 int status = 200, contentlength = 0;
00428 time_t t;
00429 unsigned int static_content = 0;
00430
00431 if (fgets(buf, sizeof(buf), ser->f)) {
00432
00433 uri = buf;
00434 while(*uri && (*uri > 32))
00435 uri++;
00436 if (*uri) {
00437 *uri = '\0';
00438 uri++;
00439 }
00440
00441
00442 while (*uri && (*uri < 33))
00443 uri++;
00444
00445 if (*uri) {
00446 c = uri;
00447 while (*c && (*c > 32))
00448 c++;
00449 if (*c) {
00450 *c = '\0';
00451 }
00452 }
00453
00454 while (fgets(cookie, sizeof(cookie), ser->f)) {
00455
00456 while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) {
00457 cookie[strlen(cookie) - 1] = '\0';
00458 }
00459 if (ast_strlen_zero(cookie))
00460 break;
00461 if (!strncasecmp(cookie, "Cookie: ", 8)) {
00462 vars = parse_cookies(cookie);
00463 }
00464 }
00465
00466 if (*uri) {
00467 if (!strcasecmp(buf, "get"))
00468 c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content);
00469 else
00470 c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\
00471 } else
00472 c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
00473
00474
00475 if (vars)
00476 ast_variables_destroy(vars);
00477
00478 if (!c)
00479 c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
00480 if (c) {
00481 time(&t);
00482 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00483 ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
00484 ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION);
00485 ast_cli(ser->fd, "Date: %s\r\n", timebuf);
00486 ast_cli(ser->fd, "Connection: close\r\n");
00487 if (!static_content)
00488 ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n");
00489
00490
00491
00492
00493
00494 if (contentlength) {
00495 char *tmp;
00496 tmp = strstr(c, "\r\n\r\n");
00497 if (tmp) {
00498 ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
00499 write(ser->fd, c, (tmp + 4 - c));
00500 write(ser->fd, tmp + 4, contentlength);
00501 }
00502 } else
00503 ast_cli(ser->fd, "%s", c);
00504 free(c);
00505 }
00506 if (title)
00507 free(title);
00508 }
00509 fclose(ser->f);
00510 free(ser);
00511 return NULL;
00512 }
00513
00514 static void *http_root(void *data)
00515 {
00516 int fd;
00517 struct sockaddr_in sin;
00518 socklen_t sinlen;
00519 struct ast_http_server_instance *ser;
00520 pthread_t launched;
00521 pthread_attr_t attr;
00522
00523 for (;;) {
00524 int flags;
00525
00526 ast_wait_for_input(httpfd, -1);
00527 sinlen = sizeof(sin);
00528 fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
00529 if (fd < 0) {
00530 if ((errno != EAGAIN) && (errno != EINTR))
00531 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
00532 continue;
00533 }
00534 ser = ast_calloc(1, sizeof(*ser));
00535 if (!ser) {
00536 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
00537 close(fd);
00538 continue;
00539 }
00540 flags = fcntl(fd, F_GETFL);
00541 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
00542 ser->fd = fd;
00543 memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
00544 if ((ser->f = fdopen(ser->fd, "w+"))) {
00545 pthread_attr_init(&attr);
00546 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00547
00548 if (ast_pthread_create_background(&launched, &attr, ast_httpd_helper_thread, ser)) {
00549 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
00550 fclose(ser->f);
00551 free(ser);
00552 }
00553 pthread_attr_destroy(&attr);
00554 } else {
00555 ast_log(LOG_WARNING, "fdopen failed!\n");
00556 close(ser->fd);
00557 free(ser);
00558 }
00559 }
00560 return NULL;
00561 }
00562
00563 char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, size_t buflen)
00564 {
00565 char *c;
00566 c = buf;
00567 ast_build_string(&c, &buflen, "Set-Cookie: %s=\"%s\"; Version=\"1\"", var, val);
00568 if (expires)
00569 ast_build_string(&c, &buflen, "; Max-Age=%d", expires);
00570 ast_build_string(&c, &buflen, "\r\n");
00571 return buf;
00572 }
00573
00574
00575 static void http_server_start(struct sockaddr_in *sin)
00576 {
00577 int flags;
00578 int x = 1;
00579
00580
00581 if (!memcmp(&oldsin, sin, sizeof(oldsin))) {
00582 ast_log(LOG_DEBUG, "Nothing changed in http\n");
00583 return;
00584 }
00585
00586 memcpy(&oldsin, sin, sizeof(oldsin));
00587
00588
00589 if (master != AST_PTHREADT_NULL) {
00590 pthread_cancel(master);
00591 pthread_kill(master, SIGURG);
00592 pthread_join(master, NULL);
00593 }
00594
00595 if (httpfd != -1)
00596 close(httpfd);
00597
00598
00599 if (!sin->sin_family)
00600 return;
00601
00602
00603 httpfd = socket(AF_INET, SOCK_STREAM, 0);
00604 if (httpfd < 0) {
00605 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00606 return;
00607 }
00608
00609 setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00610 if (bind(httpfd, (struct sockaddr *)sin, sizeof(*sin))) {
00611 ast_log(LOG_NOTICE, "Unable to bind http server to %s:%d: %s\n",
00612 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00613 strerror(errno));
00614 close(httpfd);
00615 httpfd = -1;
00616 return;
00617 }
00618 if (listen(httpfd, 10)) {
00619 ast_log(LOG_NOTICE, "Unable to listen!\n");
00620 close(httpfd);
00621 httpfd = -1;
00622 return;
00623 }
00624 flags = fcntl(httpfd, F_GETFL);
00625 fcntl(httpfd, F_SETFL, flags | O_NONBLOCK);
00626 if (ast_pthread_create_background(&master, NULL, http_root, NULL)) {
00627 ast_log(LOG_NOTICE, "Unable to launch http server on %s:%d: %s\n",
00628 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00629 strerror(errno));
00630 close(httpfd);
00631 httpfd = -1;
00632 }
00633 }
00634
00635 static int __ast_http_load(int reload)
00636 {
00637 struct ast_config *cfg;
00638 struct ast_variable *v;
00639 int enabled=0;
00640 int newenablestatic=0;
00641 struct sockaddr_in sin;
00642 struct hostent *hp;
00643 struct ast_hostent ahp;
00644 char newprefix[MAX_PREFIX];
00645
00646 memset(&sin, 0, sizeof(sin));
00647 sin.sin_port = htons(8088);
00648
00649 strcpy(newprefix, DEFAULT_PREFIX);
00650
00651 cfg = ast_config_load("http.conf");
00652 if (cfg) {
00653 v = ast_variable_browse(cfg, "general");
00654 while(v) {
00655 if (!strcasecmp(v->name, "enabled"))
00656 enabled = ast_true(v->value);
00657 else if (!strcasecmp(v->name, "enablestatic"))
00658 newenablestatic = ast_true(v->value);
00659 else if (!strcasecmp(v->name, "bindport"))
00660 sin.sin_port = ntohs(atoi(v->value));
00661 else if (!strcasecmp(v->name, "bindaddr")) {
00662 if ((hp = ast_gethostbyname(v->value, &ahp))) {
00663 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00664 } else {
00665 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
00666 }
00667 } else if (!strcasecmp(v->name, "prefix")) {
00668 if (!ast_strlen_zero(v->value)) {
00669 newprefix[0] = '/';
00670 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
00671 } else {
00672 newprefix[0] = '\0';
00673 }
00674
00675 }
00676 v = v->next;
00677 }
00678 ast_config_destroy(cfg);
00679 }
00680 if (enabled)
00681 sin.sin_family = AF_INET;
00682 if (strcmp(prefix, newprefix)) {
00683 ast_copy_string(prefix, newprefix, sizeof(prefix));
00684 prefix_len = strlen(prefix);
00685 }
00686 enablestatic = newenablestatic;
00687
00688 http_server_start(&sin);
00689
00690
00691 return 0;
00692 }
00693
00694 static int handle_show_http(int fd, int argc, char *argv[])
00695 {
00696 struct ast_http_uri *urih;
00697
00698 if (argc != 3)
00699 return RESULT_SHOWUSAGE;
00700
00701 ast_cli(fd, "HTTP Server Status:\n");
00702 ast_cli(fd, "Prefix: %s\n", prefix);
00703 if (oldsin.sin_family)
00704 ast_cli(fd, "Server Enabled and Bound to %s:%d\n\n",
00705 ast_inet_ntoa(oldsin.sin_addr),
00706 ntohs(oldsin.sin_port));
00707 else
00708 ast_cli(fd, "Server Disabled\n\n");
00709 ast_cli(fd, "Enabled URI's:\n");
00710 ast_rwlock_rdlock(&uris_lock);
00711 urih = uris;
00712 while(urih){
00713 ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
00714 urih = urih->next;
00715 }
00716 if (!uris)
00717 ast_cli(fd, "None.\n");
00718 ast_rwlock_unlock(&uris_lock);
00719
00720 return RESULT_SUCCESS;
00721 }
00722
00723 int ast_http_reload(void)
00724 {
00725 return __ast_http_load(1);
00726 }
00727
00728 static char show_http_help[] =
00729 "Usage: http show status\n"
00730 " Lists status of internal HTTP engine\n";
00731
00732 static struct ast_cli_entry cli_http[] = {
00733 { { "http", "show", "status", NULL },
00734 handle_show_http, "Display HTTP server status",
00735 show_http_help },
00736 };
00737
00738 int ast_http_init(void)
00739 {
00740 ast_http_uri_link(&statusuri);
00741 ast_http_uri_link(&staticuri);
00742 ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));
00743
00744 return __ast_http_load(0);
00745 }