#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"
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 int | find_sequence (char *inbuf, int inlen, char *matchbuf, int matchlen) |
static int | 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 *get_vars, struct ast_variable *headers) |
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 | readmimefile (FILE *fin, FILE *fout, char *boundary, int contentlen) |
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static char | prefix [MAX_PREFIX] |
Definition in file res_http_post.c.
#define MAX_PREFIX 80 |
Definition at line 53 of file res_http_post.c.
static int __ast_http_post_load | ( | int | reload | ) | [static] |
Definition at line 406 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(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, http_post_callback(), ast_variable::name, ast_variable::next, and ast_variable::value.
Referenced by load_module(), and reload().
00407 { 00408 struct ast_config *cfg; 00409 struct ast_variable *v; 00410 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 00411 00412 cfg = ast_config_load2("http.conf", "http", config_flags); 00413 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 00414 return 0; 00415 } 00416 00417 if (reload) { 00418 ast_http_uri_unlink_all_with_key(__FILE__); 00419 } 00420 00421 if (cfg) { 00422 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { 00423 if (!strcasecmp(v->name, "prefix")) { 00424 ast_copy_string(prefix, v->value, sizeof(prefix)); 00425 if (prefix[strlen(prefix)] == '/') { 00426 prefix[strlen(prefix)] = '\0'; 00427 } 00428 } 00429 } 00430 00431 for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next) { 00432 struct ast_http_uri *urih; 00433 struct ast_str *ds; 00434 00435 if (!(urih = ast_calloc(sizeof(*urih), 1))) { 00436 ast_config_destroy(cfg); 00437 return -1; 00438 } 00439 00440 if (!(ds = ast_str_create(32))) { 00441 ast_free(urih); 00442 ast_config_destroy(cfg); 00443 return -1; 00444 } 00445 00446 urih->description = ast_strdup("HTTP POST mapping"); 00447 urih->uri = ast_strdup(v->name); 00448 ast_str_set(&ds, 0, "%s", v->value); 00449 urih->data = ds; 00450 urih->has_subtree = 0; 00451 urih->callback = http_post_callback; 00452 urih->key = __FILE__; 00453 urih->mallocd = urih->dmallocd = 1; 00454 00455 ast_http_uri_link(urih); 00456 } 00457 00458 ast_config_destroy(cfg); 00459 } 00460 return 0; 00461 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 490 of file res_http_post.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 490 of file res_http_post.c.
static int find_sequence | ( | char * | inbuf, | |
int | inlen, | |||
char * | matchbuf, | |||
int | matchlen | |||
) | [static] |
Definition at line 160 of file res_http_post.c.
Referenced by readmimefile().
00161 { 00162 int current; 00163 int comp; 00164 int found = 0; 00165 00166 for (current = 0; current < inlen-matchlen; current++, inbuf++) { 00167 if (*inbuf == *matchbuf) { 00168 found=1; 00169 for (comp = 1; comp < matchlen; comp++) { 00170 if (inbuf[comp] != matchbuf[comp]) { 00171 found = 0; 00172 break; 00173 } 00174 } 00175 if (found) { 00176 break; 00177 } 00178 } 00179 } 00180 if (found) { 00181 return current; 00182 } else { 00183 return -1; 00184 } 00185 }
static int 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 * | get_vars, | |||
struct ast_variable * | headers | |||
) | [static] |
Definition at line 294 of file res_http_post.c.
References ast_http_error(), ast_http_get_cookies(), ast_http_manid_from_vars(), AST_HTTP_POST, astman_is_authed(), f, and var.
Referenced by __ast_http_post_load().
00295 { 00296 struct ast_variable *var, *cookies; 00297 unsigned long ident = 0; 00298 FILE *f; 00299 int content_len = 0; 00300 struct ast_str *post_dir; 00301 GMimeMessage *message; 00302 int message_count = 0; 00303 char * boundary_marker = NULL; 00304 00305 if (method != AST_HTTP_POST) { 00306 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method"); 00307 return -1; 00308 } 00309 00310 if (!astman_is_authed(ast_http_manid_from_vars(headers))) { 00311 ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave."); 00312 return -1; 00313 } 00314 00315 if (!urih) { 00316 ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request"); 00317 return -1; 00318 } 00319 00320 cookies = ast_http_get_cookies(headers); 00321 for (var = cookies; var; var = var->next) { 00322 if (!strcasecmp(var->name, "mansession_id")) { 00323 sscanf(var->value, "%30lx", &ident); 00324 break; 00325 } 00326 } 00327 if (cookies) { 00328 ast_variables_destroy(cookies); 00329 } 00330 00331 if (ident == 0) { 00332 ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); 00333 return -1; 00334 } 00335 if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) { 00336 ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request."); 00337 return -1; 00338 } 00339 00340 if (!(f = tmpfile())) { 00341 ast_log(LOG_ERROR, "Could not create temp file.\n"); 00342 ast_http_error(ser, 500, "Internal server error", "Could not create temp file."); 00343 return -1; 00344 } 00345 00346 for (var = headers; var; var = var->next) { 00347 fprintf(f, "%s: %s\r\n", var->name, var->value); 00348 00349 if (!strcasecmp(var->name, "Content-Length")) { 00350 if ((sscanf(var->value, "%30u", &content_len)) != 1) { 00351 ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n"); 00352 fclose(f); 00353 ast_http_error(ser, 500, "Internal server error", "Invalid Content-Length in POST request!"); 00354 return -1; 00355 } 00356 ast_debug(1, "Got a Content-Length of %d\n", content_len); 00357 } else if (!strcasecmp(var->name, "Content-Type")) { 00358 boundary_marker = strstr(var->value, "boundary="); 00359 if (boundary_marker) { 00360 boundary_marker += strlen("boundary="); 00361 } 00362 } 00363 } 00364 00365 fprintf(f, "\r\n"); 00366 00367 if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { 00368 if (option_debug) { 00369 ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n"); 00370 } 00371 fclose(f); 00372 00373 return -1; 00374 } 00375 00376 if (fseek(f, SEEK_SET, 0)) { 00377 ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n"); 00378 fclose(f); 00379 ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning."); 00380 return -1; 00381 } 00382 00383 post_dir = urih->data; 00384 00385 message = parse_message(f); /* Takes ownership and will close f */ 00386 00387 if (!message) { 00388 ast_log(LOG_ERROR, "Error parsing MIME data\n"); 00389 00390 ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); 00391 return -1; 00392 } 00393 00394 if (!(message_count = process_message(message, ast_str_buffer(post_dir)))) { 00395 ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n"); 00396 g_object_unref(message); 00397 ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request."); 00398 return -1; 00399 } 00400 g_object_unref(message); 00401 00402 ast_http_error(ser, 200, "OK", "File successfully uploaded."); 00403 return 0; 00404 }
static int load_module | ( | void | ) | [static] |
Definition at line 477 of file res_http_post.c.
References __ast_http_post_load(), and AST_MODULE_LOAD_SUCCESS.
00478 { 00479 g_mime_init(0); 00480 00481 __ast_http_post_load(0); 00482 00483 return AST_MODULE_LOAD_SUCCESS; 00484 }
static GMimeMessage* parse_message | ( | FILE * | f | ) | [static] |
Definition at line 91 of file res_http_post.c.
00092 { 00093 GMimeMessage *message; 00094 GMimeParser *parser; 00095 GMimeStream *stream; 00096 00097 stream = g_mime_stream_file_new(f); 00098 00099 parser = g_mime_parser_new_with_stream(stream); 00100 g_mime_parser_set_respect_content_length(parser, 1); 00101 00102 g_object_unref(stream); 00103 00104 message = g_mime_parser_construct_message(parser); 00105 00106 g_object_unref(parser); 00107 00108 return message; 00109 }
static void post_raw | ( | GMimePart * | part, | |
const char * | post_dir, | |||
const char * | fn | |||
) | [static] |
Definition at line 64 of file res_http_post.c.
References ast_debug, ast_log(), and LOG_WARNING.
Referenced by process_message_callback().
00065 { 00066 char filename[PATH_MAX]; 00067 GMimeDataWrapper *content; 00068 GMimeStream *stream; 00069 int fd; 00070 00071 snprintf(filename, sizeof(filename), "%s/%s", post_dir, fn); 00072 00073 ast_debug(1, "Posting raw data to %s\n", filename); 00074 00075 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666)) == -1) { 00076 ast_log(LOG_WARNING, "Unable to open %s for writing file from a POST!\n", filename); 00077 00078 return; 00079 } 00080 00081 stream = g_mime_stream_fs_new(fd); 00082 00083 content = g_mime_part_get_content_object(part); 00084 g_mime_data_wrapper_write_to_stream(content, stream); 00085 g_mime_stream_flush(stream); 00086 00087 g_object_unref(content); 00088 g_object_unref(stream); 00089 }
static int process_message | ( | GMimeMessage * | message, | |
const char * | post_dir | |||
) | [static] |
Definition at line 147 of file res_http_post.c.
References mime_cbinfo::count, and process_message_callback().
00148 { 00149 struct mime_cbinfo cbinfo = { 00150 .count = 0, 00151 .post_dir = post_dir, 00152 }; 00153 00154 g_mime_message_foreach_part(message, process_message_callback, &cbinfo); 00155 00156 return cbinfo.count; 00157 }
static void process_message_callback | ( | GMimeObject * | part, | |
gpointer | user_data | |||
) | [static] |
Definition at line 111 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().
00112 { 00113 struct mime_cbinfo *cbinfo = user_data; 00114 00115 cbinfo->count++; 00116 00117 /* We strip off the headers before we get here, so should only see GMIME_IS_PART */ 00118 if (GMIME_IS_MESSAGE_PART(part)) { 00119 ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n"); 00120 return; 00121 } else if (GMIME_IS_MESSAGE_PARTIAL(part)) { 00122 ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n"); 00123 return; 00124 } else if (GMIME_IS_MULTIPART(part)) { 00125 GList *l; 00126 00127 ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n"); 00128 l = GMIME_MULTIPART(part)->subparts; 00129 while (l) { 00130 process_message_callback(l->data, cbinfo); 00131 l = l->next; 00132 } 00133 } else if (GMIME_IS_PART(part)) { 00134 const char *filename; 00135 00136 if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) { 00137 ast_debug(1, "Skipping part with no filename\n"); 00138 return; 00139 } 00140 00141 post_raw(GMIME_PART(part), cbinfo->post_dir, filename); 00142 } else { 00143 ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n"); 00144 } 00145 }
static int readmimefile | ( | FILE * | fin, | |
FILE * | fout, | |||
char * | boundary, | |||
int | contentlen | |||
) | [static] |
Definition at line 196 of file res_http_post.c.
References ast_log(), errno, find_sequence(), fwrite, and LOG_WARNING.
00197 { 00198 int find_filename = 0; 00199 char buf[4096]; 00200 int marker; 00201 int x; 00202 int char_in_buf = 0; 00203 int num_to_read; 00204 int boundary_len; 00205 char * path_end, * path_start, * filespec; 00206 00207 if (NULL == fin || NULL == fout || NULL == boundary || 0 >= contentlen) { 00208 return -1; 00209 } 00210 00211 boundary_len = strlen(boundary); 00212 while (0 < contentlen || 0 < char_in_buf) { 00213 /* determine how much I will read into the buffer */ 00214 if (contentlen > sizeof(buf) - char_in_buf) { 00215 num_to_read = sizeof(buf)- char_in_buf; 00216 } else { 00217 num_to_read = contentlen; 00218 } 00219 00220 if (0 < num_to_read) { 00221 if (fread(&(buf[char_in_buf]), 1, num_to_read, fin) < num_to_read) { 00222 ast_log(LOG_WARNING, "fread() failed: %s\n", strerror(errno)); 00223 num_to_read = 0; 00224 } 00225 contentlen -= num_to_read; 00226 char_in_buf += num_to_read; 00227 } 00228 /* If I am looking for the filename spec */ 00229 if (find_filename) { 00230 path_end = filespec = NULL; 00231 x = strlen("filename=\""); 00232 marker = find_sequence(buf, char_in_buf, "filename=\"", x ); 00233 if (0 <= marker) { 00234 marker += x; /* Index beyond the filename marker */ 00235 path_start = &buf[marker]; 00236 for (path_end = path_start, x = 0; x < char_in_buf-marker; x++, path_end++) { 00237 if ('\\' == *path_end) { /* convert backslashses to forward slashes */ 00238 *path_end = '/'; 00239 } 00240 if ('\"' == *path_end) { /* If at the end of the file name spec */ 00241 *path_end = '\0'; /* temporarily null terminate the file spec for basename */ 00242 filespec = basename(path_start); 00243 *path_end = '\"'; 00244 break; 00245 } 00246 } 00247 } 00248 if (filespec) { /* If the file name path was found in the header */ 00249 if (fwrite(buf, 1, marker, fout) != marker) { 00250 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00251 } 00252 x = (int)(path_end+1 - filespec); 00253 if (fwrite(filespec, 1, x, fout) != x) { 00254 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00255 } 00256 x = (int)(path_end+1 - buf); 00257 memmove(buf, &(buf[x]), char_in_buf-x); 00258 char_in_buf -= x; 00259 } 00260 find_filename = 0; 00261 } else { /* I am looking for the boundary marker */ 00262 marker = find_sequence(buf, char_in_buf, boundary, boundary_len); 00263 if (0 > marker) { 00264 if (char_in_buf < (boundary_len)) { 00265 /*no possibility to find the boundary, write all you have */ 00266 if (fwrite(buf, 1, char_in_buf, fout) != char_in_buf) { 00267 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00268 } 00269 char_in_buf = 0; 00270 } else { 00271 /* write all except for area where the boundary marker could be */ 00272 if (fwrite(buf, 1, char_in_buf -(boundary_len -1), fout) != char_in_buf - (boundary_len - 1)) { 00273 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00274 } 00275 x = char_in_buf -(boundary_len -1); 00276 memmove(buf, &(buf[x]), char_in_buf-x); 00277 char_in_buf = (boundary_len -1); 00278 } 00279 } else { 00280 /* write up through the boundary, then look for filename in the rest */ 00281 if (fwrite(buf, 1, marker + boundary_len, fout) != marker + boundary_len) { 00282 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); 00283 } 00284 x = marker + boundary_len; 00285 memmove(buf, &(buf[x]), char_in_buf-x); 00286 char_in_buf -= marker + boundary_len; 00287 find_filename =1; 00288 } 00289 } 00290 } 00291 return 0; 00292 }
static int reload | ( | void | ) | [static] |
Definition at line 470 of file res_http_post.c.
References __ast_http_post_load(), and AST_MODULE_LOAD_SUCCESS.
00471 { 00472 __ast_http_post_load(1); 00473 00474 return AST_MODULE_LOAD_SUCCESS; 00475 }
static int unload_module | ( | void | ) | [static] |
Definition at line 463 of file res_http_post.c.
References ast_http_uri_unlink_all_with_key().
00464 { 00465 ast_http_uri_unlink_all_with_key(__FILE__); 00466 00467 return 0; 00468 }
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 490 of file res_http_post.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 490 of file res_http_post.c.
char prefix[MAX_PREFIX] [static] |
Definition at line 62 of file res_http_post.c.