Wed Oct 28 11:53:06 2009

Asterisk developer's documentation


res_http_post.c File Reference

HTTP POST upload support for Asterisk HTTP server. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <gmime/gmime.h>
#include "asterisk/linkedlists.h"
#include "asterisk/http.h"
#include "asterisk/paths.h"
#include "asterisk/tcptls.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/ast_version.h"

Include dependency graph for res_http_post.c:

Go to the source code of this file.

Data Structures

struct  mime_cbinfo

Defines

#define MAX_PREFIX   80

Functions

static int __ast_http_post_load (int reload)
static void __reg_module (void)
static void __unreg_module (void)
static struct ast_strhttp_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)
static int load_module (void)
static GMimeMessage * parse_message (FILE *f)
static void post_raw (GMimePart *part, const char *post_dir, const char *fn)
static int process_message (GMimeMessage *message, const char *post_dir)
static void process_message_callback (GMimeObject *part, gpointer user_data)
static int reload (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP POST support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static char prefix [MAX_PREFIX]


Detailed Description

HTTP POST upload support for Asterisk HTTP server.

Author:
Terry Wilson <twilson@digium.com
AMI over HTTP support - AMI over the http protocol

Definition in file res_http_post.c.


Define Documentation

#define MAX_PREFIX   80

Definition at line 50 of file res_http_post.c.


Function Documentation

static int __ast_http_post_load ( int  reload  )  [static]

Definition at line 269 of file res_http_post.c.

References ast_calloc, ast_config_destroy(), ast_config_load2(), ast_copy_string(), ast_free, ast_http_uri_link(), ast_http_uri_unlink_all_with_key(), ast_str_create(), ast_str_set(), ast_strdup, ast_variable_browse(), ast_http_uri::callback, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, ast_http_uri::data, ast_http_uri::description, ast_http_uri::dmallocd, ast_http_uri::has_subtree, http_post_callback(), ast_http_uri::key, ast_http_uri::mallocd, ast_variable::name, ast_variable::next, ast_http_uri::supports_get, ast_http_uri::supports_post, ast_http_uri::uri, and ast_variable::value.

Referenced by load_module(), and reload().

00270 {
00271    struct ast_config *cfg;
00272    struct ast_variable *v;
00273    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00274 
00275    if ((cfg = ast_config_load2("http.conf", "http", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
00276       return 0;
00277    }
00278 
00279    if (reload) {
00280       ast_http_uri_unlink_all_with_key(__FILE__);
00281    }
00282 
00283    if (cfg) {
00284       for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
00285          if (!strcasecmp(v->name, "prefix")) {
00286             ast_copy_string(prefix, v->value, sizeof(prefix));
00287             if (prefix[strlen(prefix)] == '/') {
00288                prefix[strlen(prefix)] = '\0';
00289             }
00290          }
00291       }
00292 
00293       for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) {
00294          struct ast_http_uri *urih;
00295          struct ast_str *ds;
00296 
00297          if (!(urih = ast_calloc(sizeof(*urih), 1))) {
00298             ast_config_destroy(cfg);
00299             return -1;
00300          }
00301 
00302          if (!(ds = ast_str_create(32))) {
00303             ast_free(urih);
00304             ast_config_destroy(cfg);
00305             return -1;
00306          }
00307 
00308          urih->description = ast_strdup("HTTP POST mapping");
00309          urih->uri = ast_strdup(v->name);
00310          ast_str_set(&ds, 0, "%s", v->value);
00311          urih->data = ds;
00312          urih->has_subtree = 0;
00313          urih->supports_get = 0;
00314          urih->supports_post = 1;
00315          urih->callback = http_post_callback;
00316          urih->key = __FILE__;
00317          urih->mallocd = urih->dmallocd = 1;
00318 
00319          ast_http_uri_link(urih);
00320       }
00321 
00322       ast_config_destroy(cfg);
00323    }
00324    return 0;
00325 }

static void __reg_module ( void   )  [static]

Definition at line 354 of file res_http_post.c.

static void __unreg_module ( void   )  [static]

Definition at line 354 of file res_http_post.c.

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 
) [static, read]

Definition at line 156 of file res_http_post.c.

References ast_debug, ast_http_error(), ast_log(), ast_strdup, astman_verify_session_writepermissions(), buf, ast_http_uri::data, errno, EVENT_FLAG_CONFIG, ast_tcptls_session_instance::f, f, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, parse_message(), process_message(), ast_str::str, ast_variable::value, and var.

Referenced by __ast_http_post_load().

00157 {
00158    struct ast_variable *var;
00159    unsigned long ident = 0;
00160    char buf[4096];
00161    FILE *f;
00162    size_t res;
00163    int content_len = 0;
00164    struct ast_str *post_dir;
00165    GMimeMessage *message;
00166    int message_count = 0;
00167 
00168    if (!urih) {
00169       return ast_http_error((*status = 400),
00170             (*title = ast_strdup("Missing URI handle")),
00171             NULL, "There was an error parsing the request");
00172    }
00173 
00174    for (var = vars; var; var = var->next) {
00175       if (strcasecmp(var->name, "mansession_id")) {
00176          continue;
00177       }
00178 
00179       if (sscanf(var->value, "%30lx", &ident) != 1) {
00180          return ast_http_error((*status = 400),
00181                      (*title = ast_strdup("Bad Request")),
00182                      NULL, "The was an error parsing the request.");
00183       }
00184 
00185       if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
00186          return ast_http_error((*status = 401),
00187                      (*title = ast_strdup("Unauthorized")),
00188                      NULL, "You are not authorized to make this request.");
00189       }
00190 
00191       break;
00192    }
00193 
00194    if (!var) {
00195       return ast_http_error((*status = 401),
00196                   (*title = ast_strdup("Unauthorized")),
00197                   NULL, "You are not authorized to make this request.");
00198    }
00199 
00200    if (!(f = tmpfile())) {
00201       ast_log(LOG_ERROR, "Could not create temp file.\n");
00202       return NULL;
00203    }
00204 
00205    for (var = headers; var; var = var->next) {
00206       fprintf(f, "%s: %s\r\n", var->name, var->value);
00207 
00208       if (!strcasecmp(var->name, "Content-Length")) {
00209          if ((sscanf(var->value, "%30u", &content_len)) != 1) {
00210             ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n");
00211             fclose(f);
00212 
00213             return NULL;
00214          }
00215          ast_debug(1, "Got a Content-Length of %d\n", content_len);
00216       }
00217    }
00218 
00219    fprintf(f, "\r\n");
00220 
00221    for (res = sizeof(buf); content_len; content_len -= res) {
00222       if (content_len < res) {
00223          res = content_len;
00224       }
00225       if (fread(buf, 1, res, ser->f) != res) {
00226          ast_log(LOG_WARNING, "fread() failed: %s\n", strerror(errno));
00227          continue;
00228       }
00229       if (fwrite(buf, 1, res, f) != res) {
00230          ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00231          continue;
00232       }
00233    }
00234 
00235    if (fseek(f, SEEK_SET, 0)) {
00236       ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n");
00237       fclose(f);
00238 
00239       return NULL;
00240    }
00241 
00242    post_dir = urih->data;
00243 
00244    message = parse_message(f); /* Takes ownership and will close f */
00245 
00246    if (!message) {
00247       ast_log(LOG_ERROR, "Error parsing MIME data\n");
00248 
00249       return ast_http_error((*status = 400),
00250                   (*title = ast_strdup("Bad Request")),
00251                   NULL, "The was an error parsing the request.");
00252    }
00253 
00254    if (!(message_count = process_message(message, post_dir->str))) {
00255       ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
00256       g_object_unref(message);
00257       return ast_http_error((*status = 400),
00258                   (*title = ast_strdup("Bad Request")),
00259                   NULL, "The was an error parsing the request.");
00260    }
00261 
00262    g_object_unref(message);
00263 
00264    return ast_http_error((*status = 200),
00265                (*title = ast_strdup("OK")),
00266                NULL, "File successfully uploaded.");
00267 }

static int load_module ( void   )  [static]

Definition at line 341 of file res_http_post.c.

References __ast_http_post_load(), and AST_MODULE_LOAD_SUCCESS.

00342 {
00343    g_mime_init(0);
00344 
00345    __ast_http_post_load(0);
00346 
00347    return AST_MODULE_LOAD_SUCCESS;
00348 }

static GMimeMessage* parse_message ( FILE *  f  )  [static]

Definition at line 88 of file res_http_post.c.

Referenced by http_post_callback().

00089 {
00090    GMimeMessage *message;
00091    GMimeParser *parser;
00092    GMimeStream *stream;
00093 
00094    stream = g_mime_stream_file_new(f);
00095 
00096    parser = g_mime_parser_new_with_stream(stream);
00097    g_mime_parser_set_respect_content_length(parser, 1);
00098    
00099    g_object_unref(stream);
00100 
00101    message = g_mime_parser_construct_message(parser);
00102 
00103    g_object_unref(parser);
00104 
00105    return message;
00106 }

static void post_raw ( GMimePart *  part,
const char *  post_dir,
const char *  fn 
) [static]

Definition at line 61 of file res_http_post.c.

References ast_debug, ast_log(), and LOG_WARNING.

Referenced by process_message_callback().

00062 {
00063    char filename[PATH_MAX];
00064    GMimeDataWrapper *content;
00065    GMimeStream *stream;
00066    int fd;
00067 
00068    snprintf(filename, sizeof(filename), "%s/%s", post_dir, fn);
00069 
00070    ast_debug(1, "Posting raw data to %s\n", filename);
00071 
00072    if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666)) == -1) {
00073       ast_log(LOG_WARNING, "Unable to open %s for writing file from a POST!\n", filename);
00074 
00075       return;
00076    }
00077 
00078    stream = g_mime_stream_fs_new(fd);
00079 
00080    content = g_mime_part_get_content_object(part);
00081    g_mime_data_wrapper_write_to_stream(content, stream);
00082    g_mime_stream_flush(stream);
00083 
00084    g_object_unref(content);
00085    g_object_unref(stream);
00086 }

static int process_message ( GMimeMessage *  message,
const char *  post_dir 
) [static]

Definition at line 144 of file res_http_post.c.

References mime_cbinfo::count, and process_message_callback().

00145 {
00146    struct mime_cbinfo cbinfo = {
00147       .count = 0,
00148       .post_dir = post_dir,
00149    };
00150 
00151    g_mime_message_foreach_part(message, process_message_callback, &cbinfo);
00152 
00153    return cbinfo.count;
00154 }

static void process_message_callback ( GMimeObject *  part,
gpointer  user_data 
) [static]

Definition at line 108 of file res_http_post.c.

References ast_debug, ast_log(), ast_strlen_zero(), mime_cbinfo::count, LOG_ERROR, LOG_WARNING, mime_cbinfo::post_dir, and post_raw().

Referenced by process_message().

00109 {
00110    struct mime_cbinfo *cbinfo = user_data;
00111 
00112    cbinfo->count++;
00113 
00114    /* We strip off the headers before we get here, so should only see GMIME_IS_PART */
00115    if (GMIME_IS_MESSAGE_PART(part)) {
00116       ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n");
00117       return;
00118    } else if (GMIME_IS_MESSAGE_PARTIAL(part)) {
00119       ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n");
00120       return;
00121    } else if (GMIME_IS_MULTIPART(part)) {
00122       GList *l;
00123       
00124       ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n");
00125       l = GMIME_MULTIPART(part)->subparts;
00126       while (l) {
00127          process_message_callback(l->data, cbinfo);
00128          l = l->next;
00129       }
00130    } else if (GMIME_IS_PART(part)) {
00131       const char *filename;
00132 
00133       if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) {
00134          ast_debug(1, "Skipping part with no filename\n");
00135          return;
00136       }
00137 
00138       post_raw(GMIME_PART(part), cbinfo->post_dir, filename);
00139    } else {
00140       ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n");
00141    }
00142 }

static int reload ( void   )  [static]

Definition at line 334 of file res_http_post.c.

References __ast_http_post_load(), and AST_MODULE_LOAD_SUCCESS.

00335 {
00336    __ast_http_post_load(1);
00337 
00338    return AST_MODULE_LOAD_SUCCESS;
00339 }

static int unload_module ( void   )  [static]

Definition at line 327 of file res_http_post.c.

References ast_http_uri_unlink_all_with_key().

00328 {
00329    ast_http_uri_unlink_all_with_key(__FILE__);
00330 
00331    return 0;
00332 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "HTTP POST support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 354 of file res_http_post.c.

Definition at line 354 of file res_http_post.c.

char prefix[MAX_PREFIX] [static]

Definition at line 59 of file res_http_post.c.


Generated on Wed Oct 28 11:53:06 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6