]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 4551: fix exceptions in new chunked decoder
authorAmos Jeffries <squid3@treenet.co.nz>
Tue, 2 Aug 2016 15:06:37 +0000 (03:06 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 2 Aug 2016 15:06:37 +0000 (03:06 +1200)
... fixing incremental CRLF parsing in both chunked encoding and
status-line parsing contexts.

src/http/one/Parser.cc
src/http/one/Parser.h
src/http/one/ResponseParser.cc
src/http/one/TeChunkedParser.cc

index 1eb1ea46b882feb37edc055f06e6bbed4622764c..625f788545109cfddfb7fe173c6bae242e792170 100644 (file)
@@ -64,7 +64,11 @@ Http::One::Parser::skipLineTerminator(Http1::Tokenizer &tok) const
     if (Config.onoff.relaxed_header_parser && tok.skipOne(CharacterSet::LF))
         return true;
 
-    return false;
+    if (tok.atEnd() || (tok.remaining().length() == 1 && tok.remaining().at(0) == '\r'))
+        return false; // need more data
+
+    throw TexcHere("garbage instead of CRLF line terminator");
+    return false; // unreachable, but make naive compilers happy
 }
 
 /// all characters except the LF line terminator
index d24c8c503ffece5bb292701e5ff03196b1752e75..b1e819a945ed9f1d5d5bc242c99a552e5a5a84ec 100644 (file)
@@ -107,8 +107,14 @@ public:
     Http::StatusCode parseStatusCode;
 
 protected:
-    /// detect and skip the CRLF or (if tolerant) LF line terminator
-    /// consume from the tokenizer and return true only if found
+    /**
+     * detect and skip the CRLF or (if tolerant) LF line terminator
+     * consume from the tokenizer.
+     *
+     * throws if non-terminator is detected.
+     * \retval true only if line terminator found.
+     * \retval false incomplete or missing line terminator, need more data.
+     */
     bool skipLineTerminator(Http1::Tokenizer &tok) const;
 
     /// the characters which are to be considered valid whitespace
index 7cdbf493cd2fc30700e76a391d45c5b67bdbb840..007cfaf72c0e6a681bff5fd631e42d8bdf7feb3c 100644 (file)
@@ -75,9 +75,6 @@ Http::One::ResponseParser::parseResponseStatusAndReason(Http1::Tokenizer &tok, c
         // NOTE: any whitespace after the single SP is part of the reason phrase.
     }
 
-    if (tok.atEnd())
-        return 0; // need more to be sure we have it all
-
     /* RFC 7230 says we SHOULD ignore the reason phrase content
      * but it has a definite valid vs invalid character set.
      * We interpret the SHOULD as ignoring absence and syntax, but
@@ -89,17 +86,18 @@ Http::One::ResponseParser::parseResponseStatusAndReason(Http1::Tokenizer &tok, c
     // if we got here we are still looking for reason-phrase bytes
     static const CharacterSet phraseChars = CharacterSet::WSP + CharacterSet::VCHAR + CharacterSet::OBSTEXT;
     (void)tok.prefix(reasonPhrase_, phraseChars); // optional, no error if missing
-    if (skipLineTerminator(tok)) {
-        debugs(74, DBG_DATA, "parse remaining buf={length=" << tok.remaining().length() << ", data='" << tok.remaining() << "'}");
-        buf_ = tok.remaining(); // resume checkpoint
-        return 1;
-    }
-    reasonPhrase_.clear();
-
-    if (tok.atEnd())
+    try {
+        if (skipLineTerminator(tok)) {
+            debugs(74, DBG_DATA, "parse remaining buf={length=" << tok.remaining().length() << ", data='" << tok.remaining() << "'}");
+            buf_ = tok.remaining(); // resume checkpoint
+            return 1;
+        }
+        reasonPhrase_.clear();
         return 0; // need more to be sure we have it all
 
-    debugs(74, 6, "invalid status-line. garbage in reason phrase.");
+    } catch (const std::exception &ex) {
+        debugs(74, 6, "invalid status-line: " << ex.what());
+    }
     return -1;
 }
 
index a247097689b91880374e4e934e5d95d1b0cbf55b..1bcaee5006766c269f130cf32cf361b4ec06fad5 100644 (file)
@@ -153,9 +153,6 @@ Http::One::TeChunkedParser::parseChunkExtension(Http1::Tokenizer &tok, bool skip
             buf_ = tok.remaining(); // parse checkpoint (unless there might be more token name)
     }
 
-    if (tok.atEnd())
-        return false;
-
     if (skipLineTerminator(tok)) {
         buf_ = tok.remaining(); // checkpoint
         // non-0 chunk means data, 0-size means optional Trailer follows
@@ -163,7 +160,6 @@ Http::One::TeChunkedParser::parseChunkExtension(Http1::Tokenizer &tok, bool skip
         return true;
     }
 
-    throw TexcHere("corrupted chunk extension value");
     return false;
 }
 
@@ -202,9 +198,6 @@ Http::One::TeChunkedParser::parseChunkEnd(Http1::Tokenizer &tok)
         theChunkSize = 0; // done with the current chunk
         parsingStage_ = Http1::HTTP_PARSE_CHUNK_SZ;
         return true;
-
-    } else if (!tok.atEnd()) {
-        throw TexcHere("found data between chunk end and CRLF");
     }
 
     return false;