[svn-commits] dbailey: trunk r151722 - /trunk/res/res_http_post.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Oct 23 10:09:20 CDT 2008


Author: dbailey
Date: Thu Oct 23 10:09:20 2008
New Revision: 151722

URL: http://svn.digium.com/view/asterisk?view=rev&rev=151722
Log:
Add patch to handle how IE7 issues POST requests using Window path spec including backslash delimiters

Modified:
    trunk/res/res_http_post.c

Modified: trunk/res/res_http_post.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_http_post.c?view=diff&rev=151722&r1=151721&r2=151722
==============================================================================
--- trunk/res/res_http_post.c (original)
+++ trunk/res/res_http_post.c Thu Oct 23 10:09:20 2008
@@ -153,17 +153,140 @@
 	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 @@
 				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;
-		}
-		fread(buf, 1, res, ser->f);
-		fwrite(buf, 1, res, f);
+	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");
+		}
+		fclose(f);
+		
+		return NULL;
 	}
 
 	if (fseek(f, SEEK_SET, 0)) {




More information about the svn-commits mailing list