Wed Oct 28 11:46:11 2009

Asterisk developer's documentation


http.c File Reference

http server for AMI access More...

#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <fcntl.h>
#include "asterisk/cli.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/strings.h"
#include "asterisk/config.h"
#include "asterisk/stringfields.h"
#include "asterisk/ast_version.h"
#include "asterisk/manager.h"

Include dependency graph for http.c:

Go to the source code of this file.

Data Structures

struct  http_uri_redirect
struct  uri_redirects
struct  uris

Defines

#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.
struct ast_strast_http_error (int status, const char *title, const char *extra_header, const char *text)
 Return an ast_str malloc()'d string containing an HTTP error message.
int ast_http_init (void)
int ast_http_reload (void)
int ast_http_uri_link (struct ast_http_uri *urih)
 Link the new uri into the list.
void ast_http_uri_unlink (struct ast_http_uri *urih)
 Destroy an HTTP server.
static const char * ftype2mtype (const char *ftype, char *wkspace, int wkspacelen)
static char * handle_show_http (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_strhandle_uri (struct ast_tcptls_session_instance *ser, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies, unsigned int *static_content)
static void http_decode (char *s)
static void * httpd_helper_thread (void *arg)
static struct ast_strhttpstatus_callback (struct ast_tcptls_session_instance *ser, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
static uint32_t manid_from_vars (struct ast_variable *sid)
static struct ast_variableparse_cookies (char *cookies)
static struct ast_strstatic_callback (struct ast_tcptls_session_instance *ser, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)

Variables

static struct ast_cli_entry cli_http []
static int enablestatic
static struct server_args http_desc
static struct ast_tls_config http_tls_cfg
static struct server_args https_desc
struct {
   const char *   ext
   const char *   mtype
mimetypes []
 Limit the kinds of files we're willing to serve up.
static char prefix [MAX_PREFIX]
static struct ast_http_uri staticuri
static struct ast_http_uri statusuri


Detailed Description

http server for AMI access

Author:
Mark Spencer <markster@digium.com>
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 Documentation

#define MAX_PREFIX   80

Definition at line 57 of file http.c.

Referenced by __ast_http_load().


Function Documentation

static int __ast_http_load ( int  reload  )  [static]

Definition at line 1003 of file http.c.

References add_redirect(), AST_CERTFILE, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_gethostbyname(), ast_log(), AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_ssl_setup(), ast_strdup, ast_strlen_zero(), ast_tcptls_server_start(), ast_true(), ast_variable_browse(), ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, ast_tls_config::enabled, enabled, enablestatic, hp, http_tls_cfg, LOG_WARNING, MAX_PREFIX, ast_variable::name, ast_variable::next, prefix, server_args::sin, server_args::tls_cfg, and ast_variable::value.

Referenced by ast_http_init(), and ast_http_reload().

01004 {
01005    struct ast_config *cfg;
01006    struct ast_variable *v;
01007    int enabled=0;
01008    int newenablestatic=0;
01009    struct hostent *hp;
01010    struct ast_hostent ahp;
01011    char newprefix[MAX_PREFIX] = "";
01012    int have_sslbindaddr = 0;
01013    struct http_uri_redirect *redirect;
01014    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01015 
01016    if ((cfg = ast_config_load("http.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
01017       return 0;
01018 
01019    /* default values */
01020    memset(&http_desc.sin, 0, sizeof(http_desc.sin));
01021    http_desc.sin.sin_port = htons(8088);
01022 
01023    memset(&https_desc.sin, 0, sizeof(https_desc.sin));
01024    https_desc.sin.sin_port = htons(8089);
01025 
01026    http_tls_cfg.enabled = 0;
01027    if (http_tls_cfg.certfile)
01028       ast_free(http_tls_cfg.certfile);
01029    http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
01030    if (http_tls_cfg.cipher)
01031       ast_free(http_tls_cfg.cipher);
01032    http_tls_cfg.cipher = ast_strdup("");
01033 
01034    AST_RWLIST_WRLOCK(&uri_redirects);
01035    while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry)))
01036       ast_free(redirect);
01037    AST_RWLIST_UNLOCK(&uri_redirects);
01038 
01039 #ifdef ENABLE_UPLOADS
01040    destroy_post_mappings();
01041 #endif /* ENABLE_UPLOADS */
01042 
01043    if (cfg) {
01044       v = ast_variable_browse(cfg, "general");
01045       for (; v; v = v->next) {
01046          if (!strcasecmp(v->name, "enabled"))
01047             enabled = ast_true(v->value);
01048          else if (!strcasecmp(v->name, "sslenable"))
01049             http_tls_cfg.enabled = ast_true(v->value);
01050          else if (!strcasecmp(v->name, "sslbindport"))
01051             https_desc.sin.sin_port = htons(atoi(v->value));
01052          else if (!strcasecmp(v->name, "sslcert")) {
01053             ast_free(http_tls_cfg.certfile);
01054             http_tls_cfg.certfile = ast_strdup(v->value);
01055          } else if (!strcasecmp(v->name, "sslcipher")) {
01056             ast_free(http_tls_cfg.cipher);
01057             http_tls_cfg.cipher = ast_strdup(v->value);
01058          }
01059          else if (!strcasecmp(v->name, "enablestatic"))
01060             newenablestatic = ast_true(v->value);
01061          else if (!strcasecmp(v->name, "bindport"))
01062             http_desc.sin.sin_port = htons(atoi(v->value));
01063          else if (!strcasecmp(v->name, "sslbindaddr")) {
01064             if ((hp = ast_gethostbyname(v->value, &ahp))) {
01065                memcpy(&https_desc.sin.sin_addr, hp->h_addr, sizeof(https_desc.sin.sin_addr));
01066                have_sslbindaddr = 1;
01067             } else {
01068                ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
01069             }
01070          } else if (!strcasecmp(v->name, "bindaddr")) {
01071             if ((hp = ast_gethostbyname(v->value, &ahp))) {
01072                memcpy(&http_desc.sin.sin_addr, hp->h_addr, sizeof(http_desc.sin.sin_addr));
01073             } else {
01074                ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
01075             }
01076          } else if (!strcasecmp(v->name, "prefix")) {
01077             if (!ast_strlen_zero(v->value)) {
01078                newprefix[0] = '/';
01079                ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
01080             } else {
01081                newprefix[0] = '\0';
01082             }
01083          } else if (!strcasecmp(v->name, "redirect")) {
01084             add_redirect(v->value);
01085          } else {
01086             ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
01087          }
01088       }
01089 
01090 #ifdef ENABLE_UPLOADS
01091       for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next)
01092          add_post_mapping(v->name, v->value);
01093 #endif /* ENABLE_UPLOADS */
01094 
01095       ast_config_destroy(cfg);
01096    }
01097    if (!have_sslbindaddr)
01098       https_desc.sin.sin_addr = http_desc.sin.sin_addr;
01099    if (enabled)
01100       http_desc.sin.sin_family = https_desc.sin.sin_family = AF_INET;
01101    if (strcmp(prefix, newprefix))
01102       ast_copy_string(prefix, newprefix, sizeof(prefix));
01103    enablestatic = newenablestatic;
01104    ast_tcptls_server_start(&http_desc);
01105    if (ast_ssl_setup(https_desc.tls_cfg))
01106       ast_tcptls_server_start(&https_desc);
01107 
01108    return 0;
01109 }

static void __fini_uri_redirects ( void   )  [static]

Definition at line 133 of file http.c.

00136 {

static void __fini_uris ( void   )  [static]

Definition at line 91 of file http.c.

00094 {

static void __init_uri_redirects ( void   )  [static]

Definition at line 133 of file http.c.

00136 {

static void __init_uris ( void   )  [static]

Definition at line 91 of file http.c.

00094 {

static void add_redirect ( const char *  value  )  [static]

Add a new URI redirect The entries in the redirect list are sorted by length, just like the list of URI handlers.

Definition at line 908 of file http.c.

References ast_calloc, ast_log(), AST_RWLIST_EMPTY, AST_RWLIST_FIRST, AST_RWLIST_INSERT_AFTER, AST_RWLIST_INSERT_HEAD, AST_RWLIST_INSERT_TAIL, AST_RWLIST_NEXT, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_skip_blanks(), ast_strdupa, http_uri_redirect::dest, http_uri_redirect::entry, LOG_WARNING, strsep(), and http_uri_redirect::target.

Referenced by __ast_http_load().

00909 {
00910    char *target, *dest;
00911    struct http_uri_redirect *redirect, *cur;
00912    unsigned int target_len;
00913    unsigned int total_len;
00914 
00915    dest = ast_strdupa(value);
00916    dest = ast_skip_blanks(dest);
00917    target = strsep(&dest, " ");
00918    target = ast_skip_blanks(target);
00919    target = strsep(&target, " "); /* trim trailing whitespace */
00920 
00921    if (!dest) {
00922       ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
00923       return;
00924    }
00925 
00926    target_len = strlen(target) + 1;
00927    total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
00928 
00929    if (!(redirect = ast_calloc(1, total_len)))
00930       return;
00931 
00932    redirect->dest = redirect->target + target_len;
00933    strcpy(redirect->target, target);
00934    strcpy(redirect->dest, dest);
00935 
00936    AST_RWLIST_WRLOCK(&uri_redirects);
00937 
00938    target_len--; /* So we can compare directly with strlen() */
00939    if ( AST_RWLIST_EMPTY(&uri_redirects) 
00940       || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
00941       AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
00942       AST_RWLIST_UNLOCK(&uri_redirects);
00943       return;
00944    }
00945 
00946    AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
00947       if ( AST_RWLIST_NEXT(cur, entry) 
00948          && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
00949          AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
00950          AST_RWLIST_UNLOCK(&uri_redirects); 
00951          return;
00952       }
00953    }
00954 
00955    AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
00956 
00957    AST_RWLIST_UNLOCK(&uri_redirects);
00958 }

struct ast_str* ast_http_error ( int  status,
const char *  title,
const char *  extra_header,
const char *  text 
) [read]

Return an ast_str malloc()'d string containing an HTTP error message.

Definition at line 288 of file http.c.

References ast_str_create(), and ast_str_set().

Referenced by generic_http_callback(), handle_uri(), httpd_helper_thread(), phoneprov_callback(), and static_callback().

00289 {
00290    struct ast_str *out = ast_str_create(512);
00291    if (out == NULL)
00292       return out;
00293    ast_str_set(&out, 0,
00294       "Content-type: text/html\r\n"
00295       "%s"
00296       "\r\n"
00297       "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00298       "<html><head>\r\n"
00299       "<title>%d %s</title>\r\n"
00300       "</head><body>\r\n"
00301       "<h1>%s</h1>\r\n"
00302       "<p>%s</p>\r\n"
00303       "<hr />\r\n"
00304       "<address>Asterisk Server</address>\r\n"
00305       "</body></html>\r\n",
00306          (extra_header ? extra_header : ""), status, title, title, text);
00307    return out;
00308 }

int ast_http_init ( void   ) 

Definition at line 1188 of file http.c.

References __ast_http_load(), ast_cli_register_multiple(), ast_http_uri_link(), cli_http, staticuri, and statusuri.

Referenced by main().

01189 {
01190 #ifdef ENABLE_UPLOADS
01191    g_mime_init(0);
01192 #endif /* ENABLE_UPLOADS */
01193 
01194    ast_http_uri_link(&statusuri);
01195    ast_http_uri_link(&staticuri);
01196    ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));
01197 
01198    return __ast_http_load(0);
01199 }

int ast_http_reload ( void   ) 

Definition at line 1179 of file http.c.

References __ast_http_load().

01180 {
01181    return __ast_http_load(1);
01182 }

int ast_http_uri_link ( struct ast_http_uri urih  ) 

Link the new uri into the list.

Link into the Asterisk HTTP server.

They are sorted by length of the string, not alphabetically. Duplicate entries are not replaced, but the insertion order (using <= and not just <) makes sure that more recent insertions hide older ones. On a lookup, we just scan the list and stop at the first matching entry.

Definition at line 319 of file http.c.

References AST_RWLIST_EMPTY, AST_RWLIST_FIRST, AST_RWLIST_INSERT_AFTER, AST_RWLIST_INSERT_HEAD, AST_RWLIST_INSERT_TAIL, AST_RWLIST_NEXT, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_http_uri::entry, len(), and ast_http_uri::uri.

Referenced by __init_manager(), ast_http_init(), and load_module().

00320 {
00321    struct ast_http_uri *uri;
00322    int len = strlen(urih->uri);
00323 
00324    AST_RWLIST_WRLOCK(&uris);
00325 
00326    if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
00327       AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
00328       AST_RWLIST_UNLOCK(&uris);
00329       return 0;
00330    }
00331 
00332    AST_RWLIST_TRAVERSE(&uris, uri, entry) {
00333       if ( AST_RWLIST_NEXT(uri, entry) 
00334          && strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len ) {
00335          AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
00336          AST_RWLIST_UNLOCK(&uris); 
00337          return 0;
00338       }
00339    }
00340 
00341    AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
00342 
00343    AST_RWLIST_UNLOCK(&uris);
00344    
00345    return 0;
00346 }  

void ast_http_uri_unlink ( struct ast_http_uri urih  ) 

Destroy an HTTP server.

Definition at line 348 of file http.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_http_uri::entry.

Referenced by __init_manager(), and unload_module().

00349 {
00350    AST_RWLIST_WRLOCK(&uris);
00351    AST_RWLIST_REMOVE(&uris, urih, entry);
00352    AST_RWLIST_UNLOCK(&uris);
00353 }

static const char* ftype2mtype ( const char *  ftype,
char *  wkspace,
int  wkspacelen 
) [static]

Definition at line 135 of file http.c.

References ext, mimetypes, and mtype.

Referenced by build_profile(), and static_callback().

00136 {
00137    int x;
00138    if (ftype) {
00139       for (x=0;x<sizeof(mimetypes) / sizeof(mimetypes[0]); x++) {
00140          if (!strcasecmp(ftype, mimetypes[x].ext))
00141             return mimetypes[x].mtype;
00142       }
00143    }
00144    snprintf(wkspace, wkspacelen, "text/%s", ftype ? ftype : "plain");
00145    return wkspace;
00146 }

static char* handle_show_http ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1111 of file http.c.

References ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_http_uri::description, http_uri_redirect::dest, ast_tls_config::enabled, ast_cli_args::fd, ast_http_uri::has_subtree, http_tls_cfg, server_args::oldsin, prefix, http_uri_redirect::target, ast_http_uri::uri, and ast_cli_entry::usage.

01112 {
01113    struct ast_http_uri *urih;
01114    struct http_uri_redirect *redirect;
01115 
01116 #ifdef ENABLE_UPLOADS
01117    struct ast_http_post_mapping *post_map;
01118 #endif /* ENABLE_UPLOADS */
01119 
01120    switch (cmd) {
01121    case CLI_INIT:
01122       e->command = "http show status";
01123       e->usage = 
01124          "Usage: http show status\n"
01125          "       Lists status of internal HTTP engine\n";
01126       return NULL;
01127    case CLI_GENERATE:
01128       return NULL;
01129    }
01130    
01131    if (a->argc != 3)
01132       return CLI_SHOWUSAGE;
01133    ast_cli(a->fd, "HTTP Server Status:\n");
01134    ast_cli(a->fd, "Prefix: %s\n", prefix);
01135    if (!http_desc.oldsin.sin_family)
01136       ast_cli(a->fd, "Server Disabled\n\n");
01137    else {
01138       ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n",
01139          ast_inet_ntoa(http_desc.oldsin.sin_addr),
01140          ntohs(http_desc.oldsin.sin_port));
01141       if (http_tls_cfg.enabled)
01142          ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
01143             ast_inet_ntoa(https_desc.oldsin.sin_addr),
01144             ntohs(https_desc.oldsin.sin_port));
01145    }
01146 
01147    ast_cli(a->fd, "Enabled URI's:\n");
01148    AST_RWLIST_RDLOCK(&uris);
01149    if (AST_RWLIST_EMPTY(&uris)) {
01150       ast_cli(a->fd, "None.\n");
01151    } else {
01152       AST_RWLIST_TRAVERSE(&uris, urih, entry)
01153          ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
01154    }
01155    AST_RWLIST_UNLOCK(&uris);
01156 
01157    ast_cli(a->fd, "\nEnabled Redirects:\n");
01158    AST_RWLIST_RDLOCK(&uri_redirects);
01159    AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
01160       ast_cli(a->fd, "  %s => %s\n", redirect->target, redirect->dest);
01161    if (AST_RWLIST_EMPTY(&uri_redirects))
01162       ast_cli(a->fd, "  None.\n");
01163    AST_RWLIST_UNLOCK(&uri_redirects);
01164 
01165 
01166 #ifdef ENABLE_UPLOADS
01167    ast_cli(a->fd, "\nPOST mappings:\n");
01168    AST_RWLIST_RDLOCK(&post_mappings);
01169    AST_LIST_TRAVERSE(&post_mappings, post_map, entry) {
01170       ast_cli(a->fd, "%s/%s => %s\n", prefix, post_map->from, post_map->to);
01171    }
01172    ast_cli(a->fd, "%s\n", AST_LIST_EMPTY(&post_mappings) ? "None.\n" : "");
01173    AST_RWLIST_UNLOCK(&post_mappings);
01174 #endif /* ENABLE_UPLOADS */
01175 
01176    return CLI_SUCCESS;
01177 }

static struct ast_str* handle_uri ( struct ast_tcptls_session_instance ser,
char *  uri,
int *  status,
char **  title,
int *  contentlength,
struct ast_variable **  cookies,
unsigned int *  static_content 
) [static, read]

Definition at line 597 of file http.c.

References ast_http_error(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdup, ast_variable_new(), ast_variables_destroy(), ast_http_uri::callback, cleanup(), http_uri_redirect::dest, http_uri_redirect::entry, ast_http_uri::has_subtree, http_decode(), ast_variable::next, prefix, ast_http_uri::static_content, strsep(), http_uri_redirect::target, and ast_http_uri::uri.

Referenced by httpd_helper_thread().

00600 {
00601    char *c;
00602    struct ast_str *out = NULL;
00603    char *params = uri;
00604    struct ast_http_uri *urih=NULL;
00605    int l;
00606    struct ast_variable *vars=NULL, *v, *prev = NULL;
00607    struct http_uri_redirect *redirect;
00608 
00609    strsep(&params, "?");
00610    /* Extract arguments from the request and store them in variables. */
00611    if (params) {
00612       char *var, *val;
00613 
00614       while ((val = strsep(&params, "&"))) {
00615          var = strsep(&val, "=");
00616          if (val)
00617             http_decode(val);
00618          else 
00619             val = "";
00620          http_decode(var);
00621          if ((v = ast_variable_new(var, val, ""))) {
00622             if (vars)
00623                prev->next = v;
00624             else
00625                vars = v;
00626             prev = v;
00627          }
00628       }
00629    }
00630    /*
00631     * Append the cookies to the variables (the only reason to have them
00632     * at the end is to avoid another pass of the cookies list to find
00633     * the tail).
00634     */
00635    if (prev)
00636       prev->next = *cookies;
00637    else
00638       vars = *cookies;
00639    *cookies = NULL;
00640    http_decode(uri);
00641 
00642    AST_RWLIST_RDLOCK(&uri_redirects);
00643    AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
00644       if (!strcasecmp(uri, redirect->target)) {
00645          char buf[512];
00646          snprintf(buf, sizeof(buf), "Location: %s\r\n", redirect->dest);
00647          out = ast_http_error((*status = 302),
00648                     (*title = ast_strdup("Moved Temporarily")),
00649                     buf, "Redirecting...");
00650 
00651          break;
00652       }
00653    }
00654    AST_RWLIST_UNLOCK(&uri_redirects);
00655    if (redirect)
00656       goto cleanup;
00657 
00658    /* We want requests to start with the (optional) prefix and '/' */
00659    l = strlen(prefix);
00660    if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
00661       uri += l + 1;
00662       /* scan registered uris to see if we match one. */
00663       AST_RWLIST_RDLOCK(&uris);
00664       AST_RWLIST_TRAVERSE(&uris, urih, entry) {
00665          l = strlen(urih->uri);
00666          c = uri + l;   /* candidate */
00667          if (strncasecmp(urih->uri, uri, l) /* no match */
00668              || (*c && *c != '/')) /* substring */
00669             continue;
00670          if (*c == '/')
00671             c++;
00672          if (!*c || urih->has_subtree) {
00673             uri = c;
00674             break;
00675          }
00676       }
00677       if (!urih)
00678          AST_RWLIST_UNLOCK(&uris);
00679    }
00680    if (urih) {
00681       if (urih->static_content)
00682          *static_content = 1;
00683       out = urih->callback(ser, uri, vars, status, title, contentlength);
00684       AST_RWLIST_UNLOCK(&uris);
00685    } else {
00686       out = ast_http_error(404, "Not Found", NULL,
00687          "The requested URL was not found on this server.");
00688       *status = 404;
00689       *title = ast_strdup("Not Found");
00690    }
00691 
00692 cleanup:
00693    ast_variables_destroy(vars);
00694    return out;
00695 }

static void http_decode ( char *  s  )  [static]

Definition at line 585 of file http.c.

References ast_uri_decode().

Referenced by handle_uri().

00586 {
00587    char *t;
00588    
00589    for (t = s; *t; t++) {
00590       if (*t == '+')
00591          *t = ' ';
00592    }
00593 
00594    ast_uri_decode(s);
00595 }

static void * httpd_helper_thread ( void *  arg  )  [static]

Definition at line 778 of file http.c.

References ao2_ref(), ast_free, ast_get_version(), ast_http_error(), ast_localtime(), ast_log(), ast_skip_blanks(), ast_skip_nonblanks(), ast_strdupa, ast_strftime(), ast_strlen_zero(), ast_trim_blanks(), ast_tvnow(), ast_variable_new(), ast_variables_destroy(), errno, ast_tcptls_session_instance::f, handle_uri(), LOG_WARNING, name, ast_variable::next, parse_cookies(), ast_str::str, and strsep().

00779 {
00780    char buf[4096];
00781    char cookie[4096];
00782    struct ast_tcptls_session_instance *ser = data;
00783    struct ast_variable *vars=NULL, *headers = NULL;
00784    char *uri, *title=NULL;
00785    int status = 200, contentlength = 0;
00786    struct ast_str *out = NULL;
00787    unsigned int static_content = 0;
00788 
00789    if (!fgets(buf, sizeof(buf), ser->f))
00790       goto done;
00791 
00792    uri = ast_skip_nonblanks(buf);   /* Skip method */
00793    if (*uri)
00794       *uri++ = '\0';
00795 
00796    uri = ast_skip_blanks(uri);   /* Skip white space */
00797 
00798    if (*uri) {       /* terminate at the first blank */
00799       char *c = ast_skip_nonblanks(uri);
00800       if (*c)
00801          *c = '\0';
00802    }
00803 
00804    /* process "Cookie: " lines */
00805    while (fgets(cookie, sizeof(cookie), ser->f)) {
00806       /* Trim trailing characters */
00807       ast_trim_blanks(cookie);
00808       if (ast_strlen_zero(cookie))
00809          break;
00810       if (strncasecmp(cookie, "Cookie: ", 8)) {
00811          char *name, *value;
00812          struct ast_variable *var;
00813 
00814          value = ast_strdupa(cookie);
00815          name = strsep(&value, ":");
00816          if (!value)
00817             continue;
00818          value = ast_skip_blanks(value);
00819          if (ast_strlen_zero(value))
00820             continue;
00821          var = ast_variable_new(name, value, "");
00822          if (!var)
00823             continue;
00824          var->next = headers;
00825          headers = var;
00826          continue;
00827       }
00828 
00829       if (vars) {
00830          ast_variables_destroy(vars);
00831       }
00832       vars = parse_cookies(cookie);
00833    }
00834 
00835    if (!*uri) {
00836       out = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
00837    } else if (!strcasecmp(buf, "post")) {
00838 #ifdef ENABLE_UPLOADS
00839       out = handle_post(ser, uri, &status, &title, &contentlength, headers, vars);
00840 #else
00841       out = ast_http_error(501, "Not Implemented", NULL,
00842          "Attempt to use unimplemented / unsupported method");
00843 #endif /* ENABLE_UPLOADS */
00844    } else if (strcasecmp(buf, "get")) {
00845       out = ast_http_error(501, "Not Implemented", NULL,
00846          "Attempt to use unimplemented / unsupported method");
00847    } else { /* try to serve it */
00848       out = handle_uri(ser, uri, &status, &title, &contentlength, &vars, &static_content);
00849    }
00850 
00851    /* If they aren't mopped up already, clean up the cookies */
00852    if (vars)
00853       ast_variables_destroy(vars);
00854    /* Clean up all the header information pulled as well */
00855    if (headers)
00856       ast_variables_destroy(headers);
00857 
00858    if (out) {
00859       struct timeval tv = ast_tvnow();
00860       char timebuf[256];
00861       struct ast_tm tm;
00862 
00863       ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&tv, &tm, "GMT"));
00864       fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
00865             "Server: Asterisk/%s\r\n"
00866             "Date: %s\r\n"
00867             "Connection: close\r\n"
00868             "%s",
00869          status, title ? title : "OK", ast_get_version(), timebuf,
00870          static_content ? "" : "Cache-Control: no-cache, no-store\r\n");
00871          /* We set the no-cache headers only for dynamic content.
00872          * If you want to make sure the static file you requested is not from cache,
00873          * append a random variable to your GET request.  Ex: 'something.html?r=109987734'
00874          */
00875       if (!contentlength) {   /* opaque body ? just dump it hoping it is properly formatted */
00876          fprintf(ser->f, "%s", out->str);
00877       } else {
00878          char *tmp = strstr(out->str, "\r\n\r\n");
00879 
00880          if (tmp) {
00881             fprintf(ser->f, "Content-length: %d\r\n", contentlength);
00882             /* first write the header, then the body */
00883             if (fwrite(out->str, 1, (tmp + 4 - out->str), ser->f) != tmp + 4 - out->str) {
00884                ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00885             }
00886             if (fwrite(tmp + 4, 1, contentlength, ser->f) != contentlength ) {
00887                ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00888             }
00889          }
00890       }
00891       ast_free(out);
00892    }
00893    if (title)
00894       ast_free(title);
00895 
00896 done:
00897    fclose(ser->f);
00898    ao2_ref(ser, -1);
00899    ser = NULL;
00900    return NULL;
00901 }

static struct ast_str* httpstatus_callback ( struct ast_tcptls_session_instance ser,
const char *  uri,
struct ast_variable vars,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 236 of file http.c.

References ast_inet_ntoa(), ast_str_append(), ast_str_create(), ast_tls_config::enabled, http_tls_cfg, ast_variable::name, ast_variable::next, server_args::oldsin, prefix, and ast_variable::value.

00237 {
00238    struct ast_str *out = ast_str_create(512);
00239    struct ast_variable *v;
00240 
00241    if (out == NULL)
00242       return out;
00243 
00244    ast_str_append(&out, 0,
00245       "\r\n"
00246       "<title>Asterisk HTTP Status</title>\r\n"
00247       "<body bgcolor=\"#ffffff\">\r\n"
00248       "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
00249       "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
00250 
00251    ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
00252    ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
00253          ast_inet_ntoa(http_desc.oldsin.sin_addr));
00254    ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
00255          ntohs(http_desc.oldsin.sin_port));
00256    if (http_tls_cfg.enabled)
00257       ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
00258          ntohs(https_desc.oldsin.sin_port));
00259    ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00260    for (v = vars; v; v = v->next) {
00261       if (strncasecmp(v->name, "cookie_", 7))
00262          ast_str_append(&out, 0, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00263    }
00264    ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00265    for (v = vars; v; v = v->next) {
00266       if (!strncasecmp(v->name, "cookie_", 7))
00267          ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00268    }
00269    ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
00270    return out;
00271 }

static uint32_t manid_from_vars ( struct ast_variable sid  )  [static]

Definition at line 148 of file http.c.

References ast_variable::name, ast_variable::next, and ast_variable::value.

Referenced by static_callback().

00148                                                           {
00149    uint32_t mngid;
00150 
00151    while (sid && strcmp(sid->name, "mansession_id"))
00152       sid = sid->next;
00153 
00154    if (!sid || sscanf(sid->value, "%30x", &mngid) != 1)
00155       return 0;
00156 
00157    return mngid;
00158 }

static struct ast_variable* parse_cookies ( char *  cookies  )  [static, read]

Definition at line 741 of file http.c.

References ast_log(), ast_strip(), ast_strip_quoted(), ast_strlen_zero(), ast_variable_new(), LOG_DEBUG, name, option_debug, and strsep().

Referenced by httpd_helper_thread().

00742 {
00743    char *cur;
00744    struct ast_variable *vars = NULL, *var;
00745 
00746    /* Skip Cookie: */
00747    cookies += 8;
00748 
00749    while ((cur = strsep(&cookies, ";"))) {
00750       char *name, *val;
00751       
00752       name = val = cur;
00753       strsep(&val, "=");
00754 
00755       if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00756          continue;
00757       }
00758 
00759       name = ast_strip(name);
00760       val = ast_strip_quoted(val, "\"", "\"");
00761 
00762       if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00763          continue;
00764       }
00765 
00766       if (option_debug) {
00767          ast_log(LOG_DEBUG, "mmm ... cookie!  Name: '%s'  Value: '%s'\n", name, val);
00768       }
00769 
00770       var = ast_variable_new(name, val, __FILE__);
00771       var->next = vars;
00772       vars = var;
00773    }
00774 
00775    return vars;
00776 }

static struct ast_str* static_callback ( struct ast_tcptls_session_instance ser,
const char *  uri,
struct ast_variable vars,
int *  status,
char **  title,
int *  contentlength 
) [static, read]

Definition at line 160 of file http.c.

References ast_config_AST_DATA_DIR, ast_get_version(), ast_http_error(), ast_localtime(), ast_log(), ast_strdup, ast_strftime(), ast_strlen_zero(), ast_tvnow(), astman_is_authed(), buf, enablestatic, errno, ast_tcptls_session_instance::f, ftype2mtype(), len(), LOG_WARNING, manid_from_vars(), and mtype.

00161 {
00162    char *path;
00163    char *ftype;
00164    const char *mtype;
00165    char wkspace[80];
00166    struct stat st;
00167    int len;
00168    int fd;
00169    struct timeval tv = ast_tvnow();
00170    char buf[256];
00171    struct ast_tm tm;
00172 
00173    /* Yuck.  I'm not really sold on this, but if you don't deliver static content it makes your configuration 
00174       substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
00175    if (!enablestatic || ast_strlen_zero(uri))
00176       goto out403;
00177    /* Disallow any funny filenames at all */
00178    if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0]))
00179       goto out403;
00180    if (strstr(uri, "/.."))
00181       goto out403;
00182       
00183    if ((ftype = strrchr(uri, '.')))
00184       ftype++;
00185    mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace));
00186    
00187    /* Cap maximum length */
00188    len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5;
00189    if (len > 1024)
00190       goto out403;
00191       
00192    path = alloca(len);
00193    sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00194    if (stat(path, &st))
00195       goto out404;
00196    if (S_ISDIR(st.st_mode))
00197       goto out404;
00198    fd = open(path, O_RDONLY);
00199    if (fd < 0)
00200       goto out403;
00201 
00202    if (strstr(path, "/private/") && !astman_is_authed(manid_from_vars(vars))) {
00203       goto out403;
00204    }
00205 
00206    ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&tv, &tm, "GMT"));
00207    fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
00208       "Server: Asterisk/%s\r\n"
00209       "Date: %s\r\n"
00210       "Connection: close\r\n"
00211       "Cache-Control: private\r\n"
00212       "Content-Length: %d\r\n"
00213       "Content-type: %s\r\n\r\n",
00214       ast_get_version(), buf, (int) st.st_size, mtype);
00215 
00216    while ((len = read(fd, buf, sizeof(buf))) > 0)
00217       if (fwrite(buf, 1, len, ser->f) != len) {
00218          ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00219       }
00220 
00221    close(fd);
00222    return NULL;
00223 
00224 out404:
00225    return ast_http_error((*status = 404),
00226                (*title = ast_strdup("Not Found")),
00227                 NULL, "The requested URL was not found on this server.");
00228 
00229 out403:
00230    return ast_http_error((*status = 403),
00231                (*title = ast_strdup("Access Denied")),
00232                NULL, "You do not have permission to access the requested URL.");
00233 }


Variable Documentation

struct ast_cli_entry cli_http[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
}

Definition at line 1184 of file http.c.

Referenced by ast_http_init().

int enablestatic [static]

Definition at line 110 of file http.c.

Referenced by __ast_http_load(), and static_callback().

const char* ext

struct server_args http_desc [static]

we have up to two accepting threads, one for http, one for https

Definition at line 71 of file http.c.

struct ast_tls_config http_tls_cfg [static]

Definition at line 64 of file http.c.

Referenced by __ast_http_load(), handle_show_http(), and httpstatus_callback().

struct server_args https_desc [static]

Definition at line 81 of file http.c.

struct { ... } mimetypes[] [static]

Limit the kinds of files we're willing to serve up.

Referenced by ftype2mtype().

const char* mtype

Definition at line 115 of file http.c.

Referenced by ftype2mtype(), and static_callback().

char prefix[MAX_PREFIX] [static]

struct ast_http_uri staticuri [static]

Definition at line 280 of file http.c.

Referenced by ast_http_init().

struct ast_http_uri statusuri [static]

Definition at line 273 of file http.c.

Referenced by ast_http_init().


Generated on Wed Oct 28 11:46:11 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6