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