from:

commit fd68382860633aca92065e6c343cfd1b12b126e7
Author: Amos Jeffries <yadij@users.noreply.github.com>
Date:   Sun Aug 16 02:21:22 2020 +0000

    Improve Transfer-Encoding handling (#702)

    Reject messages containing Transfer-Encoding header with coding other
    than chunked or identity. Squid does not support other codings.

    For simplicity and security sake, also reject messages where
    Transfer-Encoding contains unnecessary complex values that are                                                                                                                                technically equivalent to "chunked" or "identity" (e.g., ",,chunked" or
    "identity, chunked").

    RFC 7230 formally deprecated and removed identity coding, but it is
    still used by some agents.

Index: squid-3.1.23/src/HttpHeader.cc
===================================================================
--- squid-3.1.23.orig/src/HttpHeader.cc
+++ squid-3.1.23/src/HttpHeader.cc
@@ -378,12 +378,12 @@ httpHeaderStatInit(HttpHeaderStat * hs,
  * HttpHeader Implementation
  */
 
-HttpHeader::HttpHeader() : owner (hoNone), len (0)
+HttpHeader::HttpHeader() : owner (hoNone), len (0), teUnsupported_(false)
 {
     httpHeaderMaskInit(&mask, 0);
 }
 
-HttpHeader::HttpHeader(http_hdr_owner_type const &anOwner) : owner (anOwner), len (0)
+HttpHeader::HttpHeader(http_hdr_owner_type const &anOwner) : owner (anOwner), len (0), teUnsupported_(false)
 {
     assert(anOwner > hoNone && anOwner <= hoReply);
     debugs(55, 7, "init-ing hdr: " << this << " owner: " << owner);
@@ -628,9 +628,20 @@ HttpHeader::parse(const char *header_sta
                Raw("header", header_start, header_end - header_start));
     }
 
-    if (chunked()) {
+    if (has(HDR_TRANSFER_ENCODING)) {
+        const String rawTe = getStrOrList(HDR_TRANSFER_ENCODING);
         // RFC 2616 section 4.4: ignore Content-Length with Transfer-Encoding
         delById(HDR_CONTENT_LENGTH);
+
+        if (rawTe == "chunked") {
+            ; // leave header present for chunked() method
+        } else if (rawTe == "identity") { // deprecated. no coding
+            delById(HDR_TRANSFER_ENCODING);
+        } else {
+            // This also rejects multiple encodings until we support them properly.
+            debugs(55, warnOnError, "WARNING: unsupported Transfer-Encoding used by client: " << rawTe);
+            teUnsupported_ = true;
+        }
     } else if (clen.sawBad) {
         // ensure our callers do not accidentally see bad Content-Length values
         delById(HDR_CONTENT_LENGTH);
Index: squid-3.1.23/src/HttpHeader.h
===================================================================
--- squid-3.1.23.orig/src/HttpHeader.h
+++ squid-3.1.23/src/HttpHeader.h
@@ -206,7 +206,7 @@ class HttpHeader
 
 public:
     HttpHeader();
-    HttpHeader(http_hdr_owner_type const &owner);
+    explicit HttpHeader(http_hdr_owner_type const &owner);
     ~HttpHeader();
     /* Interface functions */
     void clean();
@@ -258,7 +258,13 @@ 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
+
+    /// whether the message uses chunked Transfer-Encoding
+    /// optimized implementation relies on us rejecting/removing other codings
+    bool chunked() const { return has(HDR_TRANSFER_ENCODING); }
+
+    /// whether message used an unsupported and/or invalid Transfer-Encoding
+    bool unsupportedTe() const { return teUnsupported_; }
 
     /* protected, do not use these, use interface functions instead */
     Vector<HttpHeaderEntry *> entries;		/**< parsed fields in raw format */
@@ -272,10 +278,16 @@ protected:
 
 private:
     HttpHeaderEntry *findLastEntry(http_hdr_type id) const;
+
+    // "deleted"
     /// Made it non-copyable. Our destructor is a bit nasty...
     HttpHeader(const HttpHeader &);
     //assignment is used by the reset method, can't block it..
     //const HttpHeader operator=(const HttpHeader &);
+
+    /// unsupported encoding, unnecessary syntax characters, and/or
+    /// invalid field-value found in Transfer-Encoding header
+    bool teUnsupported_;
 };
 
 
@@ -286,11 +298,4 @@ int httpMsgIsPersistent(HttpVersion cons
 
 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 */
Index: squid-3.1.23/src/client_side.cc
===================================================================
--- squid-3.1.23.orig/src/client_side.cc
+++ squid-3.1.23/src/client_side.cc
@@ -2531,7 +2531,7 @@ clientProcessRequest(ConnStateData *conn
 
     mustReplyToOptions = (method == METHOD_OPTIONS) &&
                          (request->header.getInt64(HDR_MAX_FORWARDS) == 0);
-    unsupportedTe = tePresent && !deChunked;
+    unsupportedTe = request->header.unsupportedTe();
     if (!urlCheckRequest(request) || mustReplyToOptions || unsupportedTe) {
         clientStreamNode *node = context->getClientReplyContext();
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
Index: squid-3.1.23/src/http.cc
===================================================================
--- squid-3.1.23.orig/src/http.cc
+++ squid-3.1.23/src/http.cc
@@ -1193,6 +1193,9 @@ HttpStateData::continueAfterParsingHeade
             } else if (s == HTTP_HEADER_TOO_LARGE) {
                 fwd->dontRetry(true);
                 error = ERR_TOO_BIG;
+            } else if (vrep->header.unsupportedTe()) {
+                fwd->dontRetry(true);
+                error = ERR_INVALID_RESP;
             } else {
                 return true; // done parsing, got reply, and no error
             }
