public inbox for ecos-discuss@sourceware.org
 help / color / mirror / Atom feed
* [ECOS] athttpd file upload wip
@ 2007-11-15  7:41 Øyvind Harboe
  2007-11-16  7:07 ` [ECOS] " Øyvind Harboe
  0 siblings, 1 reply; 2+ messages in thread
From: Øyvind Harboe @ 2007-11-15  7:41 UTC (permalink / raw)
  To: eCos Discussion

I've tried this on IE & Firefox and it works. I'll have to do
something about the
performance for it to be usable in our product. This is the first time
I've implemented
this sort of thing, so the code does have some of that elegance that stems from
discovering how things work and doing a first implementation :-)


This Jim Tcl script implements a file upload test page:

set form_filename [formfetch form_filename];
set form_action [formfetch form_action];
set form_filecontent [formfetch form_filecontent];

set post ""
catch {set post $post_data} err


puts "Post data: $post"

puts "Action $form_action"


set data ""
append data {<html><body><form enctype="multipart/form-data"
action="upload.tcl" method="post">}
if {[string compare $form_action "Upload"]==0} {
	set fp [aio.open $form_filename w];
	$fp puts -nonewline $form_filecontent
	$fp close
	append data "<br>Wrote $form_filename, [string length
$form_filecontent] bytes<br>"
}

append data {<a href="index.tcl">Main menu</a><br>}
append data {File upload...<br>}
append data {Filename: <input type="text" name="form_filename"> <br>}
append data {<input type="file" name="form_filecontent"> <br>}
append data {<input type="submit" name="form_action" value="Upload" ><br> }
append data {</form></body></html> }

start_chunked "html";
write_chunked $data;
end_chunked;


-- 
Øyvind Harboe
http://www.zylin.com - eCos ARM & FPGA  developer kit

--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [ECOS] Re: athttpd file upload wip
  2007-11-15  7:41 [ECOS] athttpd file upload wip Øyvind Harboe
@ 2007-11-16  7:07 ` Øyvind Harboe
  0 siblings, 0 replies; 2+ messages in thread
From: Øyvind Harboe @ 2007-11-16  7:07 UTC (permalink / raw)
  To: eCos Discussion

[-- Attachment #1: Type: text/plain, Size: 436 bytes --]

Forgot the actual patch. Better performance than first try, but really
the API needs to change to use
a single pass through the post data to make real headway
w/performance. Also it is
possible to avoid the memcpy() & allocation as pointer directly to
post data + length can be returned for each form variable is possible as the
data is not encoded.


-- 
Øyvind Harboe
http://www.zylin.com - eCos ARM & FPGA  developer kit

[-- Attachment #2: athttpdupload2.txt --]
[-- Type: text/plain, Size: 23175 bytes --]

### Eclipse Workspace Patch 1.0
#P ecos
Index: net/athttpd/current/include/forms.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/include/forms.h,v
retrieving revision 1.1
diff -u -r1.1 forms.h
--- net/athttpd/current/include/forms.h	18 Jul 2006 16:37:24 -0000	1.1
+++ net/athttpd/current/include/forms.h	15 Nov 2007 19:20:56 -0000
@@ -73,6 +73,8 @@
 
 // Prototypes.
 char *cyg_httpd_store_form_data(char*);
+void
+cyg_httpd_fetch_form_data(char *name, char *buffer, int len, int *actual);
 void cyg_httpd_handle_method_POST(void);
 cyg_int8 cyg_httpd_from_hex (cyg_int8);
 char *cyg_httpd_find_form_variable(char*);
Index: net/athttpd/current/include/http.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/include/http.h,v
retrieving revision 1.2
diff -u -r1.2 http.h
--- net/athttpd/current/include/http.h	27 Nov 2006 15:41:56 -0000	1.2
+++ net/athttpd/current/include/http.h	15 Nov 2007 19:20:56 -0000
@@ -102,6 +102,7 @@
 #define CYG_HTTPD_MODE_SEND_HEADER_ONLY       0x0004
 #define CYG_HTTPD_MODE_NO_CACHE               0x0008
 #define CYG_HTTPD_MODE_FORM_DATA              0x0010
+#define CYG_HTTPD_MODE_MULTIPART_FORM_DATA    0x0020
 
 // This must be generated at random...
 #define CYG_HTTPD_MD5_AUTH_NAME                "MD5"
@@ -175,6 +176,8 @@
     //  data (it might come in more than one frame)  and must be visible to
     //  handlers and cgi scripts.
     char        *post_data;
+    // the boundary string used for multipart/form-data
+    char		*boundary;
 
     // This pointer points to the information about the domain that needs
     //  to be authenticated. It is only used by the function that builds the
Index: net/athttpd/current/src/cgi.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/cgi.c,v
retrieving revision 1.3
diff -u -r1.3 cgi.c
--- net/athttpd/current/src/cgi.c	27 Nov 2006 15:41:56 -0000	1.3
+++ net/athttpd/current/src/cgi.c	15 Nov 2007 19:20:57 -0000
@@ -157,10 +157,89 @@
 }
 #endif
 
+/* We're not going to write ad-hoc CGI scripts without good old printf! */
+void cyg_httpd_fprintf(char *format, ...)
+{
+	char *buffer = NULL;
+	int size = 1;
+	int n=-1;
+	va_list ap;
+	va_start(ap, format);
+	diag_vprintf(format, ap);
+	va_end(ap);
+	
+	
+	/* process format string */
+	for (;;)
+	{
+		buffer=malloc(size);
+		if (buffer==NULL)
+		{
+			return;
+		}
+		
+		va_start(ap, format);
+		n = vsnprintf(buffer, size, format, ap);
+		va_end(ap);
+		if (n>0 && n < (size-1))
+			break;
+		size=size*2+1;
+		free(buffer);
+	}
+	
+	if (n > 0)
+	{
+		cyg_httpd_write_chunked(buffer, strlen(buffer));
+	} else
+	{
+		/* vsnprintf failed */
+	}
+	
+	if (buffer)
+		free(buffer);
+}
+
+
 // =============================================================================
 // tcl CGI Support
 // =============================================================================
 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
+
+
+/* Error message has to go to HTTP to make debugging less of a torturous process */
+void cyg_httpd_exec_cgi_tcl_error(Jim_Interp *interp)
+{
+    int len, i;
+
+    cyg_httpd_start_chunked("html");
+    cyg_httpd_fprintf("<html><body>\n");
+    
+    cyg_httpd_fprintf("Runtime error, file \"%s\", line %d:<br>" ,
+            interp->errorFileName, interp->errorLine);
+    cyg_httpd_fprintf("    %s<br>" ,
+            Jim_GetString(interp->result, NULL));
+    Jim_ListLength(interp, interp->stackTrace, &len);
+    for (i = 0; i < len; i+= 3) {
+        Jim_Obj *objPtr;
+        const char *proc, *file, *line;
+
+        Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
+        proc = Jim_GetString(objPtr, NULL);
+        Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
+                JIM_NONE);
+        file = Jim_GetString(objPtr, NULL);
+        Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
+                JIM_NONE);
+        line = Jim_GetString(objPtr, NULL);
+        cyg_httpd_fprintf("In procedure '%s' called at file \"%s\", line %s<br>" ,
+                proc, file, line);
+    }
+    cyg_httpd_fprintf("</html></body>\n");
+    
+    cyg_httpd_end_chunked();
+}
+
+
 int Jim_AioInit(Jim_Interp *);
 cyg_int32
 cyg_httpd_exec_cgi_tcl(char *file_name)
@@ -184,7 +263,12 @@
                                   "post_data", 
                                   httpstate.post_data);
      
-    Jim_Eval(httpstate.jim_interp, tcl_cmd);
+    int err;
+    err=Jim_Eval(httpstate.jim_interp, tcl_cmd);
+    if (err!=JIM_OK)
+    {
+    	cyg_httpd_exec_cgi_tcl_error(httpstate.jim_interp);
+    }
     return 0;
 }
 
@@ -217,10 +301,45 @@
     cyg_httpd_end_chunked();
     return JIM_OK;
 }
-  
+
+int
+cyg_httpd_Jim_Command_formfetch(Jim_Interp *interp, 
+                                   int argc,
+                                   Jim_Obj *const *argv)
+{
+    char *name = (char*)Jim_GetString(argv[1], NULL);
+	
+	// Find length
+	char buf;
+    int actual;
+    cyg_httpd_fetch_form_data(name, &buf, 1, &actual);
+
+    int len=actual+1;
+    char *destBuffer=malloc(len);
+    if (destBuffer==NULL)
+        return JIM_ERR;
+	    	
+    cyg_httpd_fetch_form_data(name, destBuffer, len, &actual);
+	    
+    Jim_Obj *objPtr;
+  	objPtr = Jim_NewStringObj(interp, destBuffer, actual);
+    Jim_SetResult(interp, objPtr);
+    free(destBuffer);
+    return JIM_OK;
+}
+
+
+// If the application wants to add commands, it will need to do so after the
+// interpreter has been initialized. However, the initialization of the http
+// server is asynchronous. This function is safe to invoke *before* the http
+// server is started.
 void
 cyg_httpd_init_tcl_interpreter(void)
 {
+	static bool initDone=false;
+	if (initDone)
+		return;
+	initDone=true;
     // Start the TCL interpreter.
     Jim_InitEmbedded();
     httpstate.jim_interp = Jim_CreateInterp();
@@ -243,6 +362,11 @@
                       cyg_httpd_Jim_Command_endchunked,
                       NULL, 
                       NULL);
+    Jim_CreateCommand(httpstate.jim_interp,
+                      "formfetch",
+                      cyg_httpd_Jim_Command_formfetch,
+                      NULL, 
+                      NULL);
 }                      
 #endif    
 
Index: net/athttpd/current/src/forms.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/forms.c,v
retrieving revision 1.4
diff -u -r1.4 forms.c
--- net/athttpd/current/src/forms.c	14 Nov 2007 14:39:13 -0000	1.4
+++ net/athttpd/current/src/forms.c	15 Nov 2007 19:20:57 -0000
@@ -83,44 +83,75 @@
             : c - 'a' + 10;     
 }
 
+/* Scan through the entire string, but only store as much as the buffer can hold.
+ * That way a string that is too long does stop subsequent variables from 
+ * being read
+ * 
+ * buflen - length of buffer, including space for \0. must be >= 1
+ * actual - actual length of string excluding \0
+ */
 char*
-cyg_httpd_store_form_variable(char *query, cyg_httpd_fvars_table_entry *entry)
+cyg_httpd_store_form_variable(char *query, char *q, int buflen, int * actual)
 {
     char *p = query;
-    char *q = entry->buf;
     int   len = 0;
-    
-    while (len < (entry->buflen - 1))
+    char c=0;
+    int gotChar;
+
+    for (;;)
+    {
+    	int done = (len >= (buflen - 1));
         switch(*p)
         {
         case '%':
             p++;
+            gotChar=0;
             if (*p) 
-                *q = cyg_httpd_from_hex(*p++) * 16;
+            {
+                c = cyg_httpd_from_hex(*p++) * 16;
+                gotChar=1;
+            }
             if (*p) 
-                *q = (*q + cyg_httpd_from_hex(*p++));
-            q++;
+            {
+                c = (c + cyg_httpd_from_hex(*p++));
+                gotChar=1;
+            }
+            if (!done&&gotChar)
+            {
+            	*q++=c;
+            }
             len++;
             break;
         case '+':
-            *q++ = ' ';
+            if (!done)
+            {
+            	*q++=' ';
+            }
             p++;
             len++;
             break;
+        case 0: // Hmmm... I'm  not quite sure how, in previous versions, the \0 sentinel was caught...
         case '&':
         case ' ':
-            *q++ = '\0';
-            return p;
-        default:    
-            *q++ = *p++;
+            goto doneLoop;
+        default:
+        	c=*p++;
+        	if (!done)
+        	{
+        		*q++ = c;
+        	}
             len++;
+            break;
         }
-        *q = '\0';
-        while ((*p != ' ') && (*p != '&'))
-            p++;
-        return p;
+    }
+doneLoop:
+	*q = '\0';
+	*actual=len;
+    return p;
 } 
 
+
+
 // We'll try to parse the data from the form, and store it in the variables
 //  that have been defined by the user in the 'form_variable_table'.
 char*
@@ -164,7 +195,8 @@
         }
             
         // Found the variable, store the name.
-        p = cyg_httpd_store_form_variable(++p2, entry);
+        int actual;
+        p = cyg_httpd_store_form_variable(++p2, entry->buf, entry->buflen, &actual);
 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
         diag_printf("Stored form variable: %s Value: %s\n",
                     entry->name,
@@ -176,6 +208,313 @@
     return p;
 }
 
+/* If the string contains *all* of prefix, return true. 
+ * \n in prefix can mean \n or \r\n in 'p'.
+ */
+static char *contains(char *p, char *prefix, int len)
+{
+	int i;
+	for (i=0; i<strlen(prefix); i++)
+	{
+		if (len<=0)
+		{
+//			diag_printf("mismatch\n");
+			return NULL;
+		}
+//		diag_printf("p=%02xprefix=%02x\n", p[i], prefix[i]); 
+//		diag_printf("p=%cprefix=%c\n", p[i], prefix[i]); 
+		if (*p!=prefix[i])
+		{
+			if ((len>=2)&&(prefix[i]=='\n')&&(*p=='\r')&&(p[1]=='\n'))
+			{
+				p+=2;
+				len-=2;
+				continue;
+			}
+//			diag_printf("mismatch\n");
+			return NULL;
+		}
+		p++;
+	}
+//	diag_printf("match\n");
+	return p;
+}
+
+/* if we're looking at this text, skip it, otherwise return NULL. 
+ * If p==NULL, return NULL. 
+ * If the function returns NULL, then *len is untouched
+ */
+static char *skip(char *p, int *len, char *expect)
+{
+//	diag_printf("skip p=%08x %s %d\n", p, expect, *len);
+	if (p==NULL)
+		return NULL;
+//	int i;
+//	for (i=0; i<strlen(expect); i++)
+//	{
+//		diag_printf("%c", p[i]);
+//	}
+//	diag_printf("strncmp starting\n");
+	char *after;
+	after=contains(p, expect, *len);
+	if (after!=NULL)
+    {
+    	// skip boundary
+    	int l=after-p;
+    	p+=l;
+    	*len-=l;
+    	return p;
+    }
+    return NULL;
+}
+
+// Same as skip() except that we skip forwards to the expected string
+static char *skipTo(char *p, int *len, char *expect)
+{
+//	diag_printf("skipTo p=%08x %s\n", p, expect);
+	if (p==NULL)
+		return NULL;
+	
+	if (strcmp(expect, "\n")==0)
+	{
+		int i;
+		// Special case to improve performance. This is the code
+		// that will skip large amounts of data
+		for (i=0; i<*len; i++)
+		{
+			if (p[i]=='\n')
+			{
+				break;
+			}
+		}
+		if (i!=*len)
+		{
+			// Found \n. Do we need to back up one?
+			if ((i>0)&&(p[i-1]=='\r'))
+			{
+				i--;
+			}
+			// found string.
+			*len-=i;
+			return p+i;
+		}
+	} else
+	{
+		int i;
+		int strLen=strlen(expect);
+		for (i=0; i<*len; i++)
+		{
+			int j;
+			char *cmp=p;
+			for (j=0; j<strLen; j++)
+			{
+				if (cmp[i+j]!=expect[j])
+				{
+					if (((*len-i)>=2)&&(expect[j]=='\n')&&(cmp[i+j]=='\r')&&(cmp[i+j+1]=='\n'))
+					{
+						// interpret \r\n as line end
+						cmp++;
+						continue;
+					}
+					break;
+				}
+			}
+			if (j==strLen)
+			{
+				// found string.
+				*len-=i;
+				return p+i;
+			}
+		}
+	}
+	// did not find string
+    return NULL;
+}
+
+// Returns pointer to the beginning of a boundary, 
+// i.e. the byte *after* the last char in 
+// the value
+static char *skipUntilBoundary(char *p, int *origLen)
+{
+//	diag_printf("skipUntilBoundary\n");
+	if (p==NULL)
+		return NULL;
+	int len=*origLen;
+	for (;;)
+	{
+		p=skipTo(p, &len, "\n");
+		// We're now at the beginning of the boundary
+		char *t=p;
+		int l=len;
+		p=skip(p, &len, "\n");
+		if (p==NULL)
+			return NULL;
+		char *p2;
+		p2=skip(p, &len, "--");
+		if (p2!=NULL)
+		{
+			if (contains(p2, httpstate.boundary, len))
+			{
+				// We back up a bit
+				*origLen=l;
+				return t;
+			}
+			// Not the boundary, continue
+		}
+	}
+	return NULL;
+}
+
+// Example(From Firefox):
+//
+//-----------------------------107852697226440
+//Content-Disposition: form-data; name="form_filename"
+//
+//test
+//-----------------------------107852697226440
+//Content-Disposition: form-data; name="form_filecontent"; filename="abc.txt"
+//Content-Type: text/plain
+//
+//file line 1
+//file line 2
+//file line 3
+//-----------------------------107852697226440
+//Content-Disposition: form-data; name="form_action"
+//
+//Upload
+//-----------------------------107852697226440--
+
+// Skip to variable and fish out contents
+static void
+cyg_httpd_fetch_multipart_form_data(char *name, char *buffer, int bufferlen, int *actual)
+{
+	char *p=httpstate.post_data;
+    int len=httpstate.content_len;
+    
+    if (httpstate.boundary==NULL)
+    {
+    	return;
+    }
+
+//	diag_printf("2YYYY %d\n", len);
+//	int i;
+//	for (i=0; i<strlen(p); i++)
+//	{
+//		diag_printf("%c", p[i]);
+//	}
+//	diag_printf("2YYYY\n");
+    
+//    diag_printf("2XXXXXX\nFinding %s\n", name);
+    
+    for (;;)
+    {
+    	p=skipTo(p, &len, "--");
+    	p=skip(p, &len, "--");
+    	p=skip(p, &len, httpstate.boundary);
+    	p=skip(p, &len, "\n");
+    	p=skip(p, &len, "Content-Disposition: form-data; name=\"");
+    	char *start=p;
+    	p=skipTo(p, &len, "\"");
+    	if (p==NULL)
+    		return;
+    	char *end=p;
+    	p=skip(p, &len, "\"");
+    	if (contains(start, name, end-start))
+    	{
+    		// Found variable! 
+    		// Is this a file or just data? 
+    		// We're ignoring the filename
+    		char *p2;
+    		p2=skip(p, &len, "; filename=\"");
+    		if (p2!=NULL)
+    		{
+    			p=p2;
+    	    	p=skipTo(p, &len, "Content-Type: ");
+    		} 
+    		p=skipTo(p, &len, "\n");
+    		p=skip(p, &len, "\n");
+    		p=skip(p, &len, "\n"); // extra blank line before data
+    		start=p;
+    		for (;;)
+    		{
+    			p=skipUntilBoundary(p, &len);
+    	    	if (p==NULL)
+    	    		return;
+	    		// Found end!
+	    		*actual=p-start;
+	    		int t;
+	    		t=bufferlen-1; // always leave space for a 0.
+	    		if (t>*actual)
+	    			t=*actual;
+	    		memcpy(buffer, start, t);
+	    		buffer[t]=0; // always poke a 0 afterwards. Note that the actual data can also contain 0's.
+//	    		diag_printf("tttt\n%s\n\nFound name=%s\nvalue=\"%s\"\n", p, name, buffer); 
+	    		return;
+    		}
+    	} else
+    	{
+    		// Skip this variable
+   			p=skipUntilBoundary(p, &len);
+    		if (p==NULL)
+    			return;
+    	}
+    }
+}
+
+// Find form variable, copy it to the buffer and return the actual length of the variable
+// 
+// If a variable is not found(or there are no post data) an empty string
+// is returned.
+void
+cyg_httpd_fetch_form_data(char *name, char *buffer, int len, int *actual)
+{
+    char      *p2;
+    
+    char *p=httpstate.post_data;
+    
+    
+    buffer[0]=0;
+    *actual=0;
+    
+    if (!p)    /* No form data? just return after clearing variables */
+        return;
+
+    if (httpstate.mode & CYG_HTTPD_MODE_MULTIPART_FORM_DATA)
+    {
+    	cyg_httpd_fetch_multipart_form_data(name, buffer, len, actual);
+    	return;
+    }
+    
+
+    while (*p && *p != ' ')
+    {
+        if (!(p2 = strchr(p, '=')))
+            return;        /* Malformed post? */
+        int var_length = (cyg_int32)p2 - (cyg_int32)p;
+
+        if (strncmp((const char*)p, name, var_length))
+        {
+            // No such variable. Run through the data.
+            while ((*p != '&') && (*p && *p != ' '))
+                p++;
+            if(*p == '&')
+                p++;
+            continue;
+        }
+            
+        // Found the variable, store the name.
+        p = cyg_httpd_store_form_variable(++p2, buffer, len, actual);
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+        diag_printf("Stored form variable: %s Value: %s\n",
+                    name,
+                    buffer);
+#endif
+        
+        return;
+    }
+}
+
+
 char*
 cyg_httpd_find_form_variable(char *p)
 {
Index: net/athttpd/current/src/http.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/http.c,v
retrieving revision 1.4
diff -u -r1.4 http.c
--- net/athttpd/current/src/http.c	14 Nov 2007 14:39:13 -0000	1.4
+++ net/athttpd/current/src/http.c	15 Nov 2007 19:20:58 -0000
@@ -851,7 +851,7 @@
 {
     // The deafult for HTTP 1.1 is keep-alive connections, unless specifically
     //  closed by the far end.
-    httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA);
+    httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA | CYG_HTTPD_MODE_MULTIPART_FORM_DATA);
     httpstate.modified_since = -1;
     httpstate.content_len = 0;
     while ((*p != '\r') && (*p != '\n') & (*p != '\0'))
@@ -892,14 +892,51 @@
         }
         else if (strncasecmp(p, "Content-Type: ", 14) == 0)
         {
-            p = strchr(p, ':') + 2;
-            if (p)
-                // In the case of a POST request, this is the total length of
-                //  the payload, which might be spread across several frames.
-                if (strncasecmp(p,
-                                "application/x-www-form-urlencoded",
-                                33) == 0)
-                    httpstate.mode |= CYG_HTTPD_MODE_FORM_DATA;
+            p = p + strlen("Content-Type: ");
+            // In the case of a POST request, this is the total length of
+            //  the payload, which might be spread across several frames.
+            if (strncasecmp(p,
+                            "application/x-www-form-urlencoded",
+                            strlen("application/x-www-form-urlencoded")) == 0)
+                httpstate.mode |= CYG_HTTPD_MODE_FORM_DATA;
+            if (strncasecmp(p,
+                            "multipart/form-data",
+                            strlen("multipart/form-data")) == 0)
+            {
+                httpstate.mode |= CYG_HTTPD_MODE_MULTIPART_FORM_DATA;
+                p+=strlen("multipart/form-data");
+            }
+
+        	// Fish out boundary
+            // Content-type: multipart/form-data, boundary=AaB03x
+        	if (httpstate.boundary!=NULL)
+        		free(httpstate.boundary);
+        	httpstate.boundary=NULL; // no boundary by default
+        	
+        	while ((*p == ' ')||(*p == ';'))
+        	{
+        		p++;
+        	}
+        	if (strncmp(p, "boundary", strlen("boundary"))==0)
+        	{
+        		p+=strlen("boundary");
+        		if (*p=='=')
+        		{
+        			p++;
+        			
+        			char *start=p;
+        			while ((*p!='\n')&&(*p!='\r')&&(*p!=';')&&(*p!=' '))
+        			{
+        				p++;
+        			}
+        			httpstate.boundary=malloc(p-start+1);
+        			if (httpstate.boundary!=NULL)
+        			{
+        				memcpy(httpstate.boundary, start, p-start);
+        				httpstate.boundary[p-start]=0;
+        			}
+        		}
+        	}
             while (*p++ != '\n');
         }
         else if (strncasecmp("Host:", p, 5) == 0)
@@ -941,28 +978,28 @@
             }
             else if (strncasecmp(p, "Digest", 6) == 0)
             {
-                p += 6;
-                while (*p == ' ')
-                   p++;
+                p += 6;
+                while (*p == ' ')
+                   p++;
                 while ((*p != '\r') && (*p != '\n'))
-                {
-                    if (strncasecmp(p, "realm=", 6) == 0)
+                {
+                    if (strncasecmp(p, "realm=", 6) == 0)
                         p = cyg_httpd_digest_skip(p + 6);
-                    else if (strncasecmp(p, "username=", 9) == 0)
+                    else if (strncasecmp(p, "username=", 9) == 0)
                         p = cyg_httpd_digest_skip(p + 9);
                     else if (strncasecmp(p, "nonce=", 6) == 0)
                         p = cyg_httpd_digest_skip(p + 6);
-                    else if (strncasecmp(p, "response=", 9) == 0)
+                    else if (strncasecmp(p, "response=", 9) == 0)
                         p = cyg_httpd_digest_data(cyg_httpd_md5_response, 
                                                   p + 9);
-                    else if (strncasecmp(p, "cnonce=", 7) == 0)
+                    else if (strncasecmp(p, "cnonce=", 7) == 0)
                         p = cyg_httpd_digest_data(cyg_httpd_md5_cnonce, p + 7);
-                    else if (strncasecmp(p, "qop=", 4) == 0)
+                    else if (strncasecmp(p, "qop=", 4) == 0)
                         p = cyg_httpd_digest_skip(p + 4);
-                    else if (strncasecmp(p, "nc=", 3) == 0)
+                    else if (strncasecmp(p, "nc=", 3) == 0)
                         p = cyg_httpd_digest_data(cyg_httpd_md5_noncecount, 
                                                   p + 3);
-                    else if (strncasecmp(p, "algorithm=", 10) == 0)
+                    else if (strncasecmp(p, "algorithm=", 10) == 0)
                         p = cyg_httpd_digest_skip(p + 10);
                     else if (strncasecmp(p, "opaque=", 7) == 0)
                         p = cyg_httpd_digest_skip(p + 7);
Index: net/athttpd/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/ChangeLog,v
retrieving revision 1.9
diff -u -r1.9 ChangeLog
--- net/athttpd/current/ChangeLog	14 Nov 2007 14:39:13 -0000	1.9
+++ net/athttpd/current/ChangeLog	15 Nov 2007 19:20:56 -0000
@@ -1,3 +1,10 @@
+2007-11-15  Oyvind Harboe  <oyvind.harboe@zylin.com>
+
+	* src/cgi.c: print error message to HTML response if tcl script fails.
+	Less torturous to debug tcl scripts.
+	* include/forms.h,include/http.h,src/cgi.c,src/forms.c,src/http.c:
+	file upload support.
+		
 2007-11-12  Oyvind Harboe  <oyvind.harboe@zylin.com>
 2007-11-12  Jonathan Larmour  <jifl@eCosCentric.com>
 

[-- Attachment #3: Type: text/plain, Size: 148 bytes --]

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-11-15 19:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-11-15  7:41 [ECOS] athttpd file upload wip Øyvind Harboe
2007-11-16  7:07 ` [ECOS] " Øyvind Harboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).