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: 62414 $")
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, "Nothing to see here. Move along.");
00171
00172 out403:
00173 *status = 403;
00174 *title = strdup("Access Denied");
00175 return ast_http_error(403, "Access Denied", NULL, "Sorry, I cannot let you do that, Dave.");
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", "This is not the page you are looking for...");
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 void *ast_httpd_helper_thread(void *data)
00383 {
00384 char buf[4096];
00385 char cookie[4096];
00386 char timebuf[256];
00387 struct ast_http_server_instance *ser = data;
00388 struct ast_variable *var, *prev=NULL, *vars=NULL;
00389 char *uri, *c, *title=NULL;
00390 char *vname, *vval;
00391 int status = 200, contentlength = 0;
00392 time_t t;
00393 unsigned int static_content = 0;
00394
00395 if (fgets(buf, sizeof(buf), ser->f)) {
00396
00397 uri = buf;
00398 while(*uri && (*uri > 32))
00399 uri++;
00400 if (*uri) {
00401 *uri = '\0';
00402 uri++;
00403 }
00404
00405
00406 while (*uri && (*uri < 33))
00407 uri++;
00408
00409 if (*uri) {
00410 c = uri;
00411 while (*c && (*c > 32))
00412 c++;
00413 if (*c) {
00414 *c = '\0';
00415 }
00416 }
00417
00418 while (fgets(cookie, sizeof(cookie), ser->f)) {
00419
00420 while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) {
00421 cookie[strlen(cookie) - 1] = '\0';
00422 }
00423 if (ast_strlen_zero(cookie))
00424 break;
00425 if (!strncasecmp(cookie, "Cookie: ", 8)) {
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 vname = cookie + 8;
00441
00442
00443
00444 if (*vname == '$') {
00445 vname = strchr(vname, ';');
00446 if (vname) {
00447 vname++;
00448 if (*vname == ' ')
00449 vname++;
00450 }
00451 }
00452
00453 if (vname) {
00454 vval = strchr(vname, '=');
00455 if (vval) {
00456
00457 *vval++ = '\0';
00458 if (*vval)
00459 vval++;
00460 if (strlen(vval))
00461 vval[strlen(vval) - 1] = '\0';
00462 var = ast_variable_new(vname, vval);
00463 if (var) {
00464 if (prev)
00465 prev->next = var;
00466 else
00467 vars = var;
00468 prev = var;
00469 }
00470 }
00471 }
00472 }
00473 }
00474
00475 if (*uri) {
00476 if (!strcasecmp(buf, "get"))
00477 c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content);
00478 else
00479 c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\
00480 } else
00481 c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
00482
00483
00484 if (vars)
00485 ast_variables_destroy(vars);
00486
00487 if (!c)
00488 c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
00489 if (c) {
00490 time(&t);
00491 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00492 ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
00493 ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION);
00494 ast_cli(ser->fd, "Date: %s\r\n", timebuf);
00495 ast_cli(ser->fd, "Connection: close\r\n");
00496 if (!static_content)
00497 ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n");
00498 if (contentlength) {
00499 char *tmp;
00500 tmp = strstr(c, "\r\n\r\n");
00501 if (tmp) {
00502 ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
00503 write(ser->fd, c, (tmp + 4 - c));
00504 write(ser->fd, tmp + 4, contentlength);
00505 }
00506 } else
00507 ast_cli(ser->fd, "%s", c);
00508 free(c);
00509 }
00510 if (title)
00511 free(title);
00512 }
00513 fclose(ser->f);
00514 free(ser);
00515 return NULL;
00516 }
00517
00518 static void *http_root(void *data)
00519 {
00520 int fd;
00521 struct sockaddr_in sin;
00522 socklen_t sinlen;
00523 struct ast_http_server_instance *ser;
00524 pthread_t launched;
00525 pthread_attr_t attr;
00526
00527 for (;;) {
00528 int flags;
00529
00530 ast_wait_for_input(httpfd, -1);
00531 sinlen = sizeof(sin);
00532 fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
00533 if (fd < 0) {
00534 if ((errno != EAGAIN) && (errno != EINTR))
00535 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
00536 continue;
00537 }
00538 ser = ast_calloc(1, sizeof(*ser));
00539 if (!ser) {
00540 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
00541 close(fd);
00542 continue;
00543 }
00544 flags = fcntl(fd, F_GETFL);
00545 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
00546 ser->fd = fd;
00547 memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
00548 if ((ser->f = fdopen(ser->fd, "w+"))) {
00549 pthread_attr_init(&attr);
00550 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00551
00552 if (ast_pthread_create_background(&launched, &attr, ast_httpd_helper_thread, ser)) {
00553 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
00554 fclose(ser->f);
00555 free(ser);
00556 }
00557 pthread_attr_destroy(&attr);
00558 } else {
00559 ast_log(LOG_WARNING, "fdopen failed!\n");
00560 close(ser->fd);
00561 free(ser);
00562 }
00563 }
00564 return NULL;
00565 }
00566
00567 char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, size_t buflen)
00568 {
00569 char *c;
00570 c = buf;
00571 ast_build_string(&c, &buflen, "Set-Cookie: %s=\"%s\"; Version=\"1\"", var, val);
00572 if (expires)
00573 ast_build_string(&c, &buflen, "; Max-Age=%d", expires);
00574 ast_build_string(&c, &buflen, "\r\n");
00575 return buf;
00576 }
00577
00578
00579 static void http_server_start(struct sockaddr_in *sin)
00580 {
00581 int flags;
00582 int x = 1;
00583
00584
00585 if (!memcmp(&oldsin, sin, sizeof(oldsin))) {
00586 ast_log(LOG_DEBUG, "Nothing changed in http\n");
00587 return;
00588 }
00589
00590 memcpy(&oldsin, sin, sizeof(oldsin));
00591
00592
00593 if (master != AST_PTHREADT_NULL) {
00594 pthread_cancel(master);
00595 pthread_kill(master, SIGURG);
00596 pthread_join(master, NULL);
00597 }
00598
00599 if (httpfd != -1)
00600 close(httpfd);
00601
00602
00603 if (!sin->sin_family)
00604 return;
00605
00606
00607 httpfd = socket(AF_INET, SOCK_STREAM, 0);
00608 if (httpfd < 0) {
00609 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00610 return;
00611 }
00612
00613 setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00614 if (bind(httpfd, (struct sockaddr *)sin, sizeof(*sin))) {
00615 ast_log(LOG_NOTICE, "Unable to bind http server to %s:%d: %s\n",
00616 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00617 strerror(errno));
00618 close(httpfd);
00619 httpfd = -1;
00620 return;
00621 }
00622 if (listen(httpfd, 10)) {
00623 ast_log(LOG_NOTICE, "Unable to listen!\n");
00624 close(httpfd);
00625 httpfd = -1;
00626 return;
00627 }
00628 flags = fcntl(httpfd, F_GETFL);
00629 fcntl(httpfd, F_SETFL, flags | O_NONBLOCK);
00630 if (ast_pthread_create_background(&master, NULL, http_root, NULL)) {
00631 ast_log(LOG_NOTICE, "Unable to launch http server on %s:%d: %s\n",
00632 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00633 strerror(errno));
00634 close(httpfd);
00635 httpfd = -1;
00636 }
00637 }
00638
00639 static int __ast_http_load(int reload)
00640 {
00641 struct ast_config *cfg;
00642 struct ast_variable *v;
00643 int enabled=0;
00644 int newenablestatic=0;
00645 struct sockaddr_in sin;
00646 struct hostent *hp;
00647 struct ast_hostent ahp;
00648 char newprefix[MAX_PREFIX];
00649
00650 memset(&sin, 0, sizeof(sin));
00651 sin.sin_port = htons(8088);
00652
00653 strcpy(newprefix, DEFAULT_PREFIX);
00654
00655 cfg = ast_config_load("http.conf");
00656 if (cfg) {
00657 v = ast_variable_browse(cfg, "general");
00658 while(v) {
00659 if (!strcasecmp(v->name, "enabled"))
00660 enabled = ast_true(v->value);
00661 else if (!strcasecmp(v->name, "enablestatic"))
00662 newenablestatic = ast_true(v->value);
00663 else if (!strcasecmp(v->name, "bindport"))
00664 sin.sin_port = ntohs(atoi(v->value));
00665 else if (!strcasecmp(v->name, "bindaddr")) {
00666 if ((hp = ast_gethostbyname(v->value, &ahp))) {
00667 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00668 } else {
00669 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
00670 }
00671 } else if (!strcasecmp(v->name, "prefix")) {
00672 if (!ast_strlen_zero(v->value)) {
00673 newprefix[0] = '/';
00674 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
00675 } else {
00676 newprefix[0] = '\0';
00677 }
00678
00679 }
00680 v = v->next;
00681 }
00682 ast_config_destroy(cfg);
00683 }
00684 if (enabled)
00685 sin.sin_family = AF_INET;
00686 if (strcmp(prefix, newprefix)) {
00687 ast_copy_string(prefix, newprefix, sizeof(prefix));
00688 prefix_len = strlen(prefix);
00689 }
00690 enablestatic = newenablestatic;
00691
00692 http_server_start(&sin);
00693
00694
00695 return 0;
00696 }
00697
00698 static int handle_show_http(int fd, int argc, char *argv[])
00699 {
00700 struct ast_http_uri *urih;
00701
00702 if (argc != 3)
00703 return RESULT_SHOWUSAGE;
00704
00705 ast_cli(fd, "HTTP Server Status:\n");
00706 ast_cli(fd, "Prefix: %s\n", prefix);
00707 if (oldsin.sin_family)
00708 ast_cli(fd, "Server Enabled and Bound to %s:%d\n\n",
00709 ast_inet_ntoa(oldsin.sin_addr),
00710 ntohs(oldsin.sin_port));
00711 else
00712 ast_cli(fd, "Server Disabled\n\n");
00713 ast_cli(fd, "Enabled URI's:\n");
00714 ast_rwlock_rdlock(&uris_lock);
00715 urih = uris;
00716 while(urih){
00717 ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
00718 urih = urih->next;
00719 }
00720 if (!uris)
00721 ast_cli(fd, "None.\n");
00722 ast_rwlock_unlock(&uris_lock);
00723
00724 return RESULT_SUCCESS;
00725 }
00726
00727 int ast_http_reload(void)
00728 {
00729 return __ast_http_load(1);
00730 }
00731
00732 static char show_http_help[] =
00733 "Usage: http show status\n"
00734 " Lists status of internal HTTP engine\n";
00735
00736 static struct ast_cli_entry cli_http[] = {
00737 { { "http", "show", "status", NULL },
00738 handle_show_http, "Display HTTP server status",
00739 show_http_help },
00740 };
00741
00742 int ast_http_init(void)
00743 {
00744 ast_http_uri_link(&statusuri);
00745 ast_http_uri_link(&staticuri);
00746 ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));
00747
00748 return __ast_http_load(0);
00749 }