From 9fe75b494ac0b0e44d30204f7347a1611d12cc6e Mon Sep 17 00:00:00 2001 From: Doug Bailey <dbailey@digium.com> Date: Thu, 23 Oct 2008 15:09:20 +0000 Subject: [PATCH] Add patch to handle how IE7 issues POST requests using Window path spec including backslash delimiters git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@151722 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_http_post.c | 143 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 7 deletions(-) diff --git a/res/res_http_post.c b/res/res_http_post.c index 3e265c4d5b..28a78e60ae 100644 --- a/res/res_http_post.c +++ b/res/res_http_post.c @@ -153,17 +153,140 @@ static int process_message(GMimeMessage *message, const char *post_dir) return cbinfo.count; } + +/* Find a sequence of bytes within a binary array. */ +static int find_sequence(char * inbuf, int inlen, char * matchbuf, int matchlen) +{ + int current; + int comp; + int found = 0; + + for (current = 0; current < inlen-matchlen; current++, inbuf++) { + if (*inbuf == *matchbuf) { + found=1; + for (comp = 1; comp < matchlen; comp++) { + if (inbuf[comp] != matchbuf[comp]) { + found = 0; + break; + } + } + if (found) { + break; + } + } + } + if (found) { + return current; + } else { + return -1; + } +} + +/* +* The following is a work around to deal with how IE7 embeds the local file name +* within the Mime header using full WINDOWS file path with backslash directory delimiters. +* This section of code attempts to isolate the directory path and remove it +* from what is written into the output file. In addition, it changes +* esc chars (i.e. backslashes) to forward slashes. +* This function has two modes. The first to find a boundary marker. The +* second is to find the filename immediately after the boundary. +*/ +static int readmimefile(FILE * fin, FILE * fout, char * boundary, int contentlen) +{ + int find_filename = 0; + char buf[4096]; + int marker; + int x; + int char_in_buf = 0; + int num_to_read; + int boundary_len; + char * path_end, * path_start, * filespec; + + if (NULL == fin || NULL == fout || NULL == boundary || 0 >= contentlen) { + return -1; + } + + boundary_len = strlen(boundary); + while (0 < contentlen || 0 < char_in_buf) { + /* determine how much I will read into the buffer */ + if (contentlen > sizeof(buf) - char_in_buf) { + num_to_read = sizeof(buf)- char_in_buf; + } else { + num_to_read = contentlen; + } + + if(0 < num_to_read) { + fread(&(buf[char_in_buf]), 1, num_to_read, fin); + contentlen -= num_to_read; + char_in_buf += num_to_read; + } + /* If I am looking for the filename spec */ + if (find_filename) { + path_end = filespec = NULL; + x = strlen("filename=\""); + marker = find_sequence(buf, char_in_buf, "filename=\"", x ); + if (0 <= marker) { + marker += x; /* Index beyond the filename marker */ + path_start = &buf[marker]; + for (path_end = path_start, x = 0; x < char_in_buf-marker; x++, path_end++) { + if ('\\' == *path_end) { /* convert backslashses to forward slashes */ + *path_end = '/'; + } + if ('\"' == *path_end) { /* If at the end of the file name spec */ + *path_end = '\0'; /* temporarily null terminate the file spec for basename */ + filespec = basename(path_start); + *path_end = '\"'; + break; + } + } + } + if (filespec) { /* If the file name path was found in the header */ + fwrite(buf, 1, marker, fout); + x = (int)(path_end+1 - filespec); + fwrite(filespec, 1, x, fout); + x = (int)(path_end+1 - buf); + memmove(buf, &(buf[x]), char_in_buf-x); + char_in_buf -= x; + } + find_filename = 0; + } else { /* I am looking for the boundary marker */ + marker = find_sequence(buf, char_in_buf, boundary, boundary_len); + if (0 > marker) { + if (char_in_buf < (boundary_len)) { + /*no possibility to find the boundary, write all you have */ + fwrite(buf, 1, char_in_buf, fout); + char_in_buf = 0; + } else { + /* write all except for area where the boundary marker could be */ + fwrite(buf, 1, char_in_buf -(boundary_len -1), fout); + x = char_in_buf -(boundary_len -1); + memmove(buf, &(buf[x]), char_in_buf-x); + char_in_buf = (boundary_len -1); + } + } else { + /* write up through the boundary, then look for filename in the rest */ + fwrite(buf, 1, marker + boundary_len, fout); + x = marker + boundary_len; + memmove(buf, &(buf[x]), char_in_buf-x); + char_in_buf -= marker + boundary_len; + find_filename =1; + } + } + } + return 0; +} + + 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; + char * boundary_marker = NULL; if (!urih) { return ast_http_error((*status = 400), @@ -213,17 +336,23 @@ static struct ast_str *http_post_callback(struct ast_tcptls_session_instance *se return NULL; } ast_debug(1, "Got a Content-Length of %d\n", content_len); + } else if (!strcasecmp(var->name, "Content-Type")) { + boundary_marker = strstr(var->value, "boundary="); + if (boundary_marker) { + boundary_marker += strlen("boundary="); + } } } fprintf(f, "\r\n"); - for (res = sizeof(buf); content_len; content_len -= res) { - if (content_len < res) { - res = content_len; + if (0 > readmimefile(ser->f, f, boundary_marker, content_len)) { + if (option_debug) { + ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n"); } - fread(buf, 1, res, ser->f); - fwrite(buf, 1, res, f); + fclose(f); + + return NULL; } if (fseek(f, SEEK_SET, 0)) { -- GitLab