dgaudet 98/02/07 02:12:23
Modified: src buff.c buff.h Log: Chunking sucks. I wrote a stress testing module and found two more bugs: - start_chunk() called bflush() called start_chunk() caused chaos - if we ended up in the tail of bwrite() where a memcpy happens to copy the remainder, in certain boundary cases with chunking we would go past the end of the buffer Just generally clean up chunking a bit more. This would be a lot easier if chunking were just a layered I/O handler. Revision Changes Path 1.28 +48 -36 apache-1.2/src/buff.c Index: buff.c =================================================================== RCS file: /export/home/cvs/apache-1.2/src/buff.c,v retrieving revision 1.27 retrieving revision 1.28 diff -u -r1.27 -r1.28 --- buff.c 1998/01/30 09:13:47 1.27 +++ buff.c 1998/02/07 10:12:18 1.28 @@ -71,6 +71,10 @@ #endif #define DEFAULT_BUFSIZE (4096) +/* This must be enough to represent (DEFAULT_BUFSIZE - 3) in hex, + * plus two extra characters. + */ +#define CHUNK_HEADER_SIZE (5) /* * Buffered I/O routines. @@ -186,6 +190,9 @@ } } + +static int bflush_core(BUFF *fb); + /* * Start chunked encoding. * @@ -198,9 +205,6 @@ static void start_chunk( BUFF *fb ) { - char chunksize[16]; /* Big enough for practically anything */ - int chunk_header_size; - if (fb->outchunk != -1) { /* already chunking */ return; @@ -210,21 +214,16 @@ return; } - /* we know that the chunk header is going to take at least 3 bytes... */ - chunk_header_size = ap_snprintf( chunksize, sizeof(chunksize), - "%x\015\012", fb->bufsiz - fb->outcnt - 3 ); /* we need at least the header_len + at least 1 data byte * remember that we've overallocated fb->outbase so that we can always * fit the two byte CRLF trailer */ - if( fb->bufsiz - fb->outcnt < chunk_header_size + 1 ) { - bflush(fb); + if( fb->bufsiz - fb->outcnt < CHUNK_HEADER_SIZE + 1 ) { + bflush_core(fb); } /* assume there's enough space now */ - memcpy( &fb->outbase[fb->outcnt], chunksize, chunk_header_size ); fb->outchunk = fb->outcnt; - fb->outcnt += chunk_header_size; - fb->outchunk_header_size = chunk_header_size; + fb->outcnt += CHUNK_HEADER_SIZE; } @@ -235,13 +234,14 @@ end_chunk( BUFF *fb ) { int i; + char *strp; if( fb->outchunk == -1 ) { /* not chunking */ return; } - if( fb->outchunk + fb->outchunk_header_size == fb->outcnt ) { + if( fb->outchunk + CHUNK_HEADER_SIZE == fb->outcnt ) { /* nothing was written into this chunk, and we can't write a 0 size * chunk because that signifies EOF, so just erase it */ @@ -252,22 +252,21 @@ /* we know this will fit because of how we wrote it in start_chunk() */ i = ap_snprintf( (char *)&fb->outbase[fb->outchunk], - fb->outchunk_header_size, - "%x", fb->outcnt - fb->outchunk - fb->outchunk_header_size ); + CHUNK_HEADER_SIZE, + "%x", fb->outcnt - fb->outchunk - CHUNK_HEADER_SIZE ); /* we may have to tack some trailing spaces onto the number we just wrote * in case it was smaller than our estimated size. We've also written * a \0 into the buffer with ap_snprintf so we might have to put a * \r back in. */ - i += fb->outchunk; - while( fb->outbase[i] != '\015' && fb->outbase[i] != '\012' ) { - fb->outbase[i++] = ' '; - } - if( fb->outbase[i] == '\012' ) { - /* we overwrote the \r, so put it back */ - fb->outbase[i-1] = '\015'; + strp = &fb->outbase[fb->outchunk + i]; + while (i < CHUNK_HEADER_SIZE - 2) { + *strp++ = ' '; + ++i; } + *strp++ = '\015'; + *strp = '\012'; /* tack on the trailing CRLF, we've reserved room for this */ fb->outbase[fb->outcnt++] = '\015'; @@ -747,7 +746,7 @@ int bwrite(BUFF *fb, const void *buf, int nbyte) { - int i, nwr; + int i, nwr, useable_bufsiz; if (fb->flags & (B_WRERR|B_EOUT)) return -1; if (nbyte == 0) return 0; @@ -833,8 +832,12 @@ * original buffer until there is less than bufsiz left. Note that we * use bcwrite() to do this for us, it will do the chunking so that * we don't have to dink around building a chunk in our own buffer. + * Remember we may not be able to use the entire buffer if we're + * chunking. */ - while (nbyte >= fb->bufsiz) + useable_bufsiz = fb->bufsiz; + if (fb->flags & B_CHUNK) useable_bufsiz -= CHUNK_HEADER_SIZE; + while (nbyte >= useable_bufsiz) { i = bcwrite(fb, buf, nbyte); if (i <= 0) { @@ -861,21 +864,10 @@ return nwr; } -/* - * Flushes the buffered stream. - * Returns 0 on success or -1 on error - */ -int -bflush(BUFF *fb) +static int bflush_core(BUFF *fb) { int i; - if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; - - if (fb->flags & B_WRERR) return -1; - - if (fb->flags & B_CHUNK) end_chunk(fb); - while (fb->outcnt > 0) { do { @@ -913,8 +905,28 @@ return -1; } - if (fb->flags & B_CHUNK) + return 0; +} + +/* + * Flushes the buffered stream. + * Returns 0 on success or -1 on error + */ +int bflush(BUFF *fb) +{ + int ret; + + if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; + + if (fb->flags & B_WRERR) return -1; + + if (fb->flags & B_CHUNK) end_chunk(fb); + + ret = bflush_core(fb); + + if (ret == 0 && (fb->flags & B_CHUNK)) { start_chunk(fb); + } return 0; } 1.14 +0 -1 apache-1.2/src/buff.h Index: buff.h =================================================================== RCS file: /export/home/cvs/apache-1.2/src/buff.h,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- buff.h 1998/01/30 09:13:48 1.13 +++ buff.h 1998/02/07 10:12:20 1.14 @@ -83,7 +83,6 @@ int incnt; /* number of bytes left to read from input buffer; * always 0 if had a read error */ int outchunk; /* location of chunk header when chunking */ - int outchunk_header_size; /* how long the header is */ int outcnt; /* number of byte put in output buffer */ unsigned char *inbase; unsigned char *outbase;