mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-09 06:28:14 +00:00
- 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:
2
CHANGES
2
CHANGES
@@ -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
|
||||||
|
@@ -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.
|
||||||
|
@@ -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;
|
||||||
|
190
main/http.c
190
main/http.c
@@ -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(¶ms, "?");
|
strsep(¶ms, "?");
|
||||||
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user