From: Amos Jeffries Date: Fri, 27 Aug 2010 16:46:02 +0000 (-0600) Subject: Author: Alex Rousskov X-Git-Tag: SQUID_3_1_8~24 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=55dfe0ccdf8192c5184bcfa368e0cd9dead880f6;p=thirdparty%2Fsquid.git Author: Alex Rousskov HTTP Compliance: remove Content-Length header if Transfer-Encoding is present. If after HTTP header parsing we have both "Transfer-Encoding: chunked" and Content-Length headers, remove the Content-Length entry. The adjusted behavior follows httpbis recommendations (ticket #95, part 2). The old client-side code forwarded the original Content-Length header which did not match the [dechunked] response, resulting in a malformed response. HttpHeader::chunked() method added to check if HTTP headers contain chunked Transfer-Encoding header. Use this method in code that checks for chunked encoding. Co-Advisor test cases: test_case/rfc2616/chunked-1p0-badClen-toClt test_case/rfc2616/chunked-1p1-badClen-toClt --- diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index b1f7f6e390..38807f4d8b 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -647,6 +647,11 @@ HttpHeader::parse(const char *header_start, const char *header_end) addEntry(e); } + if (chunked()) { + // RFC 2616 section 4.4: ignore Content-Length with Transfer-Encoding + delById(HDR_CONTENT_LENGTH); + } + PROF_stop(HttpHeaderParse); return 1; /* even if no fields where found, it is a valid header */ reset: diff --git a/src/HttpHeader.h b/src/HttpHeader.h index e7a26a3813..d37ad29200 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -255,6 +255,7 @@ public: int hasListMember(http_hdr_type id, const char *member, const char separator) const; int hasByNameListMember(const char *name, const char *member, const char separator) const; void removeHopByHopEntries(); + inline bool chunked() const; ///< whether message uses chunked Transfer-Encoding /* protected, do not use these, use interface functions instead */ Vector entries; /**< parsed fields in raw format */ @@ -282,4 +283,11 @@ int httpMsgIsPersistent(HttpVersion const &http_ver, const HttpHeader * hdr); SQUIDCEXTERN void httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count); +inline bool +HttpHeader::chunked() const +{ + return has(HDR_TRANSFER_ENCODING) && + hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','); +} + #endif /* SQUID_HTTPHEADER_H */ diff --git a/src/HttpReply.cc b/src/HttpReply.cc index f82a1bd803..6110a2b2a3 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -540,7 +540,7 @@ HttpReply::expectingBody(const HttpRequestMethod& req_method, int64_t& theSize) expectBody = true; if (expectBody) { - if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) + if (header.chunked()) theSize = -1; else if (content_length >= 0) theSize = content_length; diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 006583d53b..ca1637e0ae 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -492,7 +492,7 @@ HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t& theSize) co expectBody = Config.onoff.request_entities ? true : false; else if (method == METHOD_PUT || method == METHOD_POST) expectBody = true; - else if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) + else if (header.chunked()) expectBody = true; else if (content_length >= 0) expectBody = true; @@ -500,7 +500,7 @@ HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t& theSize) co expectBody = false; if (expectBody) { - if (header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) + if (header.chunked()) theSize = -1; else if (content_length >= 0) theSize = content_length; diff --git a/src/client_side.cc b/src/client_side.cc index 315ac0f9b7..b3e342bbb6 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1935,8 +1935,7 @@ isChunkedRequest(const HttpParser *hp) if (!request.parseHeader(HttpParserHdrBuf(hp), HttpParserHdrSz(hp))) return false; - return request.header.has(HDR_TRANSFER_ENCODING) && - request.header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ','); + return request.header.chunked(); } diff --git a/src/http.cc b/src/http.cc index 2906a3808d..7956a8ab6c 100644 --- a/src/http.cc +++ b/src/http.cc @@ -729,7 +729,7 @@ HttpStateData::processReplyHeader() } flags.chunked = 0; - if (newrep->sline.protocol == PROTO_HTTP && newrep->header.hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',')) { + if (newrep->sline.protocol == PROTO_HTTP && newrep->header.chunked()) { flags.chunked = 1; httpChunkDecoder = new ChunkedCodingParser; }