fielding 97/01/25 14:37:17
Modified: src buff.h buff.c http_main.c http_protocol.c Log: Fixed bug in bcwrite regarding failure to account for partial writes. Avoids calling bflush() when the client is pipelining requests. Remove unnecessary flushes from http_protocol. Submitted by: Dean Gaudet Reviewed by: Roy Fielding, Alexei Kosut Revision Changes Path 1.10 +1 -0 apache/src/buff.h Index: buff.h =================================================================== RCS file: /export/home/cvs/apache/src/buff.h,v retrieving revision 1.9 retrieving revision 1.10 diff -C3 -r1.9 -r1.10 *** buff.h 1997/01/01 18:10:15 1.9 --- buff.h 1997/01/25 22:37:09 1.10 *************** *** 120,125 **** --- 120,126 ---- extern int bvputs(BUFF *fb, ...); extern int bprintf(BUFF *fb,const char *fmt,...); extern int vbprintf(BUFF *fb,const char *fmt,va_list vlist); + extern int btestread(BUFF *fb); /* Internal routines */ extern int bflsbuf(int c, BUFF *fb); 1.15 +72 -9 apache/src/buff.c Index: buff.c =================================================================== RCS file: /export/home/cvs/apache/src/buff.c,v retrieving revision 1.14 retrieving revision 1.15 diff -C3 -r1.14 -r1.15 *** buff.c 1997/01/20 04:28:07 1.14 --- buff.c 1997/01/25 22:37:10 1.15 *************** *** 402,407 **** --- 402,438 ---- } /* + * Tests if there is data to be read. Returns 0 if there is data, + * -1 otherwise. + */ + int + btestread(BUFF *fb) + { + fd_set fds; + struct timeval tv; + int rv; + + /* the simple case, we've already got data in the buffer */ + if( fb->incnt ) { + return( 0 ); + } + + /* otherwise see if the descriptor would block if we try to read it */ + do { + FD_ZERO( &fds ); + FD_SET( fb->fd_in, &fds ); + tv.tv_sec = 0; + tv.tv_usec = 0; + #ifdef HPUX + rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv ); + #else + rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv ); + #endif + } while( rv < 0 && errno == EINTR ); + return( rv == 1 ? 0 : -1 ); + } + + /* * Skip data until a linefeed character is read * Returns 1 on success, 0 if no LF found, or -1 on error */ *************** *** 469,474 **** --- 500,533 ---- else return buf[0]; } + + /* + * When doing chunked encodings we really have to write everything in the + * chunk before proceeding onto anything else. This routine either writes + * nbytes and returns 0 or returns -1 indicating a failure. + * + * This is *seriously broken* if used on a non-blocking fd. It will poll. + */ + static int + write_it_all( int fd, const void *buf, int nbyte ) { + + int i; + + while( nbyte > 0 ) { + i = write( fd, buf, nbyte ); + if( i == -1 ) { + if( errno != EAGAIN && errno != EINTR ) { + return( -1 ); + } + } else { + nbyte -= i; + buf = i + (const char *)buf; + } + } + return( 0 ); + } + + /* * A hook to write() that deals with chunking. This is really a protocol- * level issue, but we deal with it here because it's simpler; this is *************** *** 476,493 **** * 2.0, using something like sfio stacked disciplines or BSD's funopen(). */ int bcwrite(BUFF *fb, const void *buf, int nbyte) { - int r; if (fb->flags & B_CHUNK) { char chunksize[16]; /* Big enough for practically anything */ ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte); ! write(fb->fd, chunksize, strlen(chunksize)); } ! r = write(fb->fd, buf, nbyte); ! if ((r > 0) && (fb->flags & B_CHUNK)) ! write(fb->fd, "\015\012", 2); ! return r; } /* --- 535,557 ---- * 2.0, using something like sfio stacked disciplines or BSD's funopen(). */ int bcwrite(BUFF *fb, const void *buf, int nbyte) { if (fb->flags & B_CHUNK) { char chunksize[16]; /* Big enough for practically anything */ ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte); ! if( write_it_all(fb->fd, chunksize, strlen(chunksize)) == -1 ) { ! return( -1 ); ! } ! if( write_it_all(fb->fd, buf, nbyte) == -1 ) { ! return( -1 ); ! } ! if( write_it_all(fb->fd, "\015\012", 2) == -1 ) { ! return( -1 ); ! } ! return( nbyte ); } ! return( write(fb->fd, buf, nbyte) ); } /* *************** *** 573,579 **** /* we have emptied the file buffer. Now try to write the data from the * original buffer until there is less than bufsiz left */ ! while (nbyte > fb->bufsiz) { do i = bcwrite(fb, buf, nbyte); while (i == -1 && errno == EINTR); --- 637,643 ---- /* we have emptied the file buffer. Now try to write the data from the * original buffer until there is less than bufsiz left */ ! while (nbyte >= fb->bufsiz) { do i = bcwrite(fb, buf, nbyte); while (i == -1 && errno == EINTR); *************** *** 611,617 **** int bflush(BUFF *fb) { ! int i, j; if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; --- 675,681 ---- int bflush(BUFF *fb) { ! int i; if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; *************** *** 620,626 **** while (fb->outcnt > 0) { /* the buffer must be full */ - j = fb->outcnt; do i = bcwrite(fb, fb->outbase, fb->outcnt); while (i == -1 && errno == EINTR); if (i > 0) fb->bytes_sent += i; --- 684,689 ---- 1.113 +5 -2 apache/src/http_main.c Index: http_main.c =================================================================== RCS file: /export/home/cvs/apache/src/http_main.c,v retrieving revision 1.112 retrieving revision 1.113 diff -C3 -r1.112 -r1.113 *** http_main.c 1997/01/25 20:28:19 1.112 --- http_main.c 1997/01/25 22:37:11 1.113 *************** *** 1675,1681 **** if (r) increment_counts(child_num,r,1); #endif while (r && current_conn->keepalive) { ! bflush(conn_io); destroy_pool(r->pool); (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE, (request_rec*)NULL); --- 1675,1684 ---- if (r) increment_counts(child_num,r,1); #endif while (r && current_conn->keepalive) { ! /* If there's no request waiting for us to read then flush the ! * socket. This is to avoid tickling a bug in older Netscape ! * clients. */ ! if( btestread(conn_io) == -1 ) bflush(conn_io); destroy_pool(r->pool); (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE, (request_rec*)NULL); *************** *** 2150,2156 **** if (r) process_request (r); /* else premature EOF (ignore) */ while (r && conn->keepalive) { ! bflush(cio); destroy_pool(r->pool); r = read_request (conn); if (r) process_request (r); --- 2153,2159 ---- if (r) process_request (r); /* else premature EOF (ignore) */ while (r && conn->keepalive) { ! if( btestread(cio) == -1 ) bflush(cio); destroy_pool(r->pool); r = read_request (conn); if (r) process_request (r); 1.92 +0 -2 apache/src/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apache/src/http_protocol.c,v retrieving revision 1.91 retrieving revision 1.92 diff -C3 -r1.91 -r1.92 *** http_protocol.c 1997/01/20 04:28:09 1.91 --- http_protocol.c 1997/01/25 22:37:12 1.92 *************** *** 1371,1378 **** o+=w; } } - - if (length > 0) bflush(c->client); SET_BYTES_SENT(r); return total_bytes_sent; --- 1371,1376 ----