[asterisk-commits] twilson: trunk r112426 - in /trunk: build_tools/ include/asterisk/ main/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 2 10:25:48 CDT 2008


Author: twilson
Date: Wed Apr  2 10:25:48 2008
New Revision: 112426

URL: http://svn.digium.com/view/asterisk?view=rev&rev=112426
Log:
Re-add HTTP post support by moving to res_http_post.c

Added:
    trunk/res/res_http_post.c   (with props)
Modified:
    trunk/build_tools/cflags.xml
    trunk/include/asterisk/http.h
    trunk/main/http.c
    trunk/main/manager.c
    trunk/res/res_phoneprov.c

Modified: trunk/build_tools/cflags.xml
URL: http://svn.digium.com/view/asterisk/trunk/build_tools/cflags.xml?view=diff&rev=112426&r1=112425&r2=112426
==============================================================================
--- trunk/build_tools/cflags.xml (original)
+++ trunk/build_tools/cflags.xml Wed Apr  2 10:25:48 2008
@@ -1,9 +1,5 @@
 	<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>

Modified: trunk/include/asterisk/http.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/http.h?view=diff&rev=112426&r1=112425&r2=112426
==============================================================================
--- trunk/include/asterisk/http.h (original)
+++ trunk/include/asterisk/http.h Wed Apr  2 10:25:48 2008
@@ -70,9 +70,9 @@
 	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 @@
 	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 @@
 /*! \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);
 

Modified: trunk/main/http.c
URL: http://svn.digium.com/view/asterisk/trunk/main/http.c?view=diff&rev=112426&r1=112425&r2=112426
==============================================================================
--- trunk/main/http.c (original)
+++ trunk/main/http.c Wed Apr  2 10:25:48 2008
@@ -38,10 +38,6 @@
 #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"
@@ -90,21 +86,6 @@
 };
 
 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];
@@ -150,8 +131,7 @@
 	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 @@
 }
 
 
-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 @@
 	.description = "Asterisk HTTP General Status",
 	.uri = "httpstatus",
 	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
 };
 	
 static struct ast_http_uri staticuri = {
@@ -295,6 +276,8 @@
 	.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 @@
 	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)
-{
-	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;
-		}
-	}
-
-	return NULL;
-}
-
-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 */
+void ast_http_uri_unlink_all_with_key(const char *key)
+{
+	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);
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END
+}
 
 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 @@
 
 	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 @@
 				     "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 @@
 	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;
@@ -1114,10 +826,6 @@
 		ast_free(redirect);
 	}
 	AST_RWLIST_UNLOCK(&uri_redirects);
-
-#ifdef ENABLE_UPLOADS
-	destroy_post_mappings();
-#endif /* ENABLE_UPLOADS */
 
 	if (cfg) {
 		v = ast_variable_browse(cfg, "general");
@@ -1165,12 +873,6 @@
 			}
 		}
 
-#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);
 	}
 
@@ -1196,10 +898,6 @@
 {
 	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:
@@ -1251,17 +949,6 @@
 	}
 	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 @@
 
 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));

Modified: trunk/main/manager.c
URL: http://svn.digium.com/view/asterisk/trunk/main/manager.c?view=diff&rev=112426&r1=112425&r2=112426
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Wed Apr  2 10:25:48 2008
@@ -3631,17 +3631,17 @@
 	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 @@
 	.uri = "rawman",
 	.callback = rawman_http_callback,
 	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
 };
 
 struct ast_http_uri manageruri = {
@@ -3658,6 +3660,8 @@
 	.uri = "manager",
 	.callback = manager_http_callback,
 	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
 };
 
 struct ast_http_uri managerxmluri = {
@@ -3665,6 +3669,8 @@
 	.uri = "mxml",
 	.callback = mxml_http_callback,
 	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
 };
 
 static int registered = 0;

Added: trunk/res/res_http_post.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_http_post.c?view=auto&rev=112426
==============================================================================
--- trunk/res/res_http_post.c (added)
+++ trunk/res/res_http_post.c Wed Apr  2 10:25:48 2008
@@ -1,0 +1,341 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster at 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 at 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,
+);

Propchange: trunk/res/res_http_post.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/res/res_http_post.c
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Propchange: trunk/res/res_http_post.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/res/res_phoneprov.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_phoneprov.c?view=diff&rev=112426&r1=112425&r2=112426
==============================================================================
--- trunk/res/res_phoneprov.c (original)
+++ trunk/res/res_phoneprov.c Wed Apr  2 10:25:48 2008
@@ -323,8 +323,7 @@
 }
 
 /*! \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 @@
 	.uri = "phoneprov",
 	.has_subtree = 1,
 	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
 };
 
 static int load_module(void)




More information about the asterisk-commits mailing list