The new diff available for Flood fixes protocol errors for keepalive (file flood_socket_keepalive.c, function keepalive_recv_resp()) mainly by assimilating the functionality of the wantresponse and !wantresponse modes within the readback operations, and maintaining whatever worked correctly. Also the algorithm for reading a decimal value within the above function was simplified (we found cases where what was replaced did not work), as was the routine for reading a hexadecimal value (this being in the function keepalive_read_chunk_size()), the same reason for its replacement applying.
Since this diff is independent of other changes made recently, I have done it off the original file in CVS/Flood 1.1, which I have in my local directory c:\flood-1.1 Norman Tuttle, developer, OpenDemand Systems, [EMAIL PROTECTED] PS: In a comparison between the 2 modes mentioned above (wantresponse and !wantresponse), the Chunked Transfer-Encoding method of reading of the body is absent from the wantresponse pathway. I was wondering whether that was inadvertent, and if so, it looks like we will have to add this functionality as well or our readback of data in that case will be incomplete.
--- flood_socket_keepalive.c 2003-10-22 12:11:38.000000000 -0400 +++ \flood-1.1\flood_socket_keepalive.c 2003-09-06 00:27:38.000000000 -0400 @@ -161,17 +161,25 @@ write_socket(ksock->s, req); } -/* This is really a hex evaluator function. */ static long keepalive_read_chunk_size(char *begin_chunk) { - long OutputHex=0; - unsigned char Addend; - while (isspace(*begin_chunk)) begin_chunk++; - while (isxdigit(Addend=(*(begin_chunk++)))) + char chunk[17], *end_chunk; + long chunk_length; + + /* FIXME: Handle chunk-extension */ + end_chunk = strstr(begin_chunk, CRLF); + + if (end_chunk && end_chunk - begin_chunk < 16) { - OutputHex=(OutputHex<<4)+((Addend & 0xF)+((Addend > '9')?9:0)); + strncpy(chunk, begin_chunk, end_chunk - begin_chunk); + chunk[end_chunk-begin_chunk] = '\0'; + /* Chunks are base-16 */ + chunk_length = strtol(chunk, &end_chunk, 16); + if (*end_chunk == '\0') + return chunk_length; } - return OutputHex; + + return 0; } static apr_status_t keepalive_read_chunk(response_t *resp, @@ -233,7 +241,7 @@ return status; } - /* We got caught in the middle of a chunk last time. */ + /* We got caught in the middle of a chunk last time. */ if (old_length < 0) { b -= old_length; blen += old_length; @@ -299,7 +307,7 @@ return APR_SUCCESS; } -static apr_status_t keepalive_load_resp(response_t *resp, +static apr_status_t keepalive_load_resp(response_t *resp, keepalive_socket_t *sock, apr_size_t remaining, apr_pool_t *pool) { @@ -352,7 +360,7 @@ cp += i; remaining -= i; } - while (status != APR_EGENERAL && status != APR_EOF && + while (status != APR_EGENERAL && status != APR_EOF && status != APR_TIMEUP && (!remain || remaining)); return status; @@ -366,7 +374,6 @@ keepalive_socket_t *ksock = (keepalive_socket_t *)sock; char *cl, *ecl, cls[17]; char *current_line; - int keep_reading = 0; int i; response_t *new_resp; apr_status_t status; @@ -400,7 +407,7 @@ header_end = memchr(current_line, ':', line_length); if (header_end) { key_length = header_end - current_line; - + header_key = apr_pstrmemdup(pool, current_line, key_length); header_val = apr_pstrmemdup(pool, current_line + key_length + 2, line_length - key_length - 2); @@ -413,10 +420,10 @@ /* If this exists, we aren't keepalive anymore. */ header = apr_table_get(new_resp->headers, "Connection"); if (header && !strcasecmp(header, "Close")) { - new_resp->keepalive = 0; + new_resp->keepalive = 0; } else { - new_resp->keepalive = 1; + new_resp->keepalive = 1; } /* If we have a HEAD request, we shouldn't be receiving a body. */ @@ -426,12 +433,11 @@ return APR_SUCCESS; } - new_resp->chunk = NULL; - new_resp->chunked = 0; header = apr_table_get(new_resp->headers, "Transfer-Encoding"); if (header && !strcasecmp(header, "Chunked")) { new_resp->chunked = 1; + new_resp->chunk = NULL; /* Find where headers ended */ cl = current_line; @@ -443,7 +449,7 @@ /* We have a partial chunk and we aren't at the end. */ if (cl && *cl && (cl - (char*)new_resp->rbuf) < new_resp->rbufsize) { int remaining; - + do { if (new_resp->chunk) { /* If we have enough space to skip over the ending CRLF, @@ -468,13 +474,10 @@ chunk_length = keepalive_read_chunk_size(new_resp->chunk); /* Search for the beginning of the chunk. */ foo = strstr(new_resp->chunk, CRLF); - if (!foo) - { - return APR_EGENERAL; // this is a serious error involving violation of chunking protocol! - } + assert(foo); new_resp->chunk = foo + 2; - remaining = new_resp->rbufsize - - (int)(new_resp->chunk - + remaining = new_resp->rbufsize - + (int)(new_resp->chunk - (char*)new_resp->rbuf); } else { @@ -492,12 +495,23 @@ header = apr_table_get(new_resp->headers, "Content-Length"); if (!header) { - new_resp->keepalive = 0; + new_resp->keepalive = 0; } - else + + if (header) { - if ((content_length = atol(header))<=0) keep_reading = 1; + cl = (char*)header; + ecl = cl + strlen(cl); + if (ecl && ecl - cl < 16) + { + strncpy(cls, cl, ecl - cl); + cls[ecl-cl] = '\0'; + content_length = strtol(cls, &ecl, 10); + if (*ecl != '\0') + new_resp->keepalive = 0; + } } + if (new_resp->keepalive) { /* Find where we ended */ @@ -505,24 +519,20 @@ /* We didn't get full headers. Crap. */ if (!ecl) - new_resp->keepalive = 0; + new_resp->keepalive = 0; { ecl += sizeof(CRLF) - 1; content_length -= new_resp->rbufsize - (ecl - (char*)new_resp->rbuf); - } + } } } - + if (ksock->wantresponse) { - if (new_resp->keepalive) - { - if ((keep_reading)||(content_length>0)) - { - status = keepalive_load_resp(new_resp, ksock, content_length, pool); - } - } - else status = keepalive_load_resp(new_resp, ksock, 0, pool); + if (new_resp->keepalive) + status = keepalive_load_resp(new_resp, ksock, content_length, pool); + else + status = keepalive_load_resp(new_resp, ksock, 0, pool); } else { @@ -534,9 +544,9 @@ } else if (new_resp->keepalive) { - while ((keep_reading || content_length) && status != APR_EGENERAL && + while (content_length && status != APR_EGENERAL && status != APR_EOF && status != APR_TIMEUP) { - if ((keep_reading)||(content_length > MAX_DOC_LENGTH - 1)) + if (content_length > MAX_DOC_LENGTH - 1) i = MAX_DOC_LENGTH - 1; else i = content_length; @@ -544,16 +554,14 @@ status = ksock_read_socket(ksock, b, &i); content_length -= i; - new_resp->rbufsize += i; // This makes sure the rbufsize maintains the real count, required by reporting! } } else { - while (status != APR_EGENERAL && status != APR_EOF && + while (status != APR_EGENERAL && status != APR_EOF && status != APR_TIMEUP) { i = MAX_DOC_LENGTH - 1; status = ksock_read_socket(ksock, b, &i); - new_resp->rbufsize += i; // This makes sure the rbufsize maintains the real count, required by reporting! } } } @@ -574,7 +582,7 @@ ksock->ssl ? ssl_close_socket(ksock->s) : close_socket(ksock->s); ksock->reopen_socket = 1; /* we just closed it */ } - + return APR_SUCCESS; }