This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

athttp


Hi Folks

It has taken a long time in coming, but at last the athttp has been
patched to bring it a little bit more up to date. Anthony and Danny
has shown that Danny does not in fact need an assignment. Apart from
the patch which is already in anoncvs, no other code from Danny has
been used. 

The patch also contains the jim tcl fix from yesterday.

Attached is the patch which i will commit.

         Andrew
? net/athttpd/current/src/http.c.diff
Index: net/athttpd/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/ChangeLog,v
retrieving revision 1.10
diff -u -r1.10 ChangeLog
--- net/athttpd/current/ChangeLog	9 Mar 2008 15:19:38 -0000	1.10
+++ net/athttpd/current/ChangeLog	18 Jun 2008 18:11:41 -0000
@@ -1,3 +1,83 @@
+2008-06-18  Oyvind Harboe  <oyvind.harboe@zylin.com>
+
+	* src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
+	buffer overrun.
+
+2008-06-17 Anthony Tonizzo <atonizzo@gmail.com>
+
+	Jumbo patch containing many individual patches from a number of
+	different contributors on different days. The ChangeLog entries
+	for all these individual patches are:
+	
+        2007-12-02  Anthony Tonizzo <atonizzo@gmail.com>
+
+	* src/socket.c src/httpd.c: Corrected a bug in
+	cyg_httpd_write_chunked(): Now the CRLF that terminates a chunk is
+	added by the function and not expected to be there already in the
+	data supplied by the user. Modified the function
+	cyg_httpd_end_chunked() so that the flag
+	CYG_HTTPD_MODE_TRANSFER_CHUNKED is always cleared after it
+	terminates. The cyg_httpd_process_request() now loops as many
+	times as the number of full requests received.  Renamed header_end
+	to request_end to better reflect its real use, and the fact that
+	the former name was misleading for POST requests (Danny
+	Sade). Changed the function that collects a request: Now the
+	remaining part of an incomplete request is copied back to the
+	beginning of the buffer. This avoids that multiple split headers
+	might creep towards the end of the buffer.
+
+        2007-11-28  Rene' Nielsen <rbn@vitesse.com> and 
+	            Anthony Tonizzo <atonizzo@gmail.com>
+
+	* doc/athttpd.sgml: Included Digest (MD5) authentication as fully
+	supported.
+	* cdl/httpd.cdl: Updated the cdl to reflect the fact that MD5
+	authentication is now a fully tested feature, at least on some
+	clients (Thanks to Tad for testing this!)
+	* src/httpd.c: Added the initialization of the global variable
+	cyg_httpd_md5_response. This corrects a security hole that could
+	allow unauthenticated browsers to access pages that require
+	authentication. This required a minor change (switch of variables
+	used) in the authentication code. Added code to avoid a buffer
+	overflow during the parsing of headers for authenticated
+	pages. Clear the CYG_HTTPD_MODE_SEND_HEADER_ONLY at the beginning
+	of any request.
+	* src/auth.c: Removed dead code and made static a bunch of
+	functions and variables.
+	* src/auth.h: The AUTH_STORAGE_BUFFER_LENGTH value is now split
+	into two numbers, one that gives the maximum length of the login
+	phrase and one for the password.
+	* src/socket.c: Added a NULL terminator after each header packet
+	that is received. Now the strstr() is guaranteed to find
+	terminated string.
+
+        2007-11-27  Tad Artis <ecos@ds3switch.com>
+
+	* src/auth.c: Modified the cyg_httpd_digest_data() and
+	cyg_httpd_digest_skip() functions to support IE7. A careful read
+	of the augmented BNF in RFC2616 indicates that spaces within the
+	elements of the authentication header are optional. The original
+	atHTTPD code incorrectly relied on a space after the comma. Moved
+	the authentication check inside cyg_httpd_process_method() so that
+	each request, regardless of the type, will have to go through
+	authentication.
+
+        2007-11-26  Tad Artis <ecos@ds3switch.com> and 
+	            Anthony Tonizzo <atonizzo@gmail.com>
+
+	* src/forms.c: Checked for a null terminator inside
+	cyg_httpd_store_form_variable, so that we do not scan past the end
+	of the packet. Check the form variables for both length and
+	content, to avoid false positives. Modified cyg_httpd_from_hex()
+	to return -1 in case of error.
+	* src/httpd.c: Corrected the strings sent back by the server to
+	challenge the client to an MD5 authentication. Adds a couple of
+	commas to separate the items in the string.
+	* src/http.h:
+	* src/socket.h: Corrected a number of indexes where
+	CYGNUM_FILEIO_NFILE was used instead of the correct
+	CYGPKG_NET_MAXSOCKETS.
+
 2008-03-04  Danny Sade  <danny@channelot.com>
 
 	* src/socket.c: put NULL at the end of inbuff on each iteration,
Index: net/athttpd/current/cdl/httpd.cdl
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/cdl/httpd.cdl,v
retrieving revision 1.4
diff -u -r1.4 httpd.cdl
--- net/athttpd/current/cdl/httpd.cdl	4 Dec 2006 20:35:30 -0000	1.4
+++ net/athttpd/current/cdl/httpd.cdl	18 Jun 2008 18:11:42 -0000
@@ -79,24 +79,26 @@
           flavor data
           default_value { CYGNUM_KERNEL_SCHED_PRIORITIES/2 }
           legal_values 0 to CYGNUM_KERNEL_SCHED_PRIORITIES
-          description "The HTTP server threads can be run at any priority.
-                       The exact priority depends on the importance of the
-                       server relative to the rest of the system. The default
-                       is to put it in the middle of the priority range to provide
-                       reasonable response without impacting genuine high
-                       priority threads."
+          description "The HTTP server threads can be run at any
+                       priority.  The exact priority depends on the
+                       importance of the server relative to the rest
+                       of the system. The default is to put it in the
+                       middle of the priority range to provide
+                       reasonable response without impacting genuine
+                       high priority threads."  
       }
 
       cdl_option CYGNUM_NET_ATHTTPD_THREADOPT_STACKSIZE {
           display "Thread stack size"
           flavor data
           default_value 4096
-          description "This is the amount of extra stack to be allocated for 
-                       the HTTPD thread. This value is added to
-                       CYGNUM_HAL_STACK_SIZE_MINIMUM to determine the final
-                       size of the stack for the server."
-      }
-    }  
+          description "This is the amount of extra stack to be
+                       allocated for the HTTPD thread. This value is
+                       added to CYGNUM_HAL_STACK_SIZE_MINIMUM to
+                       determine the final size of the stack for the
+                       server."  
+      } 
+    }
 
     cdl_component CYGOPT_NET_ATHTTPD_SERVEROPT {
         display "Server settings"
@@ -117,7 +119,8 @@
           display "Server ID string"
           flavor data
           default_value {"\"eCos Embedded Web Server\""}
-          description "This is the string sent out in the 'Server:' header line."
+          description "This is the string sent out in the 'Server:' 
+                       header line."
       }
       
       cdl_option CYGNUM_ATHTTPD_SERVER_BUFFER_SIZE {
@@ -125,8 +128,8 @@
           flavor data
           default_value 2048
           description "This option defines the size of the buffers used to 
-                       receive and transmit transmit data to and from the TCP/IP
-                       stack."
+                       receive and transmit transmit data to and from the 
+                       TCP/IP stack."
       }
 
       cdl_option CYGNUM_ATHTTPD_SERVER_MAX_POST {
@@ -141,51 +144,60 @@
           display "HTTPD root directory"
           flavor data
           default_value {"\"/\""}
-          description "This is the absolute path in the eCos file system to the 
-                       HTML documents, including cgi-bin files and error
-                       files and it is generally where the web server will
-                       look for the index file. Include a trailing slash."
+          description "This is the absolute path in the eCos file
+                       system to the HTML documents, including cgi-bin
+                       files and error files and it is generally where
+                       the web server will look for the index
+                       file. Include a trailing slash."
       }
       
       cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR {
           display "cgi-bin directory"
-          active_if    { 0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER || 0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL }
+          active_if    { 0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER || 
+                         0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL }
           flavor data
           default_value {"\"cgi-bin/\""}
-          description "This is the path, relative to CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR,
-                       where the cgi-bin files are stored. Based on the extension
-                       of the cgi-bin file requested, the appropriate interpreter
-                       will be used. Include a trailing slash."
+          description "This is the path, relative to
+                       CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR, where the
+                       cgi-bin files are stored. Based on the
+                       extension of the cgi-bin file requested, the
+                       appropriate interpreter will be used. Include a
+                       trailing slash."
       }
       
       cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR {
           display "Error files directory"
           flavor data
           default_value {"\"errors/\""}
-          description "This is the path, relative to the CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR,
-                       that contains the user-defined files that are sent out
-                       by the server in case of error. The files are named
-                       error_XXX.html where XXX is the 3 digit HTML code. 
-                       For example, for a 404 error the server file will be
-                       named error_404.html. Upon a 404 error, the server will
-                       check the existence of such a file in this directory and
-                       if found, it will send it out. Missing that file, a
-                       standard simple message will be sent instead. Include 
-                       a trailing slash."
+          description "This is the path, relative to the
+                       CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR, that
+                       contains the user-defined files that are sent
+                       out by the server in case of error. The files
+                       are named error_XXX.html where XXX is the 3
+                       digit HTML code.  For example, for a 404 error
+                       the server file will be named
+                       error_404.html. Upon a 404 error, the server
+                       will check the existence of such a file in this
+                       directory and if found, it will send it
+                       out. Missing that file, a standard simple
+                       message will be sent instead. Include a
+                       trailing slash."
       }
 
       cdl_option CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE {
           display "Default MIME type"
           flavor data
           default_value {"\"text/plain\""}
-          description "When accessing internal resources or a file system,
-                       the MIME type is determined by first finding the extension
-                       of the file itself and then by looking up the extension
-                       in the MIME table. In case no extension is found the user 
-                       can define the default MIME type to use. Notice that
-                       this is the full MIME type and not the extension.
-                       A list of standard MIME types sorted by extension can
-                       be found in the current/doc directory"
+          description "When accessing internal resources or a file
+                       system, the MIME type is determined by first
+                       finding the extension of the file itself and
+                       then by looking up the extension in the MIME
+                       table. In case no extension is found the user
+                       can define the default MIME type to use. Notice
+                       that this is the full MIME type and not the
+                       extension.  A list of standard MIME types
+                       sorted by extension can be found in the
+                       current/doc directory" 
       }
       
       cdl_option CYGDAT_NET_ATHTTPD_ALTERNATE_HOME {
@@ -213,13 +225,12 @@
     }
 
     cdl_option CYGOPT_NET_ATHTTPD_USE_AUTH {
-        display       "Support for basic authentication"
+        display       "Support for basic and digest authentication"
         flavor        bool
         default_value 0
         description   "
             This option enables the use basic authentication in web pages.
-            Digest authentication code is also included, but has not been
-            extensively tested." 
+            Not all clients have been tested." 
        compile md5c.c
        compile auth.c
     }
@@ -229,10 +240,10 @@
         flavor        bool
         default_value 1
         description   "
-            This option causes connections used for chunked transfer to be
-             closed after use. Persisting the connection will use less
-             network resources and will improve latency, but may do so at
-             the risk of compatibility with older browsers."
+            This option causes connections used for chunked transfer
+            to be closed after use. Persisting the connection will use
+            less network resources and will improve latency, but may
+            do so at the risk of compatibility with older browsers."
     }
 
     cdl_option CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME {
Index: net/athttpd/current/doc/athttpd.sgml
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/doc/athttpd.sgml,v
retrieving revision 1.6
diff -u -r1.6 athttpd.sgml
--- net/athttpd/current/doc/athttpd.sgml	14 Nov 2007 14:39:13 -0000	1.6
+++ net/athttpd/current/doc/athttpd.sgml	18 Jun 2008 18:11:42 -0000
@@ -50,7 +50,7 @@
   <listitem><para>MIME type support</para></listitem>
   <listitem><para>CGI mechanism through the OBJLOADER package or through a
                   simple tcl interpreter</para></listitem>
-  <listitem><para>Basic Authentication</para></listitem>
+  <listitem><para>Basic and Digest (MD5) Authentication</para></listitem>
   <listitem><para>Directory Listing</para></listitem>
   <listitem><para>Extendable Internal Resources</para></listitem>
 </itemizedlist>
@@ -337,7 +337,10 @@
 
 <programlisting width=72>GET /myForm.cgi?foo=1</programlisting>
 
-<para>then tcl will be able to access the variable foo as $foo.</para>
+<para>then tcl will be able to access the variable foo as $foo. The data
+in the body of a POST request is also accessible through the use of the variable
+$post_data. This is useful if the data is not in "multipart/form-data"
+and tcl has to perform any type of processing on the data itself.</para>
 
 <para>In order to send back a response to the client a few functions have been
 added to the interpreter. These functions are:</para>
Index: net/athttpd/current/include/auth.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/include/auth.h,v
retrieving revision 1.1
diff -u -r1.1 auth.h
--- net/athttpd/current/include/auth.h	18 Jul 2006 16:37:24 -0000	1.1
+++ net/athttpd/current/include/auth.h	18 Jun 2008 18:11:42 -0000
@@ -69,6 +69,10 @@
     CYG_HTTPD_AUTH_DIGEST = 1
 } cyg_httpd_auth_type;
 
+#define AUTH_STORAGE_BUFFER_LENGTH_LOGIN             32
+#define AUTH_STORAGE_BUFFER_LENGTH_PASSWORD          32
+#define AUTH_STORAGE_BUFFER_LENGTH        (AUTH_STORAGE_BUFFER_LENGTH_LOGIN +\
+                                           AUTH_STORAGE_BUFFER_LENGTH_PASSWORD)
 // It must be stressed that the auth_dirname field is the directory name
 //  that will be requested by the web server, and _not_ the absolute name
 //  in the eCos file system. 
@@ -94,11 +98,8 @@
  cyg_httpd_auth_table_entry __name CYG_HAL_TABLE_ENTRY( httpd_auth_table ) =  \
                              { __path, __domain, __un, __pw, __mode } 
 
-cyg_int32 cyg_httpd_base64_encode(char*, char*, cyg_uint32 );
-cyg_int32 cyg_httpd_base64_decode(char*, char*, cyg_uint32 );
 cyg_httpd_auth_table_entry* cyg_httpd_auth_entry_from_path(char *);
 cyg_httpd_auth_table_entry* cyg_httpd_auth_entry_from_domain(char *);
-cyg_httpd_auth_table_entry* cyg_httpd_verify_auth(char*, char*);
 cyg_httpd_auth_table_entry* cyg_httpd_is_authenticated(char*);
 char* cyg_httpd_digest_data(char *, char *);
 char* cyg_httpd_digest_skip(char *);
@@ -123,24 +124,4 @@
 extern char cyg_httpd_md5_ha2[];
 extern char cyg_httpd_md5_ha1[];
 
-
-// Calculate H(A1) as per HTTP Digest spec.
-void cyg_httpd_digest_calc_HA1(char *,
-                               char *,
-                               char *,
-                               char *,
-                               char *,
-                               char *,
-                               HASHHEX);
-
-// Calculate request-digest/response-digest as per HTTP Digest spec.
-void cyg_httpd_digest_calc_response(HASHHEX,           
-                                    char *,
-                                    char *,
-                                    char *,
-                                    char *,
-                                    char *,
-                                    char *,
-                                    HASHHEX,
-                                    HASHHEX);
 #endif // __AUTH_H__
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	18 Jun 2008 18:11:42 -0000
@@ -154,12 +154,17 @@
     cyg_int32    payload_len;
     char         outbuffer[CYG_HTTPD_MAXOUTBUFFER+1];
     
-    socket_entry sockets[CYGNUM_FILEIO_NFILE];
+    socket_entry sockets[CYGPKG_NET_MAXSOCKETS];
     cyg_int32    fdmax;
     
     // Socket handle.
     cyg_int32    client_index;
 
+    // Modified-since is always reset to -1 before parsing the headers of a
+    //  request. If the "Modified-Since" element is present in the header then
+    //  we'll copy the value in this variable, otherwise it will remain to -1.
+    // This will tell us if we can send a CYG_HTTPD_STATUS_NOT_MODIFIED back to
+    //  the client or instead we'll have to send the whole page again.
     time_t       modified_since;
     time_t       last_modified;
     
@@ -168,8 +173,9 @@
 #endif    
 
     // Pointer to the data immediately following the last byte of the header.
-    // In a POST request, this is where the goods are.
-    char        *header_end;
+    // In a POST request, this is where the goods are. After the post request
+    //  is handles it will point to the start of the new request, if any.
+    char        *request_end;
 
     // This pointer points to the buffer where we collected all the post
     //  data (it might come in more than one frame)  and must be visible to
Index: net/athttpd/current/src/auth.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/auth.c,v
retrieving revision 1.2
diff -u -r1.2 auth.c
--- net/athttpd/current/src/auth.c	10 Aug 2006 17:37:48 -0000	1.2
+++ net/athttpd/current/src/auth.c	18 Jun 2008 18:11:43 -0000
@@ -74,10 +74,12 @@
 __externC cyg_httpd_auth_table_entry cyg_httpd_auth_table[];
 __externC cyg_httpd_auth_table_entry cyg_httpd_auth_table_end[];
 
-// Variables used for authorization.
+// Variables used for authorization. The header parsing code will only copy
+//  up to AUTH_STORAGE_BUFFER_LENGTH bytes into cyg_httpd_md5_response to
+//  avoid overflow.
+char cyg_httpd_md5_response[AUTH_STORAGE_BUFFER_LENGTH + 1];
+char cyg_httpd_md5_digest[AUTH_STORAGE_BUFFER_LENGTH + 1];
 char cyg_httpd_md5_nonce[33];
-char cyg_httpd_md5_digest[33];
-char cyg_httpd_md5_response[33];
 char cyg_httpd_md5_cnonce[33];
 char cyg_httpd_md5_noncecount[9];
 char cyg_httpd_md5_ha2[HASHHEXLEN+1] = {'\0'};
@@ -126,61 +128,7 @@
     return (cyg_httpd_auth_table_entry *)0;
 }
 
-cyg_int32
-cyg_httpd_base64_encode(char* to, char* from, cyg_uint32 len )
-{
-    char     *fromp = from;
-    char     *top = to;
-    char      cbyte;
-    char      obyte;
-    cyg_int8  end[3];
-
-    for (; len >= 3; len -= 3)
-    {
-        cbyte = *fromp++;
-        *top++ = b64string[(int)(cbyte >> 2)];
-        obyte = (cbyte << 4) & 0x30;
-
-        cbyte = *fromp++;
-        obyte |= (cbyte >> 4);        
-        *top++ = b64string[(cyg_int32)obyte];
-        obyte = (cbyte << 2) & 0x3C;
-
-        cbyte = *fromp++;
-        obyte |= (cbyte >> 6);        
-        *top++ = b64string[(cyg_int32)obyte];
-        *top++ = b64string[(cyg_int32)(cbyte & 0x3F)];
-    }
-
-    if (len)
-    {
-        end[0] = *fromp++;
-        if (--len )
-            end[1] = *fromp++; 
-        else 
-            end[1] = 0;
-        end[2] = 0;
-
-        cbyte = end[0];
-        *top++ = b64string[(cyg_int32)(cbyte >> 2)];
-        obyte = (cbyte << 4) & 0x30;
-
-        cbyte = end[1];
-        obyte |= (cbyte >> 4);
-        *top++ = b64string[(cyg_int32)obyte];
-        obyte = (cbyte << 2) & 0x3C;
-
-        if (len )
-            *top++ = b64string[(cyg_int32)obyte];
-        else 
-            *top++ = '=';
-        *top++ = '=';
-    }
-    *top = 0;
-    return top - to;
-}
-
-cyg_int32
+static cyg_int32
 cyg_httpd_base64_decode(char* to, char* from, cyg_uint32 len )
 {
     char     *fromp = from;
@@ -252,19 +200,9 @@
     return (top - to) - padding;
 }
 
-cyg_httpd_auth_table_entry*
-cyg_httpd_verify_auth(char* username, char* password)
-{
-    if ((strcmp(httpstate.needs_auth->auth_username, username) == 0) &&
-        (strcmp(httpstate.needs_auth->auth_password, password) == 0))
-        return httpstate.needs_auth;
-    else    
-        return (cyg_httpd_auth_table_entry*)0;
-}
-
 // The following code is a slightly modified version of those available at the
 //  end of RFC1270.
-void cyg_httpd_cvthex(HASH Bin, HASHHEX Hex)
+static void cyg_httpd_cvthex(HASH Bin, HASHHEX Hex)
 {
     unsigned short i;
     unsigned char j;
@@ -286,7 +224,7 @@
 };
 
 // Calculate H(A1) as per spec.
-void
+static void
 cyg_httpd_digest_calc_HA1( char    *pszAlg,
                            char    *pszUserName,
                            char    *pszRealm,
@@ -378,17 +316,17 @@
     {
         if (entry->auth_mode == CYG_HTTPD_AUTH_BASIC)
         {
-            cyg_httpd_base64_decode(cyg_httpd_md5_response,
-                                    cyg_httpd_md5_digest,
-                                    strlen(cyg_httpd_md5_digest));
-            char *extension = rindex(cyg_httpd_md5_response, ':');
-            if (extension == NULL)
+            cyg_httpd_base64_decode(cyg_httpd_md5_digest,
+                                    cyg_httpd_md5_response,
+                                    strlen(cyg_httpd_md5_response));
+            char *colon = rindex(cyg_httpd_md5_digest, ':');
+            if (colon == NULL)
             {
                 return (httpstate.needs_auth = entry);
             }    
             else
             {    
-                *extension = '\0'; // Crypto now has the username.
+                *colon = '\0'; // Crypto now has the username.
                 
                 // In the case of a 'Basic" authentication, the HTTP header
                 //  did not return to us the domain name that we sent when we
@@ -396,10 +334,8 @@
                 //  are the username:password duo. In this case I will just 
                 //  compare the entry's username/password to those read from 
                 //  the header.
-                if ((strcmp(entry->auth_username, 
-                            cyg_httpd_md5_response) != 0) ||
-                    (strcmp(entry->auth_password, 
-                            ++extension) != 0))
+                if ((strcmp(entry->auth_username,cyg_httpd_md5_digest) != 0) ||
+                                 (strcmp(entry->auth_password, ++colon) != 0))
                     return (httpstate.needs_auth = entry);
             }    
         }
@@ -456,13 +392,18 @@
             *dest = '\0';
             exit = 1;
             break;
+        case ',':
+            // If it is a comma there might or might not be a blank space
+            //  following it (IE7 inserts no spaces, everyone else does...)
+            //  so before exiting the loop remove any blank space that follows.
+            if (src[1] == ' ')
+                src++;             
         case ' ':
             src++;
             *dest = '\0';
             exit = 1;
             break;
         case '"':
-        case ',':
             src++;
             break;
         default:
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	18 Jun 2008 18:11:43 -0000
@@ -165,9 +165,6 @@
 cyg_int32
 cyg_httpd_exec_cgi_tcl(char *file_name)
 {
-    char tcl_cmd[CYG_HTTPD_MAXPATH];
-    sprintf(tcl_cmd, "source %s", file_name);
-
     // Make sure that tcl sees the internal variables including the post_data.
     cyg_httpd_fvars_table_entry *entry = cyg_httpd_fvars_table;
     while (entry != cyg_httpd_fvars_table_end)
@@ -184,6 +181,8 @@
                                   "post_data", 
                                   httpstate.post_data);
      
+    char tcl_cmd[CYG_HTTPD_MAXPATH];
+    sprintf(tcl_cmd, "source %s", file_name);
     Jim_Eval(httpstate.jim_interp, tcl_cmd);
     return 0;
 }
@@ -271,7 +270,7 @@
     }    
 
 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
-    if ( strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_OBJLOADER_EXTENSION) == 0)
+    if (strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_OBJLOADER_EXTENSION) == 0)
     {
         // Load a cgibin via OBJLOADER.
         cyg_int32 rc = cyg_httpd_exec_cgi_objloader(file_name);
@@ -279,7 +278,7 @@
     }    
 #endif
 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
-    if ( strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_TCL_EXTENSION) == 0)
+    if (strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_TCL_EXTENSION) == 0)
     {
         // Load a cgibin via the TCL interpreter.
         cyg_int32 rc = cyg_httpd_exec_cgi_tcl(file_name);
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	18 Jun 2008 18:11:43 -0000
@@ -45,6 +45,7 @@
  *  Author(s):    Anthony Tonizzo (atonizzo@gmail.com)
  *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
  *                Lars Povlsen    (lpovlsen@vitesse.com)
+ *                Tad Artis       (ecos@ds3switch.com)
  *  Date:         2006-06-12
  *  Purpose:      
  *  Description:  
@@ -76,11 +77,15 @@
 cyg_int8 blank[] = "";
 
 cyg_int8
-cyg_httpd_from_hex (cyg_int8 c)
+cyg_httpd_from_hex(cyg_int8 c)
 {
-    return  c >= '0' && c <= '9' ?  c - '0'
-            : c >= 'A' && c <= 'F'? c - 'A' + 10
-            : c - 'a' + 10;     
+    if ((c >= '0') && (c <= '9'))
+        return (c - '0');
+    if ((c >= 'A') && (c <= 'F'))
+        return (c - 'A' + 10);
+    if ((c >= 'a') && (c <= 'f'))
+        return (c - 'a' + 10);
+    return -1;    
 }
 
 char*
@@ -109,14 +114,14 @@
             break;
         case '&':
         case ' ':
+        case '\0':        // Don't parse past the end of the packet.
             *q++ = '\0';
             return p;
         default:    
             *q++ = *p++;
             len++;
         }
-        *q = '\0';
-        while ((*p != ' ') && (*p != '&'))
+        while ((*p != ' ') && (*p != '&') && *p)
             p++;
         return p;
 } 
@@ -137,19 +142,25 @@
         entry++;
     }
 
-    if (!p)    /* No form data? just return after clearing variables */
+    if (!p)    // No form data? just return after clearing variables.
         return NULL;
 
     while (*p && *p != ' ')
     {
         if (!(p2 = strchr(p, '=')))
-            return NULL;        /* Malformed post? */
+            return NULL;        // Malformed post?
         var_length = (cyg_int32)p2 - (cyg_int32)p;
         entry = cyg_httpd_fvars_table;
         while (entry != cyg_httpd_fvars_table_end)
         {
-            if (!strncmp((const char*)p, entry->name, var_length ))
-                break;
+            // Compare both lenght and name.
+            // If we do not compare the lenght of the variables as well we
+            //  risk the the case where, for instance, the variable name 'foo'
+            //  hits a match with a variable name 'foobar' because the first
+            //  3 letters of the latter are the same as the former.
+            if ((strlen(entry->name) == var_length) &&
+                (strncmp((const char*)p, entry->name, var_length ) == 0))
+               break;
             entry++;
         }
                 
@@ -191,11 +202,18 @@
     return (char*)0;
 }
 
+static inline void release_post_buffer(void)
+{
+    free(httpstate.post_data);
+    httpstate.post_data = NULL;
+    return;
+}
+    
 void
 cyg_httpd_handle_method_POST(void)
 {
     CYG_ASSERT(httpstate.post_data == NULL, "Leftover content data");
-    CYG_ASSERT(httpstate.header_end != NULL, "Cannot see POST data");
+    CYG_ASSERT(httpstate.request_end != NULL, "Cannot see POST data");
     if (httpstate.content_len == 0 || 
         httpstate.content_len > CYGNUM_ATHTTPD_SERVER_MAX_POST) {
         cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
@@ -211,43 +229,43 @@
         return;
     }
 
-    /* Grab partial/all content from data read with headers */
-    /*
-     * TODO: This does NOT (yet) support multipart/form-data!
-     */
-    int header_len = (int)httpstate.header_end - (int)httpstate.inbuffer;
-    int post_data_len = httpstate.inbuffer_len - header_len;
+    // Grab partial/all content from data read with headers.
+    int header_len = (int)httpstate.request_end - (int)httpstate.inbuffer;
+    unsigned int post_data_available = httpstate.inbuffer_len - header_len;
+    if (httpstate.content_len < post_data_available)
+        post_data_available = httpstate.content_len;
     
     // Some POST data might have come along with the header frame, and the
     //  rest is coming in on following frames. Copy the data that already
-    //  arriced into the post buffer.
-    memcpy(httpstate.post_data, httpstate.header_end, post_data_len);
+    //  arrived into the post buffer.
+    memcpy(httpstate.post_data, httpstate.request_end, post_data_available);
+    httpstate.request_end += post_data_available;
+    unsigned int total_data_read = post_data_available;
+    
     // Do we need additional data?
-    if (post_data_len < httpstate.content_len) 
-    {   
-        while (post_data_len < httpstate.content_len)
+    if (total_data_read < httpstate.content_len)
+    {
+        while (total_data_read < httpstate.content_len)
         {
-            cyg_int32 len = read(httpstate.sockets[httpstate.client_index].
-                                                                   descriptor,
-                                 httpstate.post_data + post_data_len,
-                                 httpstate.content_len - post_data_len);
-            if (len < 0)
+            // Read only the data that belongs to the POST request.
+            post_data_available = read(
+                          httpstate.sockets[httpstate.client_index].descriptor,
+                          httpstate.post_data + total_data_read,
+                          httpstate.content_len - total_data_read);
+            if (post_data_available < 0)
             {
-                /* This releases POST data area*/
-                free(httpstate.post_data);
-                httpstate.post_data = NULL;
+                release_post_buffer();
                 return;
             }    
-            post_data_len += len;
-        }    
-    }
-    CYG_ASSERT(post_data_len == httpstate.content_len, "Partial read");
-
-    /* httpstate.content remains available in handler */
-    httpstate.post_data[httpstate.content_len] = '\0';
+            total_data_read += post_data_available;
+        }
+    }    
     
-    // This assumes that the data that arrived in the POST body is of
-    //  multipart/form-data MIME type. We need to change this, if we are to
+    // httpstate.content remains available in handler.
+    httpstate.post_data[total_data_read] = '\0';
+    
+    // The assumption here is that the data that arrived in the POST body is of
+    //  'multipart/form-data' MIME type. We need to change this if we are to
     //  support things such as HTTP file transfer.
     if (httpstate.mode & CYG_HTTPD_MODE_FORM_DATA)
         cyg_httpd_store_form_data(httpstate.post_data);
@@ -267,8 +285,7 @@
         // Here we'll look for extension to the file. We'll call the cgi
         //  handler only if the extension is '.o'.
         cyg_httpd_exec_cgi();
-        free(httpstate.post_data);
-        httpstate.post_data = NULL;
+        release_post_buffer();
         return;
     }
 #endif    
@@ -278,16 +295,14 @@
     {
         // A handler was found. We'll call the function associated to it.
         h(&httpstate);
-        free(httpstate.post_data);
-        httpstate.post_data = NULL;
+        release_post_buffer();
         return;
     }
 
 
     // No handler of any kind for a post request. Must send 404.
     cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
-    free(httpstate.post_data);
-    httpstate.post_data = NULL;
+    release_post_buffer();
     return;
 }
 
Index: net/athttpd/current/src/handler.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/handler.c,v
retrieving revision 1.2
diff -u -r1.2 handler.c
--- net/athttpd/current/src/handler.c	27 Nov 2006 15:41:56 -0000	1.2
+++ net/athttpd/current/src/handler.c	18 Jun 2008 18:11:43 -0000
@@ -68,7 +68,7 @@
 #include <cyg/athttpd/forms.h>
 
 #ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
-char folder_gif[] = {
+static char folder_gif[] = {
     0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x12, 0x00,
     0x12, 0x00, 0xd5, 0x00, 0x00, 0xfb, 0xfb, 0xfb,
     0xef, 0xef, 0xef, 0xdb, 0xb7, 0x52, 0xcc, 0x99,
@@ -118,7 +118,7 @@
     0x4a, 0x41, 0x00, 0x3b
 };
 
-char doc_gif[] = {
+static char doc_gif[] = {
     0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x12, 0x00,
     0x12, 0x00, 0xe6, 0x00, 0x00, 0xfb, 0xfb, 0xfb,
     0xef, 0xef, 0xef, 0xf8, 0xfb, 0xff, 0xed, 0xf6,
@@ -194,7 +194,7 @@
     0xc4, 0xd1, 0x50, 0x20, 0x00, 0x3b
 };
 
-char back_gif[] = {
+static char back_gif[] = {
     0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0a, 0x00,
     0x09, 0x00, 0xf7, 0x00, 0x00, 0xf8, 0xfa, 0xfb,
     0x3a, 0x6b, 0x9d, 0xe5, 0xeb, 0xf2, 0x87, 0xa5,
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	18 Jun 2008 18:11:44 -0000
@@ -292,9 +292,7 @@
                     &tm_mod.tm_sec);
         if (rc != 6)
         {
-            // asctime() in the stdlibc library.
-            // The date is in the format: Sun Nov 6 08:49:37 1994
-            //  and needs to be converted to GMT.
+            // asctime().
             rc = sscanf(time,"%3s %2d %2d:%2d:%2d %4d",
                         month,
                         &tm_mod.tm_mday,
@@ -411,17 +409,6 @@
     struct stat sp;
     char       file_name[CYG_HTTPD_MAXPATH];
 
-#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
-    // Let's check that the requested URL is not inside some directory that 
-    //  needs authentication.
-    cyg_httpd_auth_table_entry* auth = cyg_httpd_is_authenticated(name);
-    if (auth != 0)
-    {
-        cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_AUTHORIZED);
-        return;
-    }
-#endif
-
     strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
     if (file_name[strlen(file_name)-1] != '/')
         strcat(file_name, "/");
@@ -458,23 +445,14 @@
         //  enough) "Trailing-Slash Redirection". 
         if (name[strlen(name)-1] != '/')
         {
-            if (CYGNUM_NET_ATHTTPD_SERVEROPT_PORT == 80)
-                sprintf(httpstate.url,
-                        "http://%d.%d.%d.%d%s/";,
-                        httpstate.host[0],
-                        httpstate.host[1],
-                        httpstate.host[2],
-                        httpstate.host[3],
-                        tmp_url);
-            else            
-                sprintf(httpstate.url,
-                        "http://%d.%d.%d.%d:%d%s/";,
-                        httpstate.host[0],
-                        httpstate.host[1],
-                        httpstate.host[2],
-                        httpstate.host[3],
-                        CYGNUM_NET_ATHTTPD_SERVEROPT_PORT,
-                        tmp_url);
+            sprintf(httpstate.url,
+                    "http://%d.%d.%d.%d:%d%s/";,
+                    httpstate.host[0],
+                    httpstate.host[1],
+                    httpstate.host[2],
+                    httpstate.host[3],
+                    CYGNUM_NET_ATHTTPD_SERVEROPT_PORT,
+                    tmp_url);
             cyg_httpd_send_error(CYG_HTTPD_STATUS_MOVED_PERMANENTLY);
             return;
         }
@@ -507,9 +485,9 @@
     else    
         httpstate.status_code = CYG_HTTPD_STATUS_OK;
 
-    // Here we'll look for extension to the file. Consider the case where
-    //  there might be more than one dot in the file name. We'll look for
-    //  the last dot, then we'll check the extension.
+    // Here we'll look for an extension to the file. Consider the case where
+    //  there might be more than one dot in the file name. We'll look for just
+    //  the last one, then we'll check the extension.
     char *extension = rindex(file_name, '.');
     if (extension == NULL)
         httpstate.mime_type = 0;
@@ -522,7 +500,7 @@
     if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0)
     {                 
 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
-    diag_printf("Sending header only for URL: %s\n", file_name);
+        diag_printf("Sending header only for URL: %s\n", file_name);
 #endif    
         send(httpstate.sockets[httpstate.client_index].descriptor, 
              httpstate.outbuffer, 
@@ -558,7 +536,7 @@
     }    
     
     err = fclose(fp);
-    if(err < 0)
+    if (err < 0)
         cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
 }
 #endif
@@ -609,14 +587,14 @@
         else             
         {
             sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
-                     "WWW-Authenticate: Digest realm=\"%s\" ",
+                     "WWW-Authenticate: Digest realm=\"%s\", ",
                      httpstate.needs_auth->auth_domainname);
             strftime(cyg_httpd_md5_nonce, 
                      33,
                      TIME_FORMAT_RFC1123,
                      gmtime(&time_val));
             sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
-                    "nonce=\"%s\" ", cyg_httpd_md5_nonce);
+                    "nonce=\"%s\", ", cyg_httpd_md5_nonce);
             sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
                     "opaque=\"%s\", ", 
                     CYG_HTTPD_MD5_AUTH_OPAQUE);
@@ -708,7 +686,8 @@
 void
 cyg_httpd_handle_method_GET(void)
 {
-#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) || defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
+#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) ||\
+                             defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
     // If the URL is a CGI script, there is a different directory...
     if (httpstate.url[0] == '/' &&
                     !strncmp(httpstate.url + 1, 
@@ -722,7 +701,7 @@
     //  will likely generate a 404.
 #endif    
 
-    // Use defined handlers take precedence over other forms of response.
+    // User defined handlers take precedence over other forms of response.
     handler h = cyg_httpd_find_handler();
     if (h != 0)
     {
@@ -784,10 +763,21 @@
         if (*p == '%') 
         {
             p++;
-            if (*p) 
-                *dest = cyg_httpd_from_hex(*p++) * 16;
-            if (*p) 
-                *dest += cyg_httpd_from_hex(*p++);
+            cyg_int8 ch = cyg_httpd_from_hex(*p++);
+            if (ch == -1)
+            {
+                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+                return (char*)0;
+            }
+            *dest = ch << 4;
+            ch = cyg_httpd_from_hex(*p++);
+            if (ch == -1)
+            {
+                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+                return (char*)0;
+            }
+            *dest += ch;
+            dest++;
         }
         else 
             *dest++ = *p++;
@@ -809,7 +799,6 @@
 cyg_httpd_parse_POST(char* p)
 {
     httpstate.method = CYG_HTTPD_METHOD_POST;
-    httpstate.mode &= ~CYG_HTTPD_MODE_SEND_HEADER_ONLY;
     char *cp = cyg_httpd_get_URL(p);
     if (cp == 0)
         return (char*)0;
@@ -849,12 +838,21 @@
 char*
 cyg_httpd_process_header(char *p)
 {
+#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
+    // Clear the previous request's response. The client properly authenticated
+    //  will always reinitialize this variable during the header parsing
+    //  process. This variable is also commandeered to hold the hashed
+    //  username:password duo in the basic authentication.
+    cyg_httpd_md5_response[0] = '\0';
+#endif
+
     // 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_SEND_HEADER_ONLY);
     httpstate.modified_since = -1;
     httpstate.content_len = 0;
-    while ((*p != '\r') && (*p != '\n') & (*p != '\0'))
+    while (p < httpstate.request_end)
     {
         if (strncasecmp("GET ", p, 4) == 0)
         {
@@ -931,44 +929,56 @@
                 p++;
             if (strncasecmp("Basic", p, 5) == 0)
             {
-                char *cr = cyg_httpd_md5_digest;
                 p += 5;
                 while (*p == ' ')
                     p++;
-                while ((*p != '\r') && (*p != '\n') && (*p != ' '))
-                    *cr++ = *p++;
-                *cr = '\0';
+                cyg_int32 auth_data_length = 0;    
+                while (*p != '\n') 
+                {
+                    // We are going to copy only up to 
+                    //  AUTH_STORAGE_BUFFER_LENGTH characters to prevent
+                    //  overflow of the cyg_httpd_md5_response variable.
+                    if (auth_data_length < AUTH_STORAGE_BUFFER_LENGTH)
+                        if ((*p != '\r') && (*p != ' '))
+                            cyg_httpd_md5_response[auth_data_length++] = *p;
+                    p++;
+                }    
+                p++;        
+                cyg_httpd_md5_response[auth_data_length] = '\0';
             }
             else if (strncasecmp(p, "Digest", 6) == 0)
             {
-                p += 6;
-                while (*p == ' ')
-                   p++;
-                while ((*p != '\r') && (*p != '\n'))
-                {
-                    if (strncasecmp(p, "realm=", 6) == 0)
+                p += 6;
+                while (*p == ' ')
+                   p++;
+                while (*p != '\n')
+                {
+                    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);
                     else if (strncasecmp(p, "uri=", 4) == 0)
                         p = cyg_httpd_digest_skip(p + 4);
+                    else
+                        p++;    
                 }
+                p++;
             }    
             else
                 while (*p++ != '\n');
@@ -987,36 +997,6 @@
             // We'll just dump the rest of the line and move on to the next.
             while (*p++ != '\n');
     }
-    
-    if (*p == '\0')
-    {
-        // This is the case of a header that is split in two or more frames.
-        // We cannot process it right away and will have to wait for the rest
-        //  of the data. This has _major_ implications because we implicitly
-        //  and tacitly assume that the next frame that will be handled by the
-        //  server is the continuation of this one. But if the next frame is
-        //  for instance, a request from another client, we are in trouble
-        //  since the new request will be processed and this request will
-        //  be dropped.
-        // Caveat: This is all untested. While theoretically this is possible,
-        //  as much as I tried, I could not coerce any of the popular browser
-        //  to split a header in multiple frames.
-#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
-        diag_printf("Split header found.\r\n");
-#endif        
-        return 0;
-    }    
-
-    // If this is the end of this request, but there might be other queued up
-    //  because of pipelining of two requests in a single frame. This while()
-    //  will get rid of the \r\n that terminates the header section of a
-    //  request.
-    while (*p++ != '\n');
-    
-    // In the case of large POST the payload comes with the header (and
-    //  possibly further frames.) Here is where we mark the start of the
-    //  POST data.
-    httpstate.header_end = p;
     return p;
 }
 
@@ -1030,12 +1010,24 @@
     //  the leading returns and line carriages we find.
     while ((*p == '\r') || (*p =='\n'))
         p++;
+
     while (*p != '\0')
     {
         p = cyg_httpd_process_header(p);
         if (p == 0)
             return;
-        
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
+        // Let's check that the requested URL is not inside some directory that 
+        //  needs authentication.
+        cyg_httpd_auth_table_entry* auth = 
+                                  cyg_httpd_is_authenticated(httpstate.url);
+        if (auth != 0)
+        {
+            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_AUTHORIZED);
+            return;
+        }
+#endif
         switch (httpstate.method)
         {
             case CYG_HTTPD_METHOD_GET:
Index: net/athttpd/current/src/jim-aio.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/jim-aio.c,v
retrieving revision 1.2
diff -u -r1.2 jim-aio.c
--- net/athttpd/current/src/jim-aio.c	12 Nov 2007 13:33:12 -0000	1.2
+++ net/athttpd/current/src/jim-aio.c	18 Jun 2008 18:11:44 -0000
@@ -137,7 +137,7 @@
             buf[AIO_BUF_LEN-1] = '_';
             if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
                 break;
-            if (buf[AIO_BUF_LEN-1] == '\0' && buf[AIO_BUF_LEN] == '\n')
+            if (buf[AIO_BUF_LEN-1] == '\0' && buf[AIO_BUF_LEN-2] == '\n')
                 more = 1;
             if (more) {
                 Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN-1);
Index: net/athttpd/current/src/socket.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/athttpd/current/src/socket.c,v
retrieving revision 1.5
diff -u -r1.5 socket.c
--- net/athttpd/current/src/socket.c	9 Mar 2008 15:19:38 -0000	1.5
+++ net/athttpd/current/src/socket.c	18 Jun 2008 18:11:44 -0000
@@ -71,7 +71,7 @@
 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
 #define CYG_HTTPD_DAEMON_STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM + \
                                           CYGNUM_NET_ATHTTPD_THREADOPT_STACKSIZE)
-static cyg_int32    cyg_httpd_initialized = 0;
+static cyg_int32 cyg_httpd_initialized = 0;
 cyg_thread   cyg_httpd_thread_object;
 cyg_handle_t cyg_httpd_thread_handle;
 cyg_uint8    cyg_httpd_thread_stack[CYG_HTTPD_DAEMON_STACK_SIZE]     
@@ -108,9 +108,11 @@
     return sent;
 }
     
-// The need for chunked transfers arises from the fact that with dinamic
-//  pages it is not always possible to know the packet size upfront, and thus
-//  it is not possible to fill the 'Content-Length:' field in the header.
+// The need for chunked transfers arises from the fact that with persistent
+//  connections it is not always easy to tell when a packet end. Also, with
+//  dynamic pages it is not always possible to know the packet size upfront,
+//  and thus the value of the 'Content-Length:' field in the header is not
+//  known upfront.
 // Today's web browser use 'Content-Length:' when present in the header and 
 //  when not present they read everything that comes in up to the last 2 \r\n
 //  and then figure it out. The HTTP standard _mandates_ 'Content-Length:' to
@@ -121,8 +123,7 @@
 // -----------------------------------------------------------------------------
 //    cyg_httpd_start_chunked("html");
 //    sprintf(phttpstate->payload, ...);             
-//    cyg_httpd_write_chunked(phttpstate->payload, 
-//                             strlen(phttpstate->payload));
+//    cyg_httpd_write_chunked(phttpstate->payload, strlen(phttpstate->payload));
 //    ...                         
 //    cyg_httpd_end_chunked();
 // -----------------------------------------------------------------------------
@@ -132,7 +133,7 @@
     httpstate.status_code = CYG_HTTPD_STATUS_OK;
 
 #if defined(CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS)
-     // I am not really sure that this is necessary, but even if it isn't, the
+    // I am not really sure that this is necessary, but even if it isn't, the
     //  added overhead is not such a big deal. In simple terms, I am not sure 
     //  how much I can rely on the client to understand that the frame has ended 
     //  with the last 5 bytes sent out. In an ideal world, the data '0\r\n\r\n'
@@ -147,7 +148,7 @@
 #endif
     
     // We do not cache chunked frames. In case they are used to display dynamic
-    //  data we want them to be executed any every time they are requested.
+    //  data we want them to be executed every time they are requested.
     httpstate.mode |= 
               (CYG_HTTPD_MODE_TRANSFER_CHUNKED | CYG_HTTPD_MODE_NO_CACHE);
     
@@ -160,30 +161,28 @@
 ssize_t
 cyg_httpd_write_chunked(char* buf, int len)
 {
-    char leader[16], trailer[] = {'\r', '\n'};
+    if (len == 0)
+         return 0;
 
-    cyg_iovec iovec_bufs[] = { {leader, 0}, {buf, 0}, {trailer, 2} };
-    sprintf(leader, "%x\r\n", len);
-    iovec_bufs[0].iov_len = strlen(leader);
-    iovec_bufs[1].iov_len = len;
-    iovec_bufs[2].iov_len = 2;
+    char leader[16], trailer[] = {'\r', '\n'};
+    cyg_iovec iovec_bufs[] = { {leader, 0}, {buf, len}, {trailer, 2} };
+    iovec_bufs[0].iov_len = sprintf(leader, "%x\r\n", len);
     if (httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY)
-        return (iovec_bufs[0].iov_len + iovec_bufs[1].iov_len + 
-                                                  iovec_bufs[2].iov_len);
+        return (iovec_bufs[0].iov_len + len + 2);
     return cyg_httpd_writev(iovec_bufs, 3);
 }
 
 void
 cyg_httpd_end_chunked(void)
 {
-    if (httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY)
+    httpstate.mode &= ~CYG_HTTPD_MODE_TRANSFER_CHUNKED;
+    if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0)
         return;
     strcpy(httpstate.outbuffer, "0\r\n\r\n");
     cyg_httpd_write(httpstate.outbuffer, 5);
-    httpstate.mode &= ~CYG_HTTPD_MODE_TRANSFER_CHUNKED;
 }    
 
-// This function builds and send out a standard header. It is likely going to
+// This function builds and sends out a standard header. It is likely going to
 //  be used by a c language callback function, and thus followed by one or
 //  more calls to cyg_httpd_write(). Unlike cyg_httpd_start_chunked(), this
 //  call requires prior knowledge of the final size of the frame (browsers
@@ -212,7 +211,7 @@
 {
     httpstate.client_index = index;
     cyg_int32 descr = httpstate.sockets[index].descriptor;
-    
+
     // By placing a terminating '\0' not only we have a safe stopper point
     //  for our parsing, but also we can detect if we have a split header.
     // Since headers always end with an extra '\r\n', if we find a '\0'
@@ -220,9 +219,12 @@
     //  not been received completely and more is following (i.e. split headers.)
     httpstate.inbuffer[0] = '\0';
     httpstate.inbuffer_len = 0;
-    while ((strstr(httpstate.inbuffer, "\r\n\r\n") == 0) &&
-                (strstr(httpstate.inbuffer, "\n\n") == 0))
-    {            
+
+    cyg_bool done = false;
+    do
+    {   
+        // At this point we know we have data pending because the corresponding
+        //  bit in the fd_set structure was set.
         int len = recv(descr,
                        httpstate.inbuffer + httpstate.inbuffer_len,
                        CYG_HTTPD_MAXINBUFFER - httpstate.inbuffer_len,
@@ -255,30 +257,65 @@
 #endif    
             return;
         }  
-    
+
+        httpstate.inbuffer[httpstate.inbuffer_len + len] = '\0';
+
+        // It is always possible to receive split headers, in which case a
+        //  header is only partially sent on one packet, with the rest on
+        //  following packets. We can tell when a full packet is in the buffer
+        //  by scanning for a header terminator ('\r\n\r\n'). Be smart and
+        //  scan only the data received in the last read() operation, and not
+        //  the full buffer each time.
+        httpstate.request_end = 
+               strstr(&httpstate.inbuffer[httpstate.inbuffer_len], "\r\n\r\n");
         httpstate.inbuffer_len += len;
-        httpstate.inbuffer[httpstate.inbuffer_len] = '\0';
-    }
-    
-    httpstate.inbuffer[httpstate.inbuffer_len] = '\0';
 
-    // Timestamp the socket. 
-    httpstate.sockets[index].timestamp = time(NULL);
-        
-    // This is where it all happens.
-    cyg_httpd_process_method();
-        
-    if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
-        // There are 2 cases we can be here:
-        // 1) chunked frames close their connection by default
-        // 2) The client requested the connection be terminated with a
-        //     "Connection: close" in the header
-        // In any case, we close the TX pipe and wait for the client to
-        //  send us an EOF on the receive pipe. This is a more graceful way
-        //  to handle the closing of the socket, compared to just calling
-        //  close() without first asking the opinion of the client, and 
-        //  running the risk of stray data lingering around.
-        shutdown(descr, SHUT_WR);
+        // Go through all the requests that were received in this packet.
+        while (httpstate.request_end != 0)
+        {
+            httpstate.request_end += 4; // Include the terminator.
+            
+            // Timestamp the socket. 
+            httpstate.sockets[index].timestamp = time(NULL);
+                
+            // This is where it all happens.
+            cyg_httpd_process_method();
+                
+            if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
+            {
+                // There are 2 cases we can be here:
+                // 1) chunked frames close their connection by default
+                // 2) The client requested the connection be terminated with a
+                //     "Connection: close" in the header
+                // In any case, we close the TX pipe and wait for the client to
+                //  send us an EOF on the receive pipe. This is a more graceful
+                //  way to handle the closing of the socket, compared to just
+                //  calling close() without first asking the opinion of the
+                //  client, and  running the risk of stray data lingering 
+                //  around.
+                shutdown(descr, SHUT_WR);
+            }
+            
+            // Move back the next request (if any) to the beginning of inbuffer.
+            //  This way we avoid inching towards the end of inbuffer with
+            //  consecutive requests.
+            strcpy(httpstate.inbuffer, httpstate.request_end);
+            httpstate.inbuffer_len -= (int)(httpstate.request_end - 
+                                                       httpstate.inbuffer);
+                                                       
+            // If there is no data left over we are done processing all
+            //  requests.
+            if (httpstate.inbuffer_len == 0)
+            {
+                done = true;
+                break;
+            }    
+
+            // Any other fully formed request pending?                                           
+            httpstate.request_end = strstr(httpstate.inbuffer, "\r\n\r\n");
+        }        
+    }
+    while (done == false);
 }
 
 void
@@ -395,7 +432,7 @@
     diag_printf("Web server Started and listening...\n");
 #endif
     cyg_int32 i;
-    for (i = 0; i < CYGNUM_FILEIO_NFILE; i++)
+    for (i = 0; i < CYGPKG_NET_MAXSOCKETS; i++)
     {
         httpstate.sockets[i].descriptor  = 0;
         httpstate.sockets[i].timestamp   = (time_t)0;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]