public inbox for ecos-patches@sourceware.org
 help / color / mirror / Atom feed
* Re: atHTTPD new patch
@ 2007-12-18 15:19 Anthony Tonizzo
  2007-12-18 19:06 ` Andrew Lunn
  0 siblings, 1 reply; 6+ messages in thread
From: Anthony Tonizzo @ 2007-12-18 15:19 UTC (permalink / raw)
  To: ecos-patches

Andrew:

Me moved the development to ecosforge because it would
be much simpler to test new code as it is developed by different
parties. Currently only Oyvind and myself can check new code
in, but you will still receive new patches for the eCos tree from
me.

Just to clarify the issue of copyright assignments. Is there
any lithmus test to determine which contributions need an
assignment and which do not?

Somewhere I read something like "10 original lines of code"
make up the breakwater. Is this the accepted standard or do
you reserve the right to change this on a per-case basis?

> If one or more of the people contributing to the current patch cannot
> get a copyright assignment you then have a problem. Effectively you
> need to throw their part of the patch out and re-implement it with
> code you can get an assignment for.

Understood.

Sorry if I sound like a sticlker for details, but I want to make sure
that even after moving the development to ecosforge, there will be
no problems in the future to submit patches to eCos.

> Secondly, please keep tight control and records for everything you add
> to your ecosforge tree. When you want to contribute a patch we have
> the same copyright issues.
> You need to be able to convince the eCos
> maintainers that all the patch is covered by appropriate copyright
> assignments. The more open and visible your process is the easier you
> will find it to convince us.

The only way to record what is added is through the changelog. And
because we (as opposed to the eCos maintainers) modify the changelog,
it means that it still boils down to a matter fo trusting the contributors to
eCos, right? Or are you suggesting that we save all e-mail and individual
patches that were received from all contributors?

If we need to ask for a copyright assignment, do we ask the submitter
to send it to eCosCentric?

Thanks
Tony

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

* Re: atHTTPD new patch
  2007-12-18 15:19 atHTTPD new patch Anthony Tonizzo
@ 2007-12-18 19:06 ` Andrew Lunn
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Lunn @ 2007-12-18 19:06 UTC (permalink / raw)
  To: Anthony Tonizzo; +Cc: ecos-patches

On Tue, Dec 18, 2007 at 07:19:18AM -0800, Anthony Tonizzo wrote:
> Andrew:
> 
> Me moved the development to ecosforge because it would
> be much simpler to test new code as it is developed by different
> parties. Currently only Oyvind and myself can check new code
> in, but you will still receive new patches for the eCos tree from
> me.
> 
> Just to clarify the issue of copyright assignments. Is there
> any lithmus test to determine which contributions need an
> assignment and which do not?

I don't think there is a simple lithmus test. I look and see how
obvious the change is. A One line change don't need an assignment. A
one line changes repeated 10 times in a file does not need an an
assignment. 10 new lines which implement an algorithm does need an
assignment. 

It can worse for you if you submit one patch containing lots of
changes to the same place. It becomes unclear if its 10 individual one
lines all next to each other, or it is one 10 line change. The first
does not necessarily need an assignment, but the second does. However
how are we to know? So we will take the safe option and ask for an
assignment.
 
> Somewhere I read something like "10 original lines of code"
> make up the breakwater. Is this the accepted standard or do
> you reserve the right to change this on a per-case basis?

Jifl?
 
> Sorry if I sound like a sticlker for details, but I want to make sure
> that even after moving the development to ecosforge, there will be
> no problems in the future to submit patches to eCos.

Me too, which is why i made this warning. Also, this is why when you
announced ecosforge there was a statement from the maintainers which
talked about the assignment process and the quality process still
needing to be fulfilled when you submit a contribution.

> > Secondly, please keep tight control and records for everything you add
> > to your ecosforge tree. When you want to contribute a patch we have
> > the same copyright issues.
> > You need to be able to convince the eCos
> > maintainers that all the patch is covered by appropriate copyright
> > assignments. The more open and visible your process is the easier you
> > will find it to convince us.
 
> The only way to record what is added is through the changelog. And
> because we (as opposed to the eCos maintainers) modify the changelog,
> it means that it still boils down to a matter fo trusting the contributors to
> eCos, right? Or are you suggesting that we save all e-mail and individual
> patches that were received from all contributors?

It is not only the ChangeLog. There is the subversion
logs/history. This allows the eCos maintainers, or anybody else, to
look at the individual patches you commit to your tree. I've not tried
it, but i guess i have read only access to all this information. I
would also suggest you keep your individual patches from all
contributors, preferably in a publicly accessible mailing list. All
patches to eCos go into ecos-patch, even if they come from an
maintainer. It leaves a public record, so that if there ever is any
questions about copyright, it is all clear and out in the open, making
it easy for us to defend ourselves.

IANAL, but i don't think it is just trust. You have an assignment. If
you contribute to eCos something which you are not allowed to
contribute, you are probably violating your assignment. That could get
you into legal copyright trouble.
 
> If we need to ask for a copyright assignment, do we ask the submitter
> to send it to eCosCentric?

Just follow the usual copyright assignment process:

http://ecos.sourceware.org/assign.html

        Andrew

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

* Re: atHTTPD new patch
  2007-12-18  7:15 Øyvind Harboe
@ 2007-12-18  9:06 ` Andrew Lunn
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Lunn @ 2007-12-18  9:06 UTC (permalink / raw)
  To: ?yvind Harboe; +Cc: ecos-patches

On Tue, Dec 18, 2007 at 08:14:45AM +0100, ?yvind Harboe wrote:
> > Hi Anthony
> >
> > Sorry for taking so long.
> >
> > The ChangeLog is in the wrong order.
> >
> > There are lots of new contributors to this code. We probably need
> > copyright assignments from each of them, unless you can show me the
> > individual changes are very small and so don't need an assignment.
> 
> We're going ahead w/other developments as well. Since we are several
> people working on
> the code and we have to merge along the way, we're hosting the code at
> a subversion server. Please give word once the paperwork goes through
> and it makes sense to post a patch for the eCos repository again.

O.K.

Just two words of warning. 

If one or more of the people contributing to the current patch cannot
get a copyright assignment you then have a problem. Effectively you
need to throw their part of the patch out and re-implement it with
code you can get an assignment for.

Secondly, please keep tight control and records for everything you add
to your ecosforge tree. When you want to contribute a patch we have
the same copyright issues. You need to be able to convince the eCos
maintainers that all the patch is covered by appropriate copyright
assignments. The more open and visible your process is the easier you
will find it to convince us.

     Andrew

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

* atHTTPD new patch
@ 2007-12-18  7:15 Øyvind Harboe
  2007-12-18  9:06 ` Andrew Lunn
  0 siblings, 1 reply; 6+ messages in thread
From: Øyvind Harboe @ 2007-12-18  7:15 UTC (permalink / raw)
  To: ecos-patches

> Hi Anthony
>
> Sorry for taking so long.
>
> The ChangeLog is in the wrong order.
>
> There are lots of new contributors to this code. We probably need
> copyright assignments from each of them, unless you can show me the
> individual changes are very small and so don't need an assignment.

We're going ahead w/other developments as well. Since we are several
people working on
the code and we have to merge along the way, we're hosting the code at
a subversion server. Please give word once the paperwork goes through
and it makes sense to post a patch for the eCos repository again.

http://www.ecosforge.net/ecosforge/trunk/athttpd/

Patches & comments welcome!


Some highlights:

- lots of tcl improvements
- tcl jim now seperate module
- file upload support
- lots of bugfixes
- md5
- authorization stuff

http://www.ecosforge.net/ecosforge/trunk/athttpd/net/athttpd/current/ChangeLog



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

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

* Re: atHTTPD new patch
  2007-12-10 16:31 Anthony Tonizzo
@ 2007-12-14 10:51 ` Andrew Lunn
  0 siblings, 0 replies; 6+ messages in thread
From: Andrew Lunn @ 2007-12-14 10:51 UTC (permalink / raw)
  To: Anthony Tonizzo; +Cc: ecos-patches

On Mon, Dec 10, 2007 at 08:31:25AM -0800, Anthony Tonizzo wrote:
> Belated patch to atHTTPD after much coaching from
> Tad, Rene, Danny and Oyvind. Lots of work went into
> improving the collection of requests and making
> authentication work right. The chengelog says it all.

Hi Anthony

Sorry for taking so long.

The ChangeLog is in the wrong order.

There are lots of new contributors to this code. We probably need
copyright assignments from each of them, unless you can show me the
individual changes are very small and so don't need an assignment.

           Andrew

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

* atHTTPD new patch
@ 2007-12-10 16:31 Anthony Tonizzo
  2007-12-14 10:51 ` Andrew Lunn
  0 siblings, 1 reply; 6+ messages in thread
From: Anthony Tonizzo @ 2007-12-10 16:31 UTC (permalink / raw)
  To: ecos-patches

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

Belated patch to atHTTPD after much coaching from
Tad, Rene, Danny and Oyvind. Lots of work went into
improving the collection of requests and making
authentication work right. The chengelog says it all.

Anthony Tonizzo

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: diff.patch --]
[-- Type: text/x-patch; name=diff.patch, Size: 56130 bytes --]

diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/eCos.hhc /home/atonizzo/ecos/devo_athttpd/eCos.hhc
--- /home/atonizzo/ecos/clean/eCos.hhc	1969-12-31 16:00:00.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/eCos.hhc	2007-11-26 10:31:54.000000000 -0800
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<HTML>
+<HEAD>
+<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
+<!-- Sitemap 1.0 -->
+</HEAD><BODY>
+<UL>
+</UL>
+</BODY></HTML>
\ No newline at end of file
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/eCos.hhp /home/atonizzo/ecos/devo_athttpd/eCos.hhp
--- /home/atonizzo/ecos/clean/eCos.hhp	1969-12-31 16:00:00.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/eCos.hhp	2007-11-26 10:31:54.000000000 -0800
@@ -0,0 +1,19 @@
+[OPTIONS]
+Auto Index=Yes
+Binary Index=No
+Compatibility=1.1 or later
+Compiled file=eCos.chm
+Contents file=eCos.hhc
+Default Window=mainwin
+Default topic=/home/atonizzo/ecos/devo_athttpd/doc/index.html
+Display compile progress=Yes
+Full-text search=Yes
+Language=0x409 English (United States)
+Title=eCos
+[WINDOWS]
+mainwin="eCos Documentation","eCos.hhc",,,"index.html","http://sources.redhat.com/ecos/","Net Release","http://www.redhat.com/products/ecos/","eCos Product",0x40060420,,0xc287e,[0,0,762,400],,,,,,,0
+
+[FILES]
+index.html
+
+[INFOTYPES]
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/ChangeLog /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/ChangeLog
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/ChangeLog	2007-11-14 06:39:13.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/ChangeLog	2007-12-10 08:29:18.000000000 -0800
@@ -1,5 +1,63 @@
+2007-12-02  Danny Sade <danny@channelot.com>
+
+	* src/socket.c: Added a extra check for end of header in case of POST
+	requests. In the original code the payload following the POST header could
+	be confused with the start of a new request.
+
+2007-12-02  Danny Sade <danny@channelot.com> and Anthony Tonizzo <atonizzo@gmail.com>
+
+	* src/socket.c src/httpd.c: 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. Corrected a bug in the 
+	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. The cyg_httpd_process_request() now loops as many times
+	as the number of full requests received. Modified the function 
+	cyg_httpd_end_chunked() so that the flag CYG_HTTPD_MODE_TRANSFER_CHUNKED
+	is always cleared after it terminates. Renamed header_end to request_end
+	to better reflect its real use.
+	* doc/athttpd.sgml: Included Digest (MD5) authentication as fully supported.
+
+2007-11-28  Rene' Nielsen <rbn@vitesse.com> and Anthony Tonizzo <atonizzo@gmail.com>
+
+	* cdl/httpd.cdl: Updated the cdl to reflect the fact that MD5 authentication
+	is now a fully tested feature (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.
+    * src/auth.c: Removed dead code and made static a bunch of functions.
+	* 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>
+
+	* 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.
+	* 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.
+
 2007-11-12  Oyvind Harboe  <oyvind.harboe@zylin.com>
 2007-11-12  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* doc/athttpd.sgml: added an example of a tcl script.
 	* src/http.c, forms.c: serve cgi requests before file system requests,
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/doc/athttpd.sgml /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/doc/athttpd.sgml
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/doc/athttpd.sgml	2007-11-14 06:39:13.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/doc/athttpd.sgml	2007-12-04 13:58:25.000000000 -0800
@@ -48,11 +48,11 @@
   <listitem><para>File system Access</para></listitem>
   <listitem><para>Callbacks to C functions</para></listitem>
   <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>
 
 <para>
@@ -335,11 +335,14 @@
 form variable called foo, and during the GET request we are defining foo
 as being "1":</para>
 
 <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>
 
 <sect3 id="athttpd-start-chunked">
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/include/auth.h /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/include/auth.h
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/include/auth.h	2006-07-18 09:37:24.000000000 -0700
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/include/auth.h	2007-11-26 10:11:49.000000000 -0800
@@ -67,10 +67,14 @@
 {
     CYG_HTTPD_AUTH_BASIC = 0, 
     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. 
 // Lets' make an example. Let's say that the files of your web site reside in 
 //  the directory '/fs/jffs2/html'. Your CYG_HTTPD_DEFAULT_PATH will likely be
@@ -92,15 +96,12 @@
 typedef struct cyg_httpd_auth_table_entry cyg_httpd_auth_table_entry;
 #define CYG_HTTPD_AUTH_TABLE_ENTRY( __name, __path, __domain, __un, __pw, __mode )  \
  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 *);
 
 // The following code is a slightly modified version of those available at the
@@ -121,26 +122,6 @@
 extern char cyg_httpd_md5_response[];
 extern char cyg_httpd_md5_noncecount[];
 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__
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/include/http.h /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/include/http.h
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/include/http.h	2006-11-27 07:41:56.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/include/http.h	2007-12-05 10:15:12.000000000 -0800
@@ -152,26 +152,32 @@
     cyg_uint16   status_code;
     char        *mime_type;
     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;
     
 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
     Jim_Interp *jim_interp;
 #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
     //  handlers and cgi scripts.
     char        *post_data;
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/auth.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/auth.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/auth.c	2006-08-10 10:37:48.000000000 -0700
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/auth.c	2007-11-26 10:16:38.000000000 -0800
@@ -72,14 +72,16 @@
 CYG_HAL_TABLE_END(cyg_httpd_auth_table_end, httpd_auth_table );
 
 __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'};
 char cyg_httpd_md5_ha1[HASHHEXLEN+1];
 
@@ -124,65 +126,11 @@
     }
             
     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;
     char     *top = to;
     char     *p;
@@ -250,23 +198,13 @@
     if (len)
         return -1;
     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;
 
     for (i = 0; i < HASHLEN; i++)
@@ -284,11 +222,11 @@
     };
     Hex[HASHHEXLEN] = '\0';
 };
 
 // Calculate H(A1) as per spec.
-void
+static void
 cyg_httpd_digest_calc_HA1( char    *pszAlg,
                            char    *pszUserName,
                            char    *pszRealm,
                            char    *pszPassword,
                            char    *pszNonce,
@@ -376,32 +314,30 @@
                                 cyg_httpd_auth_entry_from_path(fname);
     if (entry != 0)
     {
         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
                 //  challenged the request: The only things that are returned 
                 //  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);
             }    
         }
         else
         {
@@ -454,17 +390,22 @@
         case '\r':
         case '\n':
             *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:
             *dest++ = *src++;
         }    
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/cgi.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/cgi.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/cgi.c	2006-11-27 07:41:56.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/cgi.c	2007-12-04 13:59:32.000000000 -0800
@@ -163,13 +163,10 @@
 #ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
 int Jim_AioInit(Jim_Interp *);
 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)
     {
         if (strlen(entry->buf) != 0)
@@ -182,10 +179,12 @@
     if (httpstate.post_data != NULL)
         Jim_SetVariableStrWithStr(httpstate.jim_interp, 
                                   "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;
 }
 
 int
@@ -269,19 +268,19 @@
         cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
         return 0;
     }    
 
 #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);
         return rc;
     }    
 #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);
         return rc;
     }    
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/forms.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/forms.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/forms.c	2007-11-14 06:39:13.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/forms.c	2007-12-07 09:00:16.000000000 -0800
@@ -43,10 +43,11 @@
  * #####DESCRIPTIONBEGIN####
  * 
  *  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:  
  *               
  * ####DESCRIPTIONEND####
@@ -74,15 +75,19 @@
 CYG_HAL_TABLE_END(cyg_httpd_fvars_table_end, httpd_fvars_table);
 
 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*
 cyg_httpd_store_form_variable(char *query, cyg_httpd_fvars_table_entry *entry)
 {
@@ -107,18 +112,18 @@
             p++;
             len++;
             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;
 } 
 
 // We'll try to parse the data from the form, and store it in the variables
@@ -135,23 +140,29 @@
     {
         entry->buf[0] = '\0';
         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++;
         }
                 
         if (entry == cyg_httpd_fvars_table_end)
         {
@@ -189,15 +200,22 @@
     }
             
     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);
         return;
     }
@@ -209,47 +227,47 @@
     {
         cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
         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);
 
 #if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) || \
@@ -265,30 +283,27 @@
                               strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
     {                              
         // 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    
     
     handler h = cyg_httpd_find_handler();
     if (h != 0)
     {
         // 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;
 }
 
 
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/handler.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/handler.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/handler.c	2006-11-27 07:41:56.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/handler.c	2007-12-04 13:45:35.000000000 -0800
@@ -66,11 +66,11 @@
 #include <cyg/athttpd/socket.h>
 #include <cyg/athttpd/handler.h>
 #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,
     0x34, 0xe4, 0xe4, 0xe4, 0xc1, 0xc1, 0xc1, 0xa3,
     0x71, 0x0b, 0xc2, 0x8f, 0x2a, 0xb7, 0xb7, 0xb7,
@@ -116,11 +116,11 @@
     0x05, 0x2b, 0xc9, 0xca, 0xcb, 0x05, 0x04, 0x44,
     0x00, 0x01, 0x26, 0xd2, 0xd3, 0xd4, 0x52, 0x4b,
     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,
     0xff, 0xc1, 0xc1, 0xc1, 0xe4, 0xe4, 0xe4, 0xfd,
     0xfd, 0xfd, 0xd8, 0xeb, 0xff, 0xc0, 0xdf, 0xff,
@@ -192,11 +192,11 @@
     0x87, 0xc3, 0x87, 0x0e, 0x09, 0x14, 0x30, 0x04,
     0x20, 0x80, 0x8e, 0x8b, 0x18, 0x2f, 0x76, 0x42,
     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,
     0xc3, 0x9d, 0xb5, 0xce, 0xd0, 0xdc, 0xe7, 0xa9,
     0xbe, 0xd4, 0x74, 0x97, 0xb9, 0x65, 0x8c, 0xb2,
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/http.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/http.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/http.c	2007-11-14 06:39:13.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/http.c	2007-12-05 16:07:22.000000000 -0800
@@ -290,13 +290,11 @@
                     &tm_mod.tm_hour,
                     &tm_mod.tm_min,
                     &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,
                         &tm_mod.tm_hour,
                         &tm_mod.tm_min,
@@ -409,21 +407,10 @@
     cyg_int32  err;
     FILE      *fp;
     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, "/");
     strcat(file_name, name);
     cyg_httpd_cleanup_filename(file_name);
@@ -456,27 +443,18 @@
         // Directories need a trialing slash, and if missing, we'll redirect
         //  the client to the right URL. This is called (appropriately
         //  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;
         }
 
         // We are going to try to locate an index page in the directory we got
@@ -505,13 +483,13 @@
         return;
     }    
     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;
     else    
         httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
@@ -520,11 +498,11 @@
     httpstate.mode &= ~CYG_HTTPD_MODE_NO_CACHE;
     cyg_int32 payload_size = cyg_httpd_format_header();
     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, 
              payload_size,
              0);
@@ -556,11 +534,11 @@
         bread = fread(httpstate.outbuffer, 1, CYG_HTTPD_MAXOUTBUFFER, fp);
         bytes_written += cyg_httpd_write(httpstate.outbuffer, bread);
     }    
     
     err = fclose(fp);
-    if(err < 0)
+    if (err < 0)
         cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
 }
 #endif
 
 cyg_int32
@@ -607,18 +585,18 @@
                     httpstate.needs_auth->auth_domainname);
         }
         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);
             sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
                     "stale=false, algorithm=%s, qop=\"%s\"\r\n",
@@ -706,11 +684,12 @@
 }
 
 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, 
                               CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR, 
                               strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
@@ -720,11 +699,11 @@
     }
     // If the OBJLOADER package is not loaded, then the request for a library
     //  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)
     {
         h(&httpstate);
         return;
@@ -782,14 +761,25 @@
     {
         // Look for encoded characters in the URL.
         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++;
     }
 
@@ -807,11 +797,10 @@
 
 char*
 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;
 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
     diag_printf("POST Request URL: %s\n", httpstate.url);
@@ -847,16 +836,25 @@
 }
 
 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)
         {
             // We need separate flags for HEAD and SEND_HEADERS_ONLY since
             //  we can send a header only even in the case of a GET request
@@ -929,26 +927,35 @@
             p += 14;
             while (*p == ' ')
                 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)
                         p = cyg_httpd_digest_skip(p + 9);
                     else if (strncasecmp(p, "nonce=", 6) == 0)
                         p = cyg_httpd_digest_skip(p + 6);
@@ -966,11 +973,14 @@
                         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');
         }   
 #endif // CYGOPT_NET_ATHTTPD_USE_AUTH
@@ -985,40 +995,10 @@
         }
         else
             // 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;
 }
 
 void
 cyg_httpd_process_method(void)
@@ -1028,16 +1008,28 @@
     // Some browsers send an extra '\r\n' after the POST data that is not
     //  accounted in the "Content-Length:" field. We are going to junk all
     //  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:
             case CYG_HTTPD_METHOD_HEAD:
                 cyg_httpd_handle_method_GET();
diff -r -U 5 -N -x CVS -x '*~' -x '.#~' /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/socket.c /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/socket.c
--- /home/atonizzo/ecos/clean/packages/net/athttpd/current/src/socket.c	2006-11-27 07:41:56.000000000 -0800
+++ /home/atonizzo/ecos/devo_athttpd/packages/net/athttpd/current/src/socket.c	2007-12-06 10:46:40.000000000 -0800
@@ -69,11 +69,11 @@
 #include <cyg/athttpd/cgi.h>
 
 #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]     
                                        __attribute__((__aligned__ (16)));
 CYG_HTTPD_STATE httpstate;
@@ -106,35 +106,36 @@
                     buf_len);
 #endif    
     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
 //  be present in the header with a correct value, and whenever that is not
 //  possible, chunked transfers must be used.
 //
 // A chunked transer takes the form of:
 // -----------------------------------------------------------------------------
 //    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();
 // -----------------------------------------------------------------------------
 ssize_t
 cyg_httpd_start_chunked(char *extension)
 {
     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'
     //  should be enough, but several posting on the subject I read seem to
     //  imply otherwise, at least with early generation browsers that supported
@@ -145,11 +146,11 @@
     //  requires it.
     httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
 #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);
     
     httpstate.last_modified = -1;
     httpstate.mime_type = cyg_httpd_find_mime_string(extension);
@@ -158,34 +159,33 @@
 }
 
 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)
-        return;
-    strcpy(httpstate.outbuffer, "0\r\n\r\n");
-    cyg_httpd_write(httpstate.outbuffer, 5);
+    if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) == 0)
+    {
+        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
 //  _will_trust_ the "Content-Length:" field when present!), and the user 
 //  is expected to make sure that the total number of bytes (octets) sent out
@@ -210,20 +210,21 @@
 void
 cyg_httpd_process_request(cyg_int32 index)
 {
     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'
     //  before the terminator than we can safely assume that the header has
     //  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
     {            
         int len = recv(descr,
                        httpstate.inbuffer + httpstate.inbuffer_len,
                        CYG_HTTPD_MAXINBUFFER - httpstate.inbuffer_len,
                        0);
@@ -253,33 +254,68 @@
             diag_printf("ERROR reading from socket. read() returned: %d\n", 
                         httpstate.inbuffer_len);
 #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 just received 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';
 
-    // 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
 cyg_httpd_handle_new_connection(cyg_int32 listener)
 {
@@ -392,11 +428,11 @@
 
 #if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
     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;
     }
     

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

end of thread, other threads:[~2007-12-18 19:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-12-18 15:19 atHTTPD new patch Anthony Tonizzo
2007-12-18 19:06 ` Andrew Lunn
  -- strict thread matches above, loose matches on Subject: below --
2007-12-18  7:15 Øyvind Harboe
2007-12-18  9:06 ` Andrew Lunn
2007-12-10 16:31 Anthony Tonizzo
2007-12-14 10:51 ` Andrew Lunn

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).