Thu Jul 9 13:41:20 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"

Go to the source code of this file.

Data Structures

struct  http_uri_redirect
struct  uri_redirects
struct  uris

Defines

#define DO_SSL
#define HOOK_T   ssize_t
#define LEN_T   size_t
#define MAX_PREFIX   80

Functions

static int __ast_http_load (int reload)
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.
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 into the Asterisk HTTP server.
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 DO_SSL

Definition at line 61 of file http.c.

#define HOOK_T   ssize_t

Definition at line 702 of file http.c.

#define LEN_T   size_t

Definition at line 703 of file http.c.

#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 ahp, AST_CERTFILE, ast_config_load, ast_free, ast_gethostbyname(), AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_true(), ast_variable_browse(), ast_tls_config::certfile, ast_tls_config::cipher, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, ast_tls_config::enabled, enabled, hp, http_desc, http_tls_cfg, https_desc, MAX_PREFIX, ast_variable::name, ast_variable::next, server_args::sin, 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 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, strsep(), and http_uri_redirect::target.

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 
)

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 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 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 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 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 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_desc, http_tls_cfg, https_desc, server_args::oldsin, 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]

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, ast_http_uri::uri, val, and var.

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(), name, parse_cookies(), ast_str::str, strsep(), and var.

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]

Definition at line 236 of file http.c.

References ast_inet_ntoa(), ast_str_append(), ast_str_create(), ast_tls_config::enabled, http_desc, http_tls_cfg, https_desc, 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, "%x", &mngid) != 1)
00155       return 0;
00156    
00157    return mngid;
00158 }

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

replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.

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, strsep(), and var.

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]

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:

 {
   { .handler =  handle_show_http , .summary =  "Display HTTP server status" ,__VA_ARGS__ },
}

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 static_callback().

const char* ext

Definition at line 114 of file http.c.

Referenced by ast_filehelper(), ast_rtp_read(), cli_console_dial(), common_exec(), console_transfer(), do_directory(), exts_compare(), ftype2mtype(), iax_park_thread(), misdn_call(), misdn_request(), mixmonitor_thread(), moh_scan_files(), oh323_request(), pbx_load_config(), record_exec(), register_exten(), register_peer_exten(), sip_park_thread(), sip_request_call(), and unregister_exten().

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.

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

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.

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

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]

Definition at line 109 of file http.c.

Referenced by _while_exec(), ast_db_deltree(), ast_db_gettree(), exec_clearhash(), handle_cli_database_show(), handle_uri(), hashkeys_read(), httpstatus_callback(), read_config(), shared_read(), shared_write(), sip_show_settings(), and while_continue_exec().

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 Thu Jul 9 13:41:20 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7