You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/12/20 23:36:12 UTC

[PATCH] fix Rasmus' chunking error

On Tue, 16 Dec 1997, Roy T. Fielding wrote:

> >When I load up the port 81 page a dialog pops up which says:
> >
> >  "Internet Explorer cannot open the Internet Site http://www.ler....
> >   Could not complete operation due to error 800c0008"
> >
> >and it shows me about 3/4 of the page.  The port 80 URL comes up fine.
> >Both servers are set up with the same document root for the
> >www.lerdorf.on.ca host-header virtual host, so it is the exact same file
> >being served up in both cases.
> 
> The last chunk is screwed up....
> 
>    positive input during the initial development of the interpreter.
>    ^M
>    1^M
>    <^M
>    /font>
>    </body></html>
>    0^M
>    ^M
> 
> which means that the module is doing something screwy with the buff.c
> calls or there is some borderline case that is being tickled.  You
> could output the same contents as a CGI (without content-length)
> and see if that is the case, but I suspect it is a problem with
> mixing buffers.  Try a systrace (truss) to see if you can pick up on
> a weird call pattern, or try stepping through it with gdb.
> 
> This is definitely not a bug in IE4.

Right, it's our bug.  In fact there's two buglets happening.  The first is
that bputc() does not understand chunking... it's a macro defined in
buff.h and I guess I missed it.  When it fills the buffer it calls
bflsbuf() to flush and buffer a single character, but it doesn't call
start_chunk() before starting the new buffer. Rather than slow down/expand
the macro any I chose to fix this problem by doing a start_chunk() in the
bflsbuf() routine.  This bug exists in 1.2. 

The second buglet is that when using bputc(), it is way easy to trigger
the large_write() code.  What was happening above was that it would
trigger large_write(), do a 4 element writev() (the buffer, chunked, plus
a chunk header, the 1 byte to write, and a chunk footer).  A workaround is
to not consider 1 byte writes for large_write().  large_write isn't in 1.2
so this bug isn't either. 

Dean

Index: main/buff.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/buff.c,v
retrieving revision 1.51
diff -u -r1.51 buff.c
--- buff.c	1997/11/13 20:37:57	1.51
+++ buff.c	1997/12/20 22:20:30
@@ -807,9 +807,16 @@
 API_EXPORT(int) bflsbuf(int c, BUFF *fb)
 {
     char ss[1];
+    int rc;
 
     ss[0] = c;
-    return bwrite(fb, ss, 1);
+    rc = bwrite(fb, ss, 1);
+    /* We do start_chunk() here so that the bputc macro can be smaller
+     * and faster
+     */
+    if (rc == 1 && (fb->flags & B_CHUNK))
+	start_chunk(fb);
+    return rc;
 }
 
 /*
@@ -1059,9 +1080,12 @@
 #ifndef NO_WRITEV
 /*
  * Detect case where we're asked to write a large buffer, and combine our
- * current buffer with it in a single writev()
+ * current buffer with it in a single writev().  Note we don't consider
+ * the case nbyte == 1 because modules which use rputc() loops will cause
+ * us to use writev() too frequently.  In those cases we really should just
+ * start a new buffer.
  */
-    if (fb->outcnt > 0 && nbyte + fb->outcnt >= fb->bufsiz) {
+    if (fb->outcnt > 0 && nbyte > 1 && nbyte + fb->outcnt >= fb->bufsiz) {
 	return large_write(fb, buf, nbyte);
     }
 #endif