--------------------- PatchSet 10318 Date: 2007/12/27 05:01:45 Author: adri Branch: s27_adri Tag: (none) Log: Use memBufFill() to read into the MemBuf; use httpState.reply_hdr now as an incoming socket buffer. This avoids the memcpy() from the 64k read buffer into the reply_hdr when parsing. My choice of buffer size is probably wrong and I can tweak all of that at a later time. Members: src/http.c:1.63.2.3.4.19->1.63.2.3.4.20 Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.63.2.3.4.19 retrieving revision 1.63.2.3.4.20 diff -u -r1.63.2.3.4.19 -r1.63.2.3.4.20 --- squid/src/http.c 22 Dec 2007 14:38:58 -0000 1.63.2.3.4.19 +++ squid/src/http.c 27 Dec 2007 05:01:45 -0000 1.63.2.3.4.20 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.63.2.3.4.19 2007/12/22 14:38:58 adri Exp $ + * $Id: http.c,v 1.63.2.3.4.20 2007/12/27 05:01:45 adri Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -413,41 +413,48 @@ } /* rewrite this later using new interfaces @?@ */ + +/* + * process a reply header chunk in buf/size. + * + * Returns 0 if there was a problem(?); or the number of bytes in buf/size + * to be considered as part of the 'header'. (Ie, everything to be consumed). + * + * Remainder bytes are (probably) HTTP reply body data, except in the case + * of a 1xx status reply where the next chunk of data is a second reply + * chunk. + */ static size_t -httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size) +httpProcessReplyHeaderBlock(HttpStateData * httpState, const char *buf, int size) { StoreEntry *entry = httpState->entry; size_t hdr_len; size_t hdr_size; - size_t old_size; - size_t done; HttpReply *reply = entry->mem_obj->reply; Ctx ctx = ctx_enter(entry->mem_obj->url); debug(11, 3) ("httpProcessReplyHeader: key '%s'\n", storeKeyText(entry->hash.key)); - if (memBufIsNull(&httpState->reply_hdr)) - memBufDefInit(&httpState->reply_hdr); + assert(httpState->reply_hdr_state == 0); - old_size = httpState->reply_hdr.size; - memBufAppend(&httpState->reply_hdr, buf, size); - hdr_len = httpState->reply_hdr.size; - if (hdr_len > 4 && strncmp(httpState->reply_hdr.buf, "HTTP/", 5)) { - debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf); + hdr_len = size; + + if (hdr_len > 4 && strncmp(buf, "HTTP/", 5)) { + debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%.*s'\n", size, buf); httpState->reply_hdr_state += 2; httpState->chunk_size = -1; /* Terminated by EOF */ - httpState->reply_hdr.size = old_size; + // XXX how am I meant to handle a non-compliant header? Just bomb the rest of the request? + //httpState->reply_hdr.size = old_size; httpBuildVersion(&reply->sline.version, 0, 9); reply->sline.status = HTTP_INVALID_HEADER; ctx_exit(ctx); return 0; } - hdr_size = headersEnd(httpState->reply_hdr.buf, hdr_len); + hdr_size = headersEnd(buf, hdr_len); if (hdr_size) hdr_len = hdr_size; if (hdr_len > Config.maxReplyHeaderSize) { debug(11, 1) ("httpProcessReplyHeader: Too large reply header\n"); - storeAppend(entry, httpState->reply_hdr.buf, httpState->reply_hdr.size); - memBufClean(&httpState->reply_hdr); + storeAppend(entry, buf, size); reply->sline.status = HTTP_HEADER_TOO_LARGE; httpState->reply_hdr_state += 2; ctx_exit(ctx); @@ -464,35 +471,30 @@ } stringClean(&entry->mem_obj->vary_headers); stringClean(&entry->mem_obj->vary_encoding); - /* Cut away any excess body data (only needed for debug?) */ - memBufAppend(&httpState->reply_hdr, "\0", 1); - httpState->reply_hdr.buf[hdr_size] = '\0'; httpState->reply_hdr_state++; assert(httpState->reply_hdr_state == 1); httpState->reply_hdr_state++; - debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n", - httpState->reply_hdr.buf); + debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%.*s\n----------\n", + (int) hdr_size, buf); /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ - httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size); - done = hdr_size - old_size; + httpReplyParse(reply, buf, hdr_size); + /* Skip 1xx messages for now. Advertised in Via as an internal 1.0 hop */ if (reply->sline.status >= 100 && reply->sline.status < 200) { - memBufClean(&httpState->reply_hdr); httpReplyReset(reply); httpState->reply_hdr_state = 0; ctx_exit(ctx); - if (done < size) - return done + httpProcessReplyHeader(httpState, buf + done, size - done); + if (hdr_size < size) + return hdr_size + httpProcessReplyHeaderBlock(httpState, buf + hdr_size, size - hdr_size); else - return done; + return hdr_size; } - storeAppend(entry, httpState->reply_hdr.buf, hdr_size); + storeAppend(entry, buf, hdr_size); if (reply->sline.status >= HTTP_INVALID_HEADER) { - debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf); - memBufClean(&httpState->reply_hdr); + debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%.*s'\n", (int) hdr_size, buf); ctx_exit(ctx); - return done; + return hdr_size; } if (!peer_supports_connection_pinning(httpState)) httpState->orig_request->flags.no_connection_auth = 1; @@ -514,7 +516,7 @@ /* Can't handle other transfer-encodings */ debug(11, 1) ("Unexpected transfer encoding '%.*s'\n", strLen2(tr), strBuf2(tr)); reply->sline.status = HTTP_INVALID_HEADER; - return done; + return hdr_size; } } stringClean(&tr); @@ -578,8 +580,8 @@ httpState->peer->stats.n_keepalives_recv++; if (Config.onoff.detect_broken_server_pconns && httpReplyBodySize(httpState->request->method, reply) == -1) { debug(11, 1) ("httpProcessReplyHeader: Impossible keep-alive header from '%s'\n", storeUrl(entry)); - debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n", - httpState->reply_hdr.buf); + debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%.*s\n----------\n", + (int) hdr_size, buf); httpState->flags.keepalive_broken = 1; } } @@ -593,7 +595,7 @@ #if HEADERS_LOG headersLog(1, 0, httpState->request->method, reply); #endif - return done; + return hdr_size; } /* Small helper function to verify if connection pinning is supported or not @@ -846,7 +848,6 @@ httpReadReply(int fd, void *data) { HttpStateData *httpState = data; - LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF + 1); StoreEntry *entry = httpState->entry; ssize_t len; int bin; @@ -872,7 +873,12 @@ errno = 0; statCounter.syscalls.sock.reads++; - len = FD_READ_METHOD(fd, buf, read_sz); + /* XXX this breaks delay pools for now - need to pass in a 'max read size' parameter to memBufFill */ + + if (memBufIsNull(&httpState->reply_hdr)) + memBufDefInit(&httpState->reply_hdr); + len = memBufFill(&httpState->reply_hdr, fd); + buffer_filled = len == read_sz; debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, (int) len); if (len > 0) { @@ -886,12 +892,12 @@ for (clen = len - 1, bin = 0; clen; bin++) clen >>= 1; IOStats.Http.read_hist[bin]++; - buf[len] = '\0'; } if (!httpState->reply_hdr.size && len > 0 && fd_table[fd].uses > 1) { /* Skip whitespace */ - while (len > 0 && xisspace(*buf)) - xmemmove(buf, buf + 1, len--); + /* XXX must redo this later once we're using buf's and offset pointers, not MemBuf's */ + //while (len > 0 && xisspace(*buf)) + // xmemmove(buf, buf + 1, len--); if (len == 0) { /* Continue to read... */ /* Timeout NOT increased. This whitespace was from previous reply */ @@ -926,7 +932,8 @@ * we want to process the reply headers. */ /* Fake an "end-of-headers" to work around such broken servers */ - httpProcessReplyHeader(httpState, "\r\n", 2); + memBufAppend(&httpState->reply_hdr, "\r\n", 2); + httpProcessReplyHeaderBlock(httpState, httpState->reply_hdr.buf, httpState->reply_hdr.size); } if (entry->mem_obj->reply->sline.status == HTTP_HEADER_TOO_LARGE) { storeEntryReset(entry); @@ -949,7 +956,7 @@ * httpAppendBody(). */ storeBuffer(entry); - done = httpProcessReplyHeader(httpState, buf, len); + done = httpProcessReplyHeaderBlock(httpState, httpState->reply_hdr.buf, httpState->reply_hdr.size); if (httpState->reply_hdr_state == 2) { http_status s = entry->mem_obj->reply->sline.status; if (s == HTTP_HEADER_TOO_LARGE) { @@ -976,7 +983,6 @@ mb = httpReplyPack(reply); storeAppend(entry, mb.buf, mb.size); storeAppend(entry, httpState->reply_hdr.buf, httpState->reply_hdr.size); - memBufClean(&httpState->reply_hdr); httpReplyReset(reply); httpReplyParse(reply, mb.buf, mb.size); memBufClean(&mb); @@ -996,7 +1002,10 @@ return; } } - httpAppendBody(httpState, buf + done, len - done, buffer_filled); + assert(! memBufIsNull(&httpState->reply_hdr)); + httpAppendBody(httpState, httpState->reply_hdr.buf + done, httpState->reply_hdr.size - done, buffer_filled); + if (! memBufIsNull(&httpState->reply_hdr)) + memBufClean(&httpState->reply_hdr); return; } }