Re-add HTTP post support by moving to res_http_post.c

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@112426 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Terry Wilson 2008-04-02 15:25:48 +00:00
parent b95d24ea47
commit 1eb31edde2
6 changed files with 378 additions and 344 deletions

View File

@ -1,10 +1,6 @@
<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
<member name="DONT_OPTIMIZE" displayname="Disable Optimizations by the Compiler">
</member>
<member name="ENABLE_UPLOADS" displayname="Enable HTTP uploads">
<defaultenabled>yes</defaultenabled>
<depend>gmime</depend>
</member>
<member name="DEBUG_THREADS" displayname="Enable Thread Debugging">
</member>
<member name="STATIC_BUILD" displayname="Build static binaries">

View File

@ -70,9 +70,9 @@ enum ast_http_method {
AST_HTTP_GET = 0,
AST_HTTP_POST,
};
struct ast_http_uri;
typedef struct ast_str *(*ast_http_callback)(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method,
struct ast_variable *params, int *status, char **title, int *contentlength);
typedef struct ast_str *(*ast_http_callback)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength);
/*! \brief Definition of a URI handler */
struct ast_http_uri {
@ -87,6 +87,10 @@ struct ast_http_uri {
unsigned int supports_get:1;
/*! This handler accepts POST requests */
unsigned int supports_post:1;
/*! Data to bind to the uri if needed */
void *data;
/*! Key to be used for unlinking if multipile URIs registerd */
const char *key;
};
/*! \brief Register a URI handler */
@ -95,6 +99,9 @@ int ast_http_uri_link(struct ast_http_uri *urihandler);
/*! \brief Unregister a URI handler */
void ast_http_uri_unlink(struct ast_http_uri *urihandler);
/*! \brief Unregister all handlers with matching key */
void ast_http_uri_unlink_all_with_key(const char *key);
/*! \brief Return an ast_str malloc()'d string containing an HTTP error message */
struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text);

View File

@ -38,10 +38,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/signal.h>
#include <fcntl.h>
#ifdef ENABLE_UPLOADS
#include <gmime/gmime.h>
#endif /* ENABLE_UPLOADS */
#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
#include "asterisk/network.h"
#include "asterisk/cli.h"
@ -91,21 +87,6 @@ static struct server_args https_desc = {
static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri); /*!< list of supported handlers */
#ifdef ENABLE_UPLOADS
struct ast_http_post_mapping {
AST_RWLIST_ENTRY(ast_http_post_mapping) entry;
char *from;
char *to;
};
static AST_RWLIST_HEAD_STATIC(post_mappings, ast_http_post_mapping);
struct mime_cbinfo {
int count;
const char *post_dir;
};
#endif /* ENABLE_UPLOADS */
/* all valid URIs must be prepended by the string in prefix. */
static char prefix[MAX_PREFIX];
static int enablestatic;
@ -150,8 +131,7 @@ static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
return wkspace;
}
static struct ast_str *static_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method,
struct ast_variable *vars, int *status, char **title, int *contentlength)
static struct ast_str *static_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
char *path;
char *ftype;
@ -234,8 +214,7 @@ out403:
}
static struct ast_str *httpstatus_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method,
struct ast_variable *vars, int *status, char **title, int *contentlength)
static struct ast_str *httpstatus_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
struct ast_str *out = ast_str_create(512);
struct ast_variable *v;
@ -286,6 +265,8 @@ static struct ast_http_uri statusuri = {
.description = "Asterisk HTTP General Status",
.uri = "httpstatus",
.supports_get = 1,
.data = NULL,
.key = __FILE__,
};
static struct ast_http_uri staticuri = {
@ -295,6 +276,8 @@ static struct ast_http_uri staticuri = {
.has_subtree = 1,
.static_content = 1,
.supports_get = 1,
.data = NULL,
.key= __FILE__,
};
struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
@ -375,242 +358,20 @@ void ast_http_uri_unlink(struct ast_http_uri *urih)
AST_RWLIST_UNLOCK(&uris);
}
#ifdef ENABLE_UPLOADS
/*! \note This assumes that the post_mappings list is locked */
static struct ast_http_post_mapping *find_post_mapping(const char *uri)
void ast_http_uri_unlink_all_with_key(const char *key)
{
struct ast_http_post_mapping *post_map;
if (!ast_strlen_zero(prefix) && strncmp(prefix, uri, strlen(prefix))) {
ast_debug(1, "URI %s does not have prefix %s\n", uri, prefix);
return NULL;
}
uri += strlen(prefix);
if (*uri == '/') {
uri++;
}
AST_RWLIST_TRAVERSE(&post_mappings, post_map, entry) {
if (!strcmp(uri, post_map->from)) {
return post_map;
struct ast_http_uri *urih;
AST_RWLIST_WRLOCK(&uris);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) {
if (!strcmp(urih->key, key)) {
AST_RWLIST_REMOVE_CURRENT(entry);
}
}
return NULL;
AST_RWLIST_TRAVERSE_SAFE_END
}
static void post_raw(GMimePart *part, const char *post_dir, const char *fn)
{
char filename[PATH_MAX];
GMimeDataWrapper *content;
GMimeStream *stream;
int fd;
snprintf(filename, sizeof(filename), "%s/%s", post_dir, fn);
ast_debug(1, "Posting raw data to %s\n", filename);
if ((fd = open(filename, O_CREAT | O_WRONLY, 0666)) == -1) {
ast_log(LOG_WARNING, "Unable to open %s for writing file from a POST!\n", filename);
return;
}
stream = g_mime_stream_fs_new(fd);
content = g_mime_part_get_content_object(part);
g_mime_data_wrapper_write_to_stream(content, stream);
g_mime_stream_flush(stream);
g_object_unref(content);
g_object_unref(stream);
}
static GMimeMessage *parse_message(FILE *f)
{
GMimeMessage *message;
GMimeParser *parser;
GMimeStream *stream;
stream = g_mime_stream_file_new(f);
parser = g_mime_parser_new_with_stream(stream);
g_mime_parser_set_respect_content_length(parser, 1);
g_object_unref(stream);
message = g_mime_parser_construct_message(parser);
g_object_unref(parser);
return message;
}
static void process_message_callback(GMimeObject *part, gpointer user_data)
{
struct mime_cbinfo *cbinfo = user_data;
cbinfo->count++;
/* We strip off the headers before we get here, so should only see GMIME_IS_PART */
if (GMIME_IS_MESSAGE_PART(part)) {
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n");
return;
} else if (GMIME_IS_MESSAGE_PARTIAL(part)) {
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n");
return;
} else if (GMIME_IS_MULTIPART(part)) {
GList *l;
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n");
l = GMIME_MULTIPART(part)->subparts;
while (l) {
process_message_callback(l->data, cbinfo);
l = l->next;
}
} else if (GMIME_IS_PART(part)) {
const char *filename;
if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) {
ast_debug(1, "Skipping part with no filename\n");
return;
}
post_raw(GMIME_PART(part), cbinfo->post_dir, filename);
} else {
ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n");
}
}
static int process_message(GMimeMessage *message, const char *post_dir)
{
struct mime_cbinfo cbinfo = {
.count = 0,
.post_dir = post_dir,
};
g_mime_message_foreach_part(message, process_message_callback, &cbinfo);
return cbinfo.count;
}
static struct ast_str *handle_post(struct ast_tcptls_session_instance *ser, char *uri,
int *status, char **title, int *contentlength, struct ast_variable *headers,
struct ast_variable *cookies)
{
char buf[4096];
FILE *f;
size_t res;
struct ast_variable *var;
int content_len = 0;
struct ast_http_post_mapping *post_map;
const char *post_dir;
unsigned long ident = 0;
GMimeMessage *message;
int message_count = 0;
for (var = cookies; var; var = var->next) {
if (strcasecmp(var->name, "mansession_id")) {
continue;
}
if (sscanf(var->value, "%lx", &ident) != 1) {
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
return ast_http_error((*status = 401),
(*title = ast_strdup("Unauthorized")),
NULL, "You are not authorized to make this request.");
}
break;
}
if (!var) {
return ast_http_error((*status = 401),
(*title = ast_strdup("Unauthorized")),
NULL, "You are not authorized to make this request.");
}
if (!(f = tmpfile())) {
return NULL;
}
for (var = headers; var; var = var->next) {
if (!strcasecmp(var->name, "Content-Length")) {
if ((sscanf(var->value, "%u", &content_len)) != 1) {
ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n");
fclose(f);
return NULL;
}
ast_debug(1, "Got a Content-Length of %d\n", content_len);
} else if (!strcasecmp(var->name, "Content-Type")) {
fprintf(f, "Content-Type: %s\r\n\r\n", var->value);
}
}
for (res = sizeof(buf); content_len; content_len -= res) {
if (content_len < res) {
res = content_len;
}
fread(buf, 1, res, ser->f);
fwrite(buf, 1, res, f);
}
if (fseek(f, SEEK_SET, 0)) {
ast_debug(1, "Failed to seek temp file back to beginning.\n");
fclose(f);
return NULL;
}
AST_RWLIST_RDLOCK(&post_mappings);
if (!(post_map = find_post_mapping(uri))) {
ast_debug(1, "%s is not a valid URI for POST\n", uri);
AST_RWLIST_UNLOCK(&post_mappings);
return ast_http_error((*status = 404),
(*title = ast_strdup("Not Found")),
NULL, "The requested URL was not found on this server.");
}
post_dir = ast_strdupa(post_map->to);
post_map = NULL;
AST_RWLIST_UNLOCK(&post_mappings);
ast_debug(1, "Going to post files to dir %s\n", post_dir);
message = parse_message(f); /* Takes ownership and will close f */
if (!message) {
ast_log(LOG_ERROR, "Error parsing MIME data\n");
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
if (!(message_count = process_message(message, post_dir))) {
ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
return ast_http_error((*status = 200),
(*title = ast_strdup("OK")),
NULL, "File successfully uploaded.");
}
#endif /* ENABLE_UPLOADS */
static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method,
int *status, char **title, int *contentlength, struct ast_variable **cookies,
int *status, char **title, int *contentlength, struct ast_variable **cookies, struct ast_variable *headers,
unsigned int *static_content)
{
char *c;
@ -734,7 +495,7 @@ static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char
if (urih) {
*static_content = urih->static_content;
out = urih->callback(ser, uri, method, vars, status, title, contentlength);
out = urih->callback(ser, urih, uri, method, vars, headers, status, title, contentlength);
AST_RWLIST_UNLOCK(&uris);
} else if (saw_method) {
out = ast_http_error((*status = 404),
@ -910,7 +671,7 @@ static void *httpd_helper_thread(void *data)
"Attempt to use unimplemented / unsupported method");
} else { /* try to serve it */
out = handle_uri(ser, uri, (!strcasecmp(buf, "get")) ? AST_HTTP_GET : AST_HTTP_POST,
&status, &title, &contentlength, &vars, &static_content);
&status, &title, &contentlength, &vars, headers, &static_content);
}
/* If they aren't mopped up already, clean up the cookies */
@ -1026,55 +787,6 @@ static void add_redirect(const char *value)
AST_RWLIST_UNLOCK(&uri_redirects);
}
#ifdef ENABLE_UPLOADS
static void destroy_post_mapping(struct ast_http_post_mapping *post_map)
{
if (post_map->from) {
ast_free(post_map->from);
}
if (post_map->to) {
ast_free(post_map->to);
}
ast_free(post_map);
}
static void destroy_post_mappings(void)
{
struct ast_http_post_mapping *post_map;
AST_RWLIST_WRLOCK(&post_mappings);
while ((post_map = AST_RWLIST_REMOVE_HEAD(&post_mappings, entry))) {
destroy_post_mapping(post_map);
}
AST_RWLIST_UNLOCK(&post_mappings);
}
static void add_post_mapping(const char *from, const char *to)
{
struct ast_http_post_mapping *post_map;
if (!(post_map = ast_calloc(1, sizeof(*post_map)))) {
return;
}
if (!(post_map->from = ast_strdup(from))) {
destroy_post_mapping(post_map);
return;
}
if (!(post_map->to = ast_strdup(to))) {
destroy_post_mapping(post_map);
return;
}
AST_RWLIST_WRLOCK(&post_mappings);
AST_RWLIST_INSERT_TAIL(&post_mappings, post_map, entry);
AST_RWLIST_UNLOCK(&post_mappings);
}
#endif /* ENABLE_UPLOADS */
static int __ast_http_load(int reload)
{
struct ast_config *cfg;
@ -1115,10 +827,6 @@ static int __ast_http_load(int reload)
}
AST_RWLIST_UNLOCK(&uri_redirects);
#ifdef ENABLE_UPLOADS
destroy_post_mappings();
#endif /* ENABLE_UPLOADS */
if (cfg) {
v = ast_variable_browse(cfg, "general");
for (; v; v = v->next) {
@ -1165,12 +873,6 @@ static int __ast_http_load(int reload)
}
}
#ifdef ENABLE_UPLOADS
for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
add_post_mapping(v->name, v->value);
}
#endif /* ENABLE_UPLOADS */
ast_config_destroy(cfg);
}
@ -1197,10 +899,6 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a
struct ast_http_uri *urih;
struct http_uri_redirect *redirect;
#ifdef ENABLE_UPLOADS
struct ast_http_post_mapping *post_map;
#endif /* ENABLE_UPLOADS */
switch (cmd) {
case CLI_INIT:
e->command = "http show status";
@ -1251,17 +949,6 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a
}
AST_RWLIST_UNLOCK(&uri_redirects);
#ifdef ENABLE_UPLOADS
ast_cli(a->fd, "\nPOST mappings:\n");
AST_RWLIST_RDLOCK(&post_mappings);
AST_LIST_TRAVERSE(&post_mappings, post_map, entry) {
ast_cli(a->fd, "%s/%s => %s\n", prefix, post_map->from, post_map->to);
}
ast_cli(a->fd, "%s\n", AST_LIST_EMPTY(&post_mappings) ? "None.\n" : "");
AST_RWLIST_UNLOCK(&post_mappings);
#endif /* ENABLE_UPLOADS */
return CLI_SUCCESS;
}
@ -1276,10 +963,6 @@ static struct ast_cli_entry cli_http[] = {
int ast_http_init(void)
{
#ifdef ENABLE_UPLOADS
g_mime_init(0);
#endif /* ENABLE_UPLOADS */
ast_http_uri_link(&statusuri);
ast_http_uri_link(&staticuri);
ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));

View File

@ -3631,17 +3631,17 @@ generic_callback_out:
return out;
}
static struct ast_str *manager_http_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *params, int *status, char **title, int *contentlength)
static struct ast_str *manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
return generic_http_callback(FORMAT_HTML, &ser->requestor, uri, method, params, status, title, contentlength);
}
static struct ast_str *mxml_http_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *params, int *status, char **title, int *contentlength)
static struct ast_str *mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
return generic_http_callback(FORMAT_XML, &ser->requestor, uri, method, params, status, title, contentlength);
}
static struct ast_str *rawman_http_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method, struct ast_variable *params, int *status, char **title, int *contentlength)
static struct ast_str *rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
return generic_http_callback(FORMAT_RAW, &ser->requestor, uri, method, params, status, title, contentlength);
}
@ -3651,6 +3651,8 @@ struct ast_http_uri rawmanuri = {
.uri = "rawman",
.callback = rawman_http_callback,
.supports_get = 1,
.data = NULL,
.key = __FILE__,
};
struct ast_http_uri manageruri = {
@ -3658,6 +3660,8 @@ struct ast_http_uri manageruri = {
.uri = "manager",
.callback = manager_http_callback,
.supports_get = 1,
.data = NULL,
.key = __FILE__,
};
struct ast_http_uri managerxmluri = {
@ -3665,6 +3669,8 @@ struct ast_http_uri managerxmluri = {
.uri = "mxml",
.callback = mxml_http_callback,
.supports_get = 1,
.data = NULL,
.key = __FILE__,
};
static int registered = 0;

341
res/res_http_post.c Normal file
View File

@ -0,0 +1,341 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!
* \file
* \brief HTTP POST upload support for Asterisk HTTP server
*
* \author Terry Wilson <twilson@digium.com
*
* \ref AstHTTP - AMI over the http protocol
*/
/*** MODULEINFO
<depend>gmime</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision: 111213 $")
#include <sys/stat.h>
#include <fcntl.h>
#include <gmime/gmime.h>
#include "asterisk/linkedlists.h"
#include "asterisk/http.h"
#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
#include "asterisk/tcptls.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/ast_version.h"
#define MAX_PREFIX 80
/* just a little structure to hold callback info for gmime */
struct mime_cbinfo {
int count;
const char *post_dir;
};
/* all valid URIs must be prepended by the string in prefix. */
static char prefix[MAX_PREFIX];
static void post_raw(GMimePart *part, const char *post_dir, const char *fn)
{
char filename[PATH_MAX];
GMimeDataWrapper *content;
GMimeStream *stream;
int fd;
snprintf(filename, sizeof(filename), "%s/%s", post_dir, fn);
ast_debug(1, "Posting raw data to %s\n", filename);
if ((fd = open(filename, O_CREAT | O_WRONLY, 0666)) == -1) {
ast_log(LOG_WARNING, "Unable to open %s for writing file from a POST!\n", filename);
return;
}
stream = g_mime_stream_fs_new(fd);
content = g_mime_part_get_content_object(part);
g_mime_data_wrapper_write_to_stream(content, stream);
g_mime_stream_flush(stream);
g_object_unref(content);
g_object_unref(stream);
}
static GMimeMessage *parse_message(FILE *f)
{
GMimeMessage *message;
GMimeParser *parser;
GMimeStream *stream;
stream = g_mime_stream_file_new(f);
parser = g_mime_parser_new_with_stream(stream);
g_mime_parser_set_respect_content_length(parser, 1);
g_object_unref(stream);
message = g_mime_parser_construct_message(parser);
g_object_unref(parser);
return message;
}
static void process_message_callback(GMimeObject *part, gpointer user_data)
{
struct mime_cbinfo *cbinfo = user_data;
cbinfo->count++;
/* We strip off the headers before we get here, so should only see GMIME_IS_PART */
if (GMIME_IS_MESSAGE_PART(part)) {
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n");
return;
} else if (GMIME_IS_MESSAGE_PARTIAL(part)) {
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n");
return;
} else if (GMIME_IS_MULTIPART(part)) {
GList *l;
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n");
l = GMIME_MULTIPART(part)->subparts;
while (l) {
process_message_callback(l->data, cbinfo);
l = l->next;
}
} else if (GMIME_IS_PART(part)) {
const char *filename;
if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) {
ast_debug(1, "Skipping part with no filename\n");
return;
}
post_raw(GMIME_PART(part), cbinfo->post_dir, filename);
} else {
ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n");
}
}
static int process_message(GMimeMessage *message, const char *post_dir)
{
struct mime_cbinfo cbinfo = {
.count = 0,
.post_dir = post_dir,
};
g_mime_message_foreach_part(message, process_message_callback, &cbinfo);
return cbinfo.count;
}
static struct ast_str *http_post_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
struct ast_variable *var;
unsigned long ident = 0;
char buf[4096];
FILE *f;
size_t res;
int content_len = 0;
struct ast_str *post_dir;
GMimeMessage *message;
int message_count = 0;
if (!urih) {
return ast_http_error((*status = 400),
(*title = ast_strdup("Missing URI handle")),
NULL, "There was an error parsing the request");
}
for (var = vars; var; var = var->next) {
if (strcasecmp(var->name, "mansession_id")) {
continue;
}
if (sscanf(var->value, "%lx", &ident) != 1) {
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
return ast_http_error((*status = 401),
(*title = ast_strdup("Unauthorized")),
NULL, "You are not authorized to make this request.");
}
break;
}
if (!var) {
return ast_http_error((*status = 401),
(*title = ast_strdup("Unauthorized")),
NULL, "You are not authorized to make this request.");
}
if (!(f = tmpfile())) {
ast_log(LOG_ERROR, "Could not create temp file.\n");
return NULL;
}
for (var = headers; var; var = var->next) {
if (!strcasecmp(var->name, "Content-Length")) {
if ((sscanf(var->value, "%u", &content_len)) != 1) {
ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n");
fclose(f);
return NULL;
}
ast_debug(1, "Got a Content-Length of %d\n", content_len);
} else if (!strcasecmp(var->name, "Content-Type")) {
fprintf(f, "Content-Type: %s\r\n\r\n", var->value);
}
}
for (res = sizeof(buf); content_len; content_len -= res) {
if (content_len < res) {
res = content_len;
}
fread(buf, 1, res, ser->f);
fwrite(buf, 1, res, f);
}
if (fseek(f, SEEK_SET, 0)) {
ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n");
fclose(f);
return NULL;
}
post_dir = urih->data;
message = parse_message(f); /* Takes ownership and will close f */
if (!message) {
ast_log(LOG_ERROR, "Error parsing MIME data\n");
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
if (!(message_count = process_message(message, post_dir->str))) {
ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
return ast_http_error((*status = 400),
(*title = ast_strdup("Bad Request")),
NULL, "The was an error parsing the request.");
}
return ast_http_error((*status = 200),
(*title = ast_strdup("OK")),
NULL, "File successfully uploaded.");
}
static int __ast_http_post_load(int reload)
{
struct ast_config *cfg;
struct ast_variable *v;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
if ((cfg = ast_config_load2("http.conf", "http", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
}
if (reload) {
ast_http_uri_unlink_all_with_key(__FILE__);
}
if (cfg) {
for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
if (!strcasecmp(v->name, "prefix")) {
ast_copy_string(prefix, v->value, sizeof(prefix));
if (prefix[strlen(prefix)] == '/') {
prefix[strlen(prefix)] = '\0';
}
}
}
for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
struct ast_http_uri *urih;
struct ast_str *ds;
if (!(urih = ast_calloc(sizeof(*urih), 1))) {
return -1;
}
if (!(ds = ast_str_create(32)))
return -1;
urih->description = ast_strdup("HTTP POST mapping");
urih->uri = ast_strdup(v->name);
ast_str_set(&ds, 0, "%s/%s", prefix, v->value);
urih->data = ds;
urih->has_subtree = 0;
urih->supports_get = 0;
urih->supports_post = 1;
urih->callback = http_post_callback;
urih->key = __FILE__;
ast_http_uri_link(urih);
}
ast_config_destroy(cfg);
}
return 0;
}
static int unload_module(void)
{
ast_http_uri_unlink_all_with_key(__FILE__);
return 0;
}
static int reload(void)
{
__ast_http_post_load(1);
return AST_MODULE_LOAD_SUCCESS;
}
static int load_module(void)
{
g_mime_init(0);
__ast_http_post_load(0);
return AST_MODULE_LOAD_SUCCESS;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "HTTP POST support",
.load = load_module,
.unload = unload_module,
.reload = reload,
);

View File

@ -323,8 +323,7 @@ static int load_file(const char *filename, char **ret)
}
/*! \brief Callback that is executed everytime an http request is received by this module */
static struct ast_str *phoneprov_callback(struct ast_tcptls_session_instance *ser, const char *uri, enum ast_http_method method,
struct ast_variable *vars, int *status, char **title, int *contentlength)
static struct ast_str *phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *vars, struct ast_variable *headers, int *status, char **title, int *contentlength)
{
struct http_route *route;
struct http_route search_route = {
@ -987,6 +986,8 @@ static struct ast_http_uri phoneprovuri = {
.uri = "phoneprov",
.has_subtree = 1,
.supports_get = 1,
.data = NULL,
.key = __FILE__,
};
static int load_module(void)