--------------------- PatchSet 11178 Date: 2007/01/21 10:26:43 Author: hno Branch: SQUID_2_6 Tag: SQUID_2_6_STABLE8 Log: Back out the chunked decoding for now, deferring it to 2.6.STABLE9. Appears to be some issues, and don't want to hold back 2.6.STABLE8 any longer. Members: ChangeLog:1.604->1.604.2.1 doc/release-notes/release-2.6.html:1.44->1.44.2.1 doc/release-notes/release-2.6.sgml:1.52->1.52.2.1 src/HttpHeader.c:1.91->1.91.2.1 src/client_side.c:1.693->1.693.2.1 src/enums.h:1.237->1.237.2.1 src/http.c:1.419.2.1->1.419.2.2 src/structs.h:1.507->1.507.2.1 Index: squid/ChangeLog =================================================================== RCS file: /cvsroot/squid/squid/ChangeLog,v retrieving revision 1.604 retrieving revision 1.604.2.1 diff -u -r1.604 -r1.604.2.1 --- squid/ChangeLog 21 Jan 2007 04:02:35 -0000 1.604 +++ squid/ChangeLog 21 Jan 2007 10:26:43 -0000 1.604.2.1 @@ -16,9 +16,6 @@ - Don't update object timestamps on a failed revalidation. - Fix how ftp://user@host URLs is rendered when Squid is built with leak checking enabled - - Primitive support for HTTP/1.1 chunked encoding, working around - broken servers sending chunked encoding in response to HTTP/1.0 - requests. Changes to squid-2.6.STABLE7 (Jan 13 2007) Index: squid/doc/release-notes/release-2.6.html =================================================================== RCS file: /cvsroot/squid/squid/doc/release-notes/release-2.6.html,v retrieving revision 1.44 retrieving revision 1.44.2.1 diff -u -r1.44 -r1.44.2.1 --- squid/doc/release-notes/release-2.6.html 21 Jan 2007 04:02:35 -0000 1.44 +++ squid/doc/release-notes/release-2.6.html 21 Jan 2007 10:26:44 -0000 1.44.2.1 @@ -7,7 +7,7 @@

Squid 2.6.STABLE8 release notes

-

Squid Developers

$Id: release-2.6.html,v 1.44 2007/01/21 04:02:35 hno Exp $ +

Squid Developers

$Id: release-2.6.html,v 1.44.2.1 2007/01/21 10:26:44 hno Exp $
This document contains the release notes for version 2.6 of Squid. Squid is a WWW Cache application developed by the Web Caching community. @@ -580,7 +580,6 @@
  • Bug #1872: Date parsing error causing objects to get unexpectedly cached. Problem introduced in 2.6.STABLE6.
  • Bug #1873: authenticateNTLMFixErrorHeader: state 4. NTLM & Negotiate instability introduced in 2.6.STABLE6.
  • -
  • Primitive support for HTTP/1.1 chunked encoding, working around broken servers sending chunked encoding in response to HTTP/1.0 requests.
  • Bug #1783: STALE: Entry's timestamp greater than check time. Clock going backwards?
  • Don't update object timestamps on a failed revalidation.
  • a number of other minor and cosmetic bugfixes. See the list of Index: squid/doc/release-notes/release-2.6.sgml =================================================================== RCS file: /cvsroot/squid/squid/doc/release-notes/release-2.6.sgml,v retrieving revision 1.52 retrieving revision 1.52.2.1 diff -u -r1.52 -r1.52.2.1 --- squid/doc/release-notes/release-2.6.sgml 21 Jan 2007 04:02:35 -0000 1.52 +++ squid/doc/release-notes/release-2.6.sgml 21 Jan 2007 10:26:44 -0000 1.52.2.1 @@ -2,7 +2,7 @@
    Squid 2.6.STABLE8 release notes Squid Developers -$Id: release-2.6.sgml,v 1.52 2007/01/21 04:02:35 hno Exp $ +$Id: release-2.6.sgml,v 1.52.2.1 2007/01/21 10:26:44 hno Exp $ This document contains the release notes for version 2.6 of Squid. @@ -498,7 +498,6 @@ Bug #1872: Date parsing error causing objects to get unexpectedly cached. Problem introduced in 2.6.STABLE6. Bug #1873: authenticateNTLMFixErrorHeader: state 4. NTLM & Negotiate instability introduced in 2.6.STABLE6. - Primitive support for HTTP/1.1 chunked encoding, working around broken servers sending chunked encoding in response to HTTP/1.0 requests. Bug #1783: STALE: Entry's timestamp greater than check time. Clock going backwards? Don't update object timestamps on a failed revalidation. a number of other minor and cosmetic bugfixes. See the list of flags.hit) httpHeaderDelById(hdr, HDR_SET_COOKIE); - httpHeaderDelById(hdr, HDR_TRAILER); - httpHeaderDelById(hdr, HDR_TRANSFER_ENCODING); - httpHeaderDelById(hdr, HDR_UPGRADE); /* handle Connection header */ if (httpHeaderHas(hdr, HDR_CONNECTION)) { /* anything that matches Connection list member will be deleted */ @@ -1903,10 +1900,6 @@ } else if (http->entry->timestamp < squid_curtime) httpHeaderPutInt(hdr, HDR_AGE, squid_curtime - http->entry->timestamp); - if (!httpHeaderHas(hdr, HDR_CONTENT_LENGTH) && http->entry->mem_obj && http->entry->store_status == STORE_OK) { - rep->content_length = contentLen(http->entry); - httpHeaderPutSize(hdr, HDR_CONTENT_LENGTH, rep->content_length); - } } /* Filter unproxyable authentication types */ if (http->log_type != LOG_TCP_DENIED && @@ -1974,7 +1967,7 @@ } /* Append Via */ { - char bbuf[MAX_URL + 32]; + LOCAL_ARRAY(char, bbuf, MAX_URL + 32); String strVia = httpHeaderGetList(hdr, HDR_VIA); snprintf(bbuf, sizeof(bbuf), "%d.%d %s", rep->sline.version.major, @@ -3119,7 +3112,10 @@ } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) { debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd); /* We're finished case */ - if (!done) { + if (httpReplyBodySize(http->request->method, entry->mem_obj->reply) < 0) { + debug(33, 5) ("clientWriteComplete: closing, content_length < 0\n"); + comm_close(fd); + } else if (!done) { debug(33, 5) ("clientWriteComplete: closing, !done\n"); comm_close(fd); } else if (clientGotNotEnough(http)) { @@ -3483,7 +3479,6 @@ http->uri = xstrdup(uri); http->log_uri = xstrndup(uri, MAX_URL); http->range_iter.boundary = StringNull; - httpBuildVersion(&http->http_ver, 1, 0); dlinkAdd(http, &http->active, &ClientActiveRequests); return http; } @@ -4788,8 +4783,7 @@ { squid_off_t cl = httpReplyBodySize(http->request->method, http->entry->mem_obj->reply); int hs = http->entry->mem_obj->reply->hdr_sz; - if (cl < 0) - return 0; + assert(cl >= 0); if (http->out.offset != cl + hs) return 1; return 0; Index: squid/src/enums.h =================================================================== RCS file: /cvsroot/squid/squid/src/enums.h,v retrieving revision 1.237 retrieving revision 1.237.2.1 diff -u -r1.237 -r1.237.2.1 --- squid/src/enums.h 19 Jan 2007 01:10:12 -0000 1.237 +++ squid/src/enums.h 21 Jan 2007 10:26:44 -0000 1.237.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.237 2007/01/19 01:10:12 hno Exp $ + * $Id: enums.h,v 1.237.2.1 2007/01/21 10:26:44 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -209,9 +209,6 @@ HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, - HDR_TE, - HDR_TRANSFER_ENCODING, - HDR_TRAILER, HDR_COOKIE, HDR_DATE, HDR_ETAG, @@ -239,11 +236,12 @@ HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE, + HDR_TITLE, + HDR_TRANSFER_ENCODING, HDR_UPGRADE, HDR_USER_AGENT, HDR_VARY, HDR_VIA, - HDR_EXPECT, HDR_WARNING, HDR_WWW_AUTHENTICATE, HDR_AUTHENTICATION_INFO, Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid/squid/src/http.c,v retrieving revision 1.419.2.1 retrieving revision 1.419.2.2 diff -u -r1.419.2.1 -r1.419.2.2 --- squid/src/http.c 21 Jan 2007 10:00:40 -0000 1.419.2.1 +++ squid/src/http.c 21 Jan 2007 10:26:44 -0000 1.419.2.2 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.419.2.1 2007/01/21 10:00:40 hno Exp $ + * $Id: http.c,v 1.419.2.2 2007/01/21 10:26:44 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -80,7 +80,6 @@ requestUnlink(httpState->orig_request); httpState->request = NULL; httpState->orig_request = NULL; - stringClean(&httpState->chunkhdr); cbdataFree(httpState); } @@ -410,14 +409,12 @@ } /* rewrite this later using new interfaces @?@ */ -static size_t +static void httpProcessReplyHeader(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", @@ -425,7 +422,6 @@ 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)) { @@ -435,19 +431,19 @@ httpBuildVersion(&reply->sline.version, 0, 9); reply->sline.status = HTTP_INVALID_HEADER; ctx_exit(ctx); - return 0; + return; } hdr_size = headersEnd(httpState->reply_hdr.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); + if (!memBufIsNull(&httpState->reply_hdr)) + memBufClean(&httpState->reply_hdr); reply->sline.status = HTTP_HEADER_TOO_LARGE; httpState->reply_hdr_state += 2; ctx_exit(ctx); - return size; + return; } /* headers can be incomplete only if object still arriving */ if (!hdr_size) { @@ -455,7 +451,7 @@ hdr_size = hdr_len; else { ctx_exit(ctx); - return size; /* headers not complete */ + return; /* headers not complete */ } } safe_free(entry->mem_obj->vary_headers); @@ -471,48 +467,17 @@ /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size); - storeAppend(entry, httpState->reply_hdr.buf, hdr_size); - done = hdr_size - old_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); ctx_exit(ctx); - return done; + return; } if (!peer_supports_connection_pinning(httpState)) httpState->orig_request->flags.no_connection_auth = 1; storeTimestampsSet(entry); /* Check if object is cacheable or not based on reply code */ debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status); - if (httpHeaderHas(&reply->header, HDR_TRANSFER_ENCODING)) { - String tr = httpHeaderGetList(&reply->header, HDR_TRANSFER_ENCODING); - const char *pos = NULL; - const char *item = NULL; - int ilen = 0; - if (strListGetItem(&tr, ',', &item, &ilen, &pos)) { - if (ilen == 7 && strncasecmp(item, "chunked", ilen) == 0) { - httpState->flags.chunked = 1; - if (!strListGetItem(&tr, ',', &item, &ilen, &pos)) - item = NULL; - } - if (item) { - /* Can't handle other transfer-encodings */ - debug(11, 1) ("Unexpected transfer encoding '%s'\n", strBuf(tr)); - reply->sline.status = HTTP_INVALID_HEADER; - return done; - } - } - stringClean(&tr); - if (httpState->flags.chunked && reply->content_length >= 0) { - /* Can't have a content-length in chunked encoding */ - reply->sline.status = HTTP_INVALID_HEADER; - return done; - } - } - if (!httpState->flags.chunked) { - /* non-chunked. Handle as one single big chunk (-1 if terminated by EOF) */ - httpState->chunk_size = httpReplyBodySize(httpState->orig_request->method, reply); - } if (httpHeaderHas(&reply->header, HDR_VARY) #if X_ACCELERATOR_VARY || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY) @@ -523,7 +488,7 @@ vary = httpMakeVaryMark(httpState->orig_request, reply); if (!vary) { httpMakePrivate(entry); - goto no_cache; /* XXX Would be better if this was used by the swicht statement below */ + goto no_cache; } entry->mem_obj->vary_headers = xstrdup(vary); if (strBuf(httpState->orig_request->vary_encoding)) @@ -578,7 +543,36 @@ #if HEADERS_LOG headersLog(1, 0, httpState->request->method, reply); #endif - return done; +} + +static int +httpPconnTransferDone(HttpStateData * httpState) +{ + /* return 1 if we got the last of the data on a persistent connection */ + MemObject *mem = httpState->entry->mem_obj; + HttpReply *reply = mem->reply; + squid_off_t clen; + debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd); + debug(11, 5) ("httpPconnTransferDone: content_length=%" PRINTF_OFF_T "\n", + reply->content_length); + /* If we haven't seen the end of reply headers, we are not done */ + if (httpState->reply_hdr_state < 2) + return 0; + clen = httpReplyBodySize(httpState->request->method, reply); + /* If the body size is unknown we must wait for EOF */ + if (clen < 0) + return 0; + /* Barf if we got more than we asked for */ + if (mem->inmem_hi > clen + reply->hdr_sz) + return -1; + /* If there is no message body, we can be persistent */ + if (0 == clen) + return 1; + /* If the body size is known, we must wait until we've gotten all of it. */ + if (mem->inmem_hi < clen + reply->hdr_sz) + return 0; + /* We got it all */ + return 1; } /* Small helper function to verify if connection pinning is supported or not @@ -621,192 +615,6 @@ return rc; } -static void -httpAppendBody(HttpStateData * httpState, const char *buf, ssize_t len, int buffer_filled) -{ - StoreEntry *entry = httpState->entry; - const request_t *request = httpState->request; - const request_t *orig_request = httpState->orig_request; - struct in_addr *client_addr = NULL; - u_short client_port = 0; - int fd = httpState->fd; - int complete = httpState->eof; - int keep_alive = !httpState->eof; - while (len > 0) { - if (httpState->chunk_size > 0) { - size_t size = len; - if (size > httpState->chunk_size) - size = httpState->chunk_size; - httpState->chunk_size -= size; - storeAppend(httpState->entry, buf, size); - buf += size; - len -= size; - } else if (httpState->chunk_size < 0) { - /* non-chunked without content-length */ - storeAppend(httpState->entry, buf, len); - len = 0; - } else if (httpState->flags.chunked) { - char *eol = memchr(buf, '\n', len); - size_t size = eol - buf + 1; - if (!eol) - size = len; - stringAppend(&httpState->chunkhdr, buf, size); - buf += size; - len -= size; - if (strLen(httpState->chunkhdr) > 256) { - debug(11, 1) ("Oversized chunk header on port %d, url %s\n", comm_local_port(fd), entry->mem_obj->url); - comm_close(fd); - return; - } - if (eol) { - if (!httpState->flags.trailer) { - /* chunk header */ - char *end = NULL; - int badchunk = 0; - debug(11, 3) ("Chunk header '%s'\n", strBuf(httpState->chunkhdr)); - httpState->chunk_size = strto_off_t(strBuf(httpState->chunkhdr), &end, 16); - if (end == strBuf(httpState->chunkhdr)) - badchunk = 1; - while (end && (*end == '\r' || *end == ' ' || *end == '\t')) - end++; - if (httpState->chunk_size < 0 || !end || (*end != '\n' && *end == ';')) { - debug(11, 0) ("Invalid chunk header '%s'\n", strBuf(httpState->chunkhdr)); - comm_close(fd); - return; - } - if (badchunk) - continue; /* Skip blank lines */ - debug(11, 2) ("Chunk size %" PRINTF_OFF_T "\n", httpState->chunk_size); - if (httpState->chunk_size == 0) { - debug(11, 3) ("Processing trailer\n"); - httpState->flags.trailer = 1; - } - } else { - /* trailer */ - const char *p = strBuf(httpState->chunkhdr); - while (*p == '\r') - p++; - if (*p == '\n') { - complete = 1; - debug(11, 2) ("Chunked response complete\n"); - } - } - stringReset(&httpState->chunkhdr, NULL); - } - } else { - /* Don't know what to do with this data. Bail out */ - break; - } - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - /* - * the above storeAppend() call could ABORT this entry, - * in that case, the server FD should already be closed. - * there's nothing for us to do. - */ - return; - } - } - if (!httpState->chunk_size && !httpState->flags.chunked) - complete = 1; - if (!complete && len == 0) { - /* Wait for more data or EOF condition */ - if (httpState->flags.keepalive_broken) { - commSetTimeout(fd, 10, NULL, NULL); - } else { - commSetTimeout(fd, Config.Timeout.read, NULL, NULL); - } - commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); - return; - } - /* Is it a incomplete reply? */ - if (httpState->chunk_size > 0) { - debug(11, 1) ("Short response on port %d. Expecting %" PRINTF_OFF_T " octets more\n", comm_local_port(fd), httpState->chunk_size); - comm_close(fd); - return; - } - /* - * Verify that the connection is clean - */ - if (len == 0 && buffer_filled >= 0) { - char buf2[4]; - statCounter.syscalls.sock.reads++; - len = FD_READ_METHOD(fd, buf2, sizeof(buf2)); - if ((len < 0 && !ignoreErrno(errno)) || len == 0) { - keep_alive = 0; - } - } - if (len > 0) { - debug(11, Config.onoff.relaxed_header_parser <= 0 || keep_alive ? 1 : 2) - ("httpReadReply: Excess data from \"%s %s\"\n", - RequestMethodStr[orig_request->method], - storeUrl(entry)); - comm_close(fd); - return; - } - /* - * Verified and done with the reply - */ - fwdComplete(httpState->fwd); - - /* - * If we didn't send a keep-alive request header, then this - * can not be a persistent connection. - */ - if (!httpState->flags.keepalive) - keep_alive = 0; - /* - * If we haven't sent the whole request then this can not be a persistent - * connection. - */ - if (!httpState->flags.request_sent) { - debug(11, 1) ("httpReadReply: Request not yet fully sent \"%s %s\"\n", - RequestMethodStr[orig_request->method], - storeUrl(entry)); - keep_alive = 0; - } - /* - * What does the reply have to say about keep-alive? - */ - if (!entry->mem_obj->reply->keep_alive) - keep_alive = 0; - if (keep_alive) { - int pinned = 0; -#if LINUX_TPROXY - if (orig_request->flags.tproxy) { - client_addr = &httpState->request->client_addr; - } -#endif - /* yes we have to clear all these! */ - commSetDefer(fd, NULL, NULL); - commSetTimeout(fd, -1, NULL, NULL); - commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); -#if DELAY_POOLS - delayClearNoDelay(fd); -#endif - comm_remove_close_handler(fd, httpStateFree, httpState); - fwdUnregister(fd, httpState->fwd); - if (request->flags.pinned) { - pinned = 1; - } else if (request->flags.connection_auth && request->flags.auth_sent) { - pinned = 1; - } - if (orig_request->pinned_connection && pinned) { - clientPinConnection(orig_request->pinned_connection, fd, orig_request, httpState->peer, request->flags.connection_auth); - } else if (httpState->peer) { - if (httpState->peer->options.originserver) - pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host, client_addr, client_port); - else - pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL, client_addr, client_port); - } else { - pconnPush(fd, request->host, request->port, NULL, client_addr, client_port); - } - httpState->fd = -1; - httpStateFree(fd, httpState); - } else { - comm_close(fd); - } -} - /* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ /* XXX this function is too long! */ @@ -814,17 +622,19 @@ httpReadReply(int fd, void *data) { HttpStateData *httpState = data; - LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF + 1); + LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF); StoreEntry *entry = httpState->entry; - ssize_t len; + const request_t *request = httpState->request; + const request_t *orig_request = httpState->orig_request; + int len; int bin; int clen; - int done = 0; size_t read_sz = SQUID_TCP_SO_RCVBUF; + struct in_addr *client_addr = NULL; + u_short client_port = 0; #if DELAY_POOLS delay_id delay_id; #endif - int buffer_filled; if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); @@ -841,8 +651,7 @@ errno = 0; statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, read_sz); - buffer_filled = len == read_sz; - debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, (int) len); + debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_READ); #if DELAY_POOLS @@ -854,7 +663,6 @@ 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 */ @@ -903,14 +711,13 @@ fwdFail(httpState->fwd, errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, httpState->fwd->request)); httpState->fwd->flags.dont_retry = 1; } else { - httpAppendBody(httpState, NULL, 0, -1); /* EOF */ - return; + fwdComplete(httpState->fwd); } comm_close(fd); return; } else { if (httpState->reply_hdr_state < 2) { - done = httpProcessReplyHeader(httpState, buf, len); + httpProcessReplyHeader(httpState, buf, len); if (httpState->reply_hdr_state == 2) { http_status s = entry->mem_obj->reply->sline.status; if (s == HTTP_HEADER_TOO_LARGE) { @@ -937,14 +744,121 @@ */ if (!fwdReforwardableStatus(s)) EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); + } + } + storeAppend(entry, buf, len); + if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + /* + * the above storeAppend() call could ABORT this entry, + * in that case, the server FD should already be closed. + * there's nothing for us to do. + */ + return; + } + switch (httpPconnTransferDone(httpState)) { + case 1: + { + int keep_alive = 1; + /* + * If we didn't send a keep-alive request header, then this + * can not be a persistent connection. + */ + if (!httpState->flags.keepalive) + keep_alive = 0; + /* + * If we haven't sent the whole request then this can not be a persistent + * connection. + */ + if (!httpState->flags.request_sent) { + debug(11, 1) ("httpReadReply: Request not yet fully sent \"%s %s\"\n", + RequestMethodStr[orig_request->method], + storeUrl(entry)); + keep_alive = 0; + } + /* + * What does the reply have to say about keep-alive? + */ + if (!entry->mem_obj->reply->keep_alive) + keep_alive = 0; + /* + * Verify that the connection is clean + */ + if (len == read_sz) { + statCounter.syscalls.sock.reads++; + len = FD_READ_METHOD(fd, buf, SQUID_TCP_SO_RCVBUF); + if ((len < 0 && !ignoreErrno(errno)) || len == 0) { + keep_alive = 0; + } else if (len > 0) { + debug(11, Config.onoff.relaxed_header_parser <= 0 || keep_alive ? 1 : 2) + ("httpReadReply: Excess data from \"%s %s\"\n", + RequestMethodStr[orig_request->method], + storeUrl(entry)); + storeAppend(entry, buf, len); + keep_alive = 0; + } + } + if (keep_alive) { + int pinned = 0; +#if LINUX_TPROXY + if (orig_request->flags.tproxy) { + client_addr = &httpState->request->client_addr; + } +#endif + /* yes we have to clear all these! */ + commSetDefer(fd, NULL, NULL); + commSetTimeout(fd, -1, NULL, NULL); + commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); +#if DELAY_POOLS + delayClearNoDelay(fd); +#endif + comm_remove_close_handler(fd, httpStateFree, httpState); + fwdUnregister(fd, httpState->fwd); + if (request->flags.pinned) { + pinned = 1; + } else if (request->flags.connection_auth && request->flags.auth_sent) { + pinned = 1; + } + if (orig_request->pinned_connection && pinned) { + clientPinConnection(orig_request->pinned_connection, fd, orig_request, httpState->peer, request->flags.connection_auth); + } else if (httpState->peer) { + if (httpState->peer->options.originserver) + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host, client_addr, client_port); + else + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL, client_addr, client_port); + } else { + pconnPush(fd, request->host, request->port, NULL, client_addr, client_port); + } + fwdComplete(httpState->fwd); + httpState->fd = -1; + httpStateFree(fd, httpState); + } else { + fwdComplete(httpState->fwd); + comm_close(fd); + } + } + return; + case 0: + /* Wait for more data or EOF condition */ + if (httpState->flags.keepalive_broken) { + commSetTimeout(fd, 10, NULL, NULL); } else { commSetTimeout(fd, Config.Timeout.read, NULL, NULL); - commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); - return; } + commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); + return; + case -1: + /* Server is nasty on us. Shut down */ + debug(11, Config.onoff.relaxed_header_parser <= 0 || entry->mem_obj->reply->keep_alive ? 1 : 2) + ("httpReadReply: Excess data from \"%s %s\"\n", + RequestMethodStr[orig_request->method], + storeUrl(entry)); + fwdComplete(httpState->fwd); + comm_close(fd); + return; + default: + fatal("Unexpected httpPconnTransferDone() status\n"); + break; } - httpAppendBody(httpState, buf + done, len - done, buffer_filled); - return; } } @@ -1056,7 +970,7 @@ debug(11, 5) ("httpBuildRequestHeader: %s: %s\n", strBuf(e->name), strBuf(e->value)); if (!httpRequestHdrAllowed(e, &strConnection)) { - debug(11, 2) ("'%s' header is a hop-by-hop connections header\n", + debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n", strBuf(e->name)); continue; } @@ -1145,18 +1059,8 @@ if (!Config.onoff.via) httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); break; - case HDR_CONNECTION: - case HDR_KEEP_ALIVE: - /* case HDR_PROXY_AUTHORIZATION: is special and handled above */ - case HDR_PROXY_AUTHENTICATE: - case HDR_TE: - case HDR_TRAILER: - case HDR_TRANSFER_ENCODING: - case HDR_UPGRADE: case HDR_PROXY_CONNECTION: - case HDR_EXPECT: - /* hop-by-hop headers. Don't forward */ - break; + case HDR_CONNECTION: case HDR_CACHE_CONTROL: /* append these after the loop if needed */ break; Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid/squid/src/structs.h,v retrieving revision 1.507 retrieving revision 1.507.2.1 diff -u -r1.507 -r1.507.2.1 --- squid/src/structs.h 19 Jan 2007 01:10:12 -0000 1.507 +++ squid/src/structs.h 21 Jan 2007 10:26:44 -0000 1.507.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.507 2007/01/19 01:10:12 hno Exp $ + * $Id: structs.h,v 1.507.2.1 2007/01/21 10:26:44 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1093,8 +1093,6 @@ unsigned int request_sent:1; unsigned int front_end_https:2; unsigned int originpeer:1; - unsigned int chunked:1; - unsigned int trailer:1; }; struct _HttpStateData { @@ -1110,8 +1108,6 @@ FwdState *fwd; char *body_buf; int body_buf_sz; - squid_off_t chunk_size; - String chunkhdr; }; struct _icpUdpData {