- Convert the list of URI handlers to use the linked list macros. While doing

this, implementing locking of this list to make it thread-safe.

- Add a "redirect" option to http.conf that allows redirecting one URI to
  another.  I was inspired to do this while playing with the Asterisk GUI.  I
  got tired of typing this URL to get to the GUI:
     
     http://localhost:8088/asterisk/static/config/cfgadvanced.html

  So, now I have the following line in http.conf:

     redirect=/=/asterisk/static/config/cfgadvanced.html

  Now, I can type the following into my browser and go to the GUI:

     http://localhost:8088


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48930 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Russell Bryant
2006-12-23 20:13:14 +00:00
parent 08cfbe97b8
commit 2c5071a006
4 changed files with 165 additions and 49 deletions

View File

@@ -64,4 +64,4 @@ Changes since Asterisk 1.4-beta was branched:
* Added maxfiles option to options section of asterisk.conf which allows you to specify * Added maxfiles option to options section of asterisk.conf which allows you to specify
what Asterisk should set as the maximum number of open files when it loads. what Asterisk should set as the maximum number of open files when it loads.
* Added the jittertargetextra configuration option. * Added the jittertargetextra configuration option.
* Added the URI redirect option for the built-in HTTP server

View File

@@ -9,11 +9,6 @@
; ;
;enabled=yes ;enabled=yes
; ;
; Whether Asterisk should serve static content from http-static
; Default is no.
;
;enablestatic=yes
;
; Address to bind to, both for HTTP and HTTPS. Default is 0.0.0.0 ; Address to bind to, both for HTTP and HTTPS. Default is 0.0.0.0
; ;
bindaddr=127.0.0.1 bindaddr=127.0.0.1
@@ -27,7 +22,20 @@ bindaddr=127.0.0.1
; requests must begin with /asterisk ; requests must begin with /asterisk
; ;
;prefix=asterisk ;prefix=asterisk
;
; Whether Asterisk should serve static content from http-static
; Default is no.
;
;enablestatic=yes
;
; Redirect one URI to another. This is how you would set a
; default page.
; Syntax: redirect=<from here>=<to there>
; For example, if you are using the Asterisk-gui,
; it is convenient to enable the following redirect:
;
;redirect=/=/asterisk/static/config/cfgadvanced.html
;
; HTTPS support. In addition to enabled=yes, you need to ; HTTPS support. In addition to enabled=yes, you need to
; explicitly enable ssl, define the port to use, ; explicitly enable ssl, define the port to use,
; and have a certificate somewhere. ; and have a certificate somewhere.

View File

@@ -147,7 +147,7 @@ int ssl_setup(struct tls_config *cfg);
typedef struct ast_str *(*ast_http_callback)(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength); typedef struct ast_str *(*ast_http_callback)(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength);
struct ast_http_uri { struct ast_http_uri {
struct ast_http_uri *next; AST_LIST_ENTRY(ast_http_uri) entry;
const char *description; const char *description;
const char *uri; const char *uri;
int has_subtree; int has_subtree;

View File

@@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/strings.h" #include "asterisk/strings.h"
#include "asterisk/options.h" #include "asterisk/options.h"
#include "asterisk/config.h" #include "asterisk/config.h"
#include "asterisk/stringfields.h"
#define MAX_PREFIX 80 #define MAX_PREFIX 80
#define DEFAULT_PREFIX "/asterisk" #define DEFAULT_PREFIX "/asterisk"
@@ -106,7 +107,7 @@ static struct server_args https_desc = {
.worker_fn = httpd_helper_thread, .worker_fn = httpd_helper_thread,
}; };
static struct ast_http_uri *uris; /*!< list of supported handlers */ static AST_LIST_HEAD_STATIC(uris, ast_http_uri); /*!< list of supported handlers */
/* all valid URIs must be prepended by the string in prefix. */ /* all valid URIs must be prepended by the string in prefix. */
static char prefix[MAX_PREFIX]; static char prefix[MAX_PREFIX];
@@ -124,6 +125,16 @@ static struct {
{ "mp3", "audio/mpeg" }, { "mp3", "audio/mpeg" },
}; };
struct http_uri_redirect {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(target);
AST_STRING_FIELD(dest);
);
AST_LIST_ENTRY(http_uri_redirect) entry;
};
static AST_LIST_HEAD_STATIC(uri_redirects, http_uri_redirect);
static char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen) static char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
{ {
int x; int x;
@@ -297,37 +308,38 @@ struct ast_str *ast_http_error(int status, const char *title, const char *extra_
*/ */
int ast_http_uri_link(struct ast_http_uri *urih) int ast_http_uri_link(struct ast_http_uri *urih)
{ {
struct ast_http_uri *prev=uris; struct ast_http_uri *uri;
int len = strlen(urih->uri); int len = strlen(urih->uri);
if (!uris || strlen(uris->uri) <= len ) { AST_LIST_LOCK(&uris);
urih->next = uris;
uris = urih; if ( AST_LIST_EMPTY(&uris) || strlen(AST_LIST_FIRST(&uris)->uri) <= len ) {
} else { AST_LIST_INSERT_HEAD(&uris, urih, entry);
while (prev->next && strlen(prev->next->uri) > len) AST_LIST_UNLOCK(&uris);
prev = prev->next; return 0;
/* Insert it here */
urih->next = prev->next;
prev->next = urih;
} }
AST_LIST_TRAVERSE(&uris, uri, entry) {
if ( AST_LIST_NEXT(uri, entry)
&& strlen(AST_LIST_NEXT(uri, entry)->uri) <= len ) {
AST_LIST_INSERT_AFTER(&uris, uri, urih, entry);
AST_LIST_UNLOCK(&uris);
return 0;
}
}
AST_LIST_INSERT_TAIL(&uris, urih, entry);
AST_LIST_UNLOCK(&uris);
return 0; return 0;
} }
void ast_http_uri_unlink(struct ast_http_uri *urih) void ast_http_uri_unlink(struct ast_http_uri *urih)
{ {
struct ast_http_uri *prev = uris; AST_LIST_LOCK(&uris);
if (!uris) AST_LIST_REMOVE(&uris, urih, entry);
return; AST_LIST_UNLOCK(&uris);
if (uris == urih) {
uris = uris->next;
}
while(prev->next) {
if (prev->next == urih) {
prev->next = urih->next;
break;
}
prev = prev->next;
}
} }
static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies) static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength, struct ast_variable **cookies)
@@ -338,6 +350,7 @@ static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *statu
struct ast_http_uri *urih=NULL; struct ast_http_uri *urih=NULL;
int l; int l;
struct ast_variable *vars=NULL, *v, *prev = NULL; struct ast_variable *vars=NULL, *v, *prev = NULL;
struct http_uri_redirect *redirect;
strsep(&params, "?"); strsep(&params, "?");
/* Extract arguments from the request and store them in variables. */ /* Extract arguments from the request and store them in variables. */
@@ -372,12 +385,29 @@ static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *statu
*cookies = NULL; *cookies = NULL;
ast_uri_decode(uri); ast_uri_decode(uri);
AST_LIST_LOCK(&uri_redirects);
AST_LIST_TRAVERSE(&uri_redirects, redirect, entry) {
if (!strcasecmp(uri, redirect->target)) {
char buf[512];
snprintf(buf, sizeof(buf), "Location: %s\r\n", redirect->dest);
out = ast_http_error(302, "Moved Temporarily", buf,
"There is no spoon...");
*status = 302;
*title = strdup("Moved Temporarily");
break;
}
}
AST_LIST_UNLOCK(&uri_redirects);
if (redirect)
goto cleanup;
/* We want requests to start with the prefix and '/' */ /* We want requests to start with the prefix and '/' */
l = strlen(prefix); l = strlen(prefix);
if (l && !strncasecmp(uri, prefix, l) && uri[l] == '/') { if (l && !strncasecmp(uri, prefix, l) && uri[l] == '/') {
uri += l + 1; uri += l + 1;
/* scan registered uris to see if we match one. */ /* scan registered uris to see if we match one. */
for (urih = uris; urih; urih = urih->next) { AST_LIST_LOCK(&uris);
AST_LIST_TRAVERSE(&uris, urih, entry) {
l = strlen(urih->uri); l = strlen(urih->uri);
c = uri + l; /* candidate */ c = uri + l; /* candidate */
if (strncasecmp(urih->uri, uri, l) /* no match */ if (strncasecmp(urih->uri, uri, l) /* no match */
@@ -390,22 +420,20 @@ static struct ast_str *handle_uri(struct sockaddr_in *sin, char *uri, int *statu
break; break;
} }
} }
if (!urih)
AST_LIST_UNLOCK(&uris);
} }
if (urih) { if (urih) {
out = urih->callback(sin, uri, vars, status, title, contentlength); out = urih->callback(sin, uri, vars, status, title, contentlength);
} else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) { AST_LIST_UNLOCK(&uris);
/* Special case: no prefix, no URI, send to /static/index.html */
out = ast_http_error(302, "Moved Temporarily",
"Location: /static/index.html\r\n",
"This is not the page you are looking for...");
*status = 302;
*title = strdup("Moved Temporarily");
} else { } else {
out = ast_http_error(404, "Not Found", NULL, out = ast_http_error(404, "Not Found", NULL,
"The requested URL was not found on this server."); "The requested URL was not found on this server.");
*status = 404; *status = 404;
*title = strdup("Not Found"); *title = strdup("Not Found");
} }
cleanup:
ast_variables_destroy(vars); ast_variables_destroy(vars);
return out; return out;
} }
@@ -778,6 +806,66 @@ error:
desc->accept_fd = -1; desc->accept_fd = -1;
} }
/*!
* \brief Add a new URI redirect
* The entries in the redirect list are sorted by length, just like the list
* of URI handlers.
*/
static void add_redirect(const char *value)
{
char *target, *dest;
struct http_uri_redirect *redirect, *cur;
unsigned int len;
dest = ast_strdupa(value);
target = strsep(&dest, "=");
if (!dest) {
ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
return;
}
if (!(redirect = ast_calloc(1, sizeof(*redirect))))
return;
if (ast_string_field_init(redirect, 32)) {
free(redirect);
return;
}
ast_string_field_set(redirect, target, target);
ast_string_field_set(redirect, dest, dest);
AST_LIST_LOCK(&uri_redirects);
len = strlen(target);
if ( AST_LIST_EMPTY(&uri_redirects)
|| strlen(AST_LIST_FIRST(&uri_redirects)->target) <= len ) {
AST_LIST_INSERT_HEAD(&uri_redirects, redirect, entry);
AST_LIST_UNLOCK(&uri_redirects);
return;
}
AST_LIST_TRAVERSE(&uri_redirects, cur, entry) {
if ( AST_LIST_NEXT(cur, entry)
&& strlen(AST_LIST_NEXT(cur, entry)->target) <= len ) {
AST_LIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
AST_LIST_UNLOCK(&uri_redirects);
return;
}
}
AST_LIST_INSERT_TAIL(&uri_redirects, redirect, entry);
AST_LIST_UNLOCK(&uri_redirects);
}
static void destroy_redirect(struct http_uri_redirect *redirect)
{
ast_string_field_free_all(redirect);
free(redirect);
}
static int __ast_http_load(int reload) static int __ast_http_load(int reload)
{ {
struct ast_config *cfg; struct ast_config *cfg;
@@ -788,6 +876,7 @@ static int __ast_http_load(int reload)
struct ast_hostent ahp; struct ast_hostent ahp;
char newprefix[MAX_PREFIX]; char newprefix[MAX_PREFIX];
int have_sslbindaddr = 0; int have_sslbindaddr = 0;
struct http_uri_redirect *redirect;
/* default values */ /* default values */
memset(&http_desc.sin, 0, sizeof(http_desc.sin)); memset(&http_desc.sin, 0, sizeof(http_desc.sin));
@@ -796,7 +885,6 @@ static int __ast_http_load(int reload)
memset(&https_desc.sin, 0, sizeof(https_desc.sin)); memset(&https_desc.sin, 0, sizeof(https_desc.sin));
https_desc.sin.sin_port = htons(8089); https_desc.sin.sin_port = htons(8089);
strcpy(newprefix, DEFAULT_PREFIX); strcpy(newprefix, DEFAULT_PREFIX);
cfg = ast_config_load("http.conf");
http_tls_cfg.enabled = 0; http_tls_cfg.enabled = 0;
if (http_tls_cfg.certfile) if (http_tls_cfg.certfile)
@@ -806,9 +894,15 @@ static int __ast_http_load(int reload)
free(http_tls_cfg.cipher); free(http_tls_cfg.cipher);
http_tls_cfg.cipher = ast_strdup(""); http_tls_cfg.cipher = ast_strdup("");
AST_LIST_LOCK(&uri_redirects);
while ((redirect = AST_LIST_REMOVE_HEAD(&uri_redirects, entry)))
destroy_redirect(redirect);
AST_LIST_UNLOCK(&uri_redirects);
cfg = ast_config_load("http.conf");
if (cfg) { if (cfg) {
v = ast_variable_browse(cfg, "general"); v = ast_variable_browse(cfg, "general");
while(v) { for (; v; v = v->next) {
if (!strcasecmp(v->name, "enabled")) if (!strcasecmp(v->name, "enabled"))
enabled = ast_true(v->value); enabled = ast_true(v->value);
else if (!strcasecmp(v->name, "sslenable")) else if (!strcasecmp(v->name, "sslenable"))
@@ -846,9 +940,11 @@ static int __ast_http_load(int reload)
} else { } else {
newprefix[0] = '\0'; newprefix[0] = '\0';
} }
} else if (!strcasecmp(v->name, "redirect")) {
add_redirect(v->value);
} else {
ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
} }
v = v->next;
} }
ast_config_destroy(cfg); ast_config_destroy(cfg);
} }
@@ -868,8 +964,11 @@ static int __ast_http_load(int reload)
static int handle_show_http(int fd, int argc, char *argv[]) static int handle_show_http(int fd, int argc, char *argv[])
{ {
struct ast_http_uri *urih; struct ast_http_uri *urih;
struct http_uri_redirect *redirect;
if (argc != 3) if (argc != 3)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
ast_cli(fd, "HTTP Server Status:\n"); ast_cli(fd, "HTTP Server Status:\n");
ast_cli(fd, "Prefix: %s\n", prefix); ast_cli(fd, "Prefix: %s\n", prefix);
if (!http_desc.oldsin.sin_family) if (!http_desc.oldsin.sin_family)
@@ -883,14 +982,23 @@ static int handle_show_http(int fd, int argc, char *argv[])
ast_inet_ntoa(https_desc.oldsin.sin_addr), ast_inet_ntoa(https_desc.oldsin.sin_addr),
ntohs(https_desc.oldsin.sin_port)); ntohs(https_desc.oldsin.sin_port));
} }
ast_cli(fd, "Enabled URI's:\n"); ast_cli(fd, "Enabled URI's:\n");
urih = uris; AST_LIST_LOCK(&uris);
while(urih){ AST_LIST_TRAVERSE(&uris, urih, entry)
ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description); ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
urih = urih->next; if (AST_LIST_EMPTY(&uris))
}
if (!uris)
ast_cli(fd, "None.\n"); ast_cli(fd, "None.\n");
AST_LIST_UNLOCK(&uris);
ast_cli(fd, "\nEnabled Redirects:\n");
AST_LIST_LOCK(&uri_redirects);
AST_LIST_TRAVERSE(&uri_redirects, redirect, entry)
ast_cli(fd, " %s => %s\n", redirect->target, redirect->dest);
if (AST_LIST_EMPTY(&uri_redirects))
ast_cli(fd, " None.\n");
AST_LIST_UNLOCK(&uri_redirects);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }