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