]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
HTTP/1.1: handle syntactically valid requests with unsupported HTTP versions
authorEduard Bagdasaryan <eduard.bagdasaryan@measurement-factory.com>
Tue, 4 Oct 2016 14:25:15 +0000 (03:25 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 4 Oct 2016 14:25:15 +0000 (03:25 +1300)
Before this change, when a syntactically valid HTTP/1 request indicated
HTTP major version 2, Squid mangled and forwarded the request as an
HTTP/1 message. Since Squid does not and cannot correctly interpret an
HTTP/1 request using HTTP/2 rules, returning an error and closing the
connection appears to be the only correct action possible.

If a version label matches the "HTTP/" 1*DIGIT "." 1*DIGIT pattern from
RFC 2616 it should not be handled as 0.9 syntax. All unacceptible
versions that begin with "HTTP/" should get a 505.

To be compliant with RFC 7230 as well:

- versions 1.2 thru 1.9 accept and handle normally. That is a SHOULD
  requirement in RFC 7230 section 2.6 final paragraph.

- other single-digit versions should get the 505 error.

 - versions with multiple digits should get the 505 error.

src/http/one/RequestParser.cc

index 19dd0286465ef99a6ecd34f5266a3586ec1d85bb..cd8955f0a519ab1ffdbe53015b0734a9f10bfd35 100644 (file)
@@ -185,14 +185,36 @@ Http::One::RequestParser::parseUriField(Http1::Tokenizer &tok)
 bool
 Http::One::RequestParser::parseHttpVersionField(Http1::Tokenizer &tok)
 {
+    static const SBuf http1p0("HTTP/1.0");
+    static const SBuf http1p1("HTTP/1.1");
     const auto savedTok = tok;
 
-    SBuf digit;
-    // Searching for Http1magic precludes detecting HTTP/2+ versions.
-    // Rewrite if we ever _need_ to return 505 (Version Not Supported) errors.
-    if (tok.suffix(digit, CharacterSet::DIGIT) && tok.skipSuffix(Http1magic)) {
-        msgProtocol_ = Http::ProtocolVersion(1, (*digit.rawContent() - '0'));
+    // Optimization: Expect (and quickly parse) HTTP/1.1 or HTTP/1.0 in
+    // the vast majority of cases.
+    if (tok.skipSuffix(http1p1)) {
+        msgProtocol_ = Http::ProtocolVersion(1, 1);
         return true;
+    } else if (tok.skipSuffix(http1p0)) {
+        msgProtocol_ = Http::ProtocolVersion(1, 0);
+        return true;
+    } else {
+        // RFC 7230 section 2.6:
+        // HTTP-version  = HTTP-name "/" DIGIT "." DIGIT
+        static const CharacterSet period("Decimal point", ".");
+        static const SBuf proto("HTTP/");
+        SBuf majorDigit;
+        SBuf minorDigit;
+        if (tok.suffix(minorDigit, CharacterSet::DIGIT) &&
+                tok.skipOneTrailing(period) &&
+                tok.suffix(majorDigit, CharacterSet::DIGIT) &&
+                tok.skipSuffix(proto)) {
+            const bool multiDigits = majorDigit.length() > 1 || minorDigit.length() > 1;
+            // use '0.0' for unsupported multiple digit version numbers
+            const unsigned int major = multiDigits ? 0 : (*majorDigit.rawContent() - '0');
+            const unsigned int minor = multiDigits ? 0 : (*minorDigit.rawContent() - '0');
+            msgProtocol_ = Http::ProtocolVersion(major, minor);
+            return true;
+        }
     }
 
     // A GET request might use HTTP/0.9 syntax