From: Alex Rousskov Date: Tue, 24 Aug 2010 04:18:51 +0000 (-0600) Subject: Compliance: remove Content-Length header if Transfer-Encoding is present. X-Git-Tag: take1~337 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c3d0ba0c0522ec460dd8ebf1af38f432ddba71c8;p=thirdparty%2Fsquid.git 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 ffd9fbaaba..0f597654a1 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -254,6 +254,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 */ @@ -279,4 +280,11 @@ SQUIDCEXTERN int httpHeaderHasByNameListMember(const HttpHeader * hdr, const cha SQUIDCEXTERN void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask); 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 8a5950a92a..5c55886cb7 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -541,7 +541,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 d79704ba3d..de1e5229dc 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -498,7 +498,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; @@ -506,7 +506,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 921ff931da..ee33f79cee 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1988,8 +1988,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 82c5c0b2b1..3d1d8bdc78 100644 --- a/src/http.cc +++ b/src/http.cc @@ -726,7 +726,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; }