]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Update HTTP-version parsing with RFC 7230 octet magics
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 1 Jun 2014 11:53:02 +0000 (04:53 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 1 Jun 2014 11:53:02 +0000 (04:53 -0700)
RFC 7230 replaces RFC 2616 and defines HTTP-version for HTTP/1 protocol
as having exact case-sensitive octets "HTTP/1." and a variable minor
version consisting of exactly one DIGIT.

This allows us to use magic-octet matching to detect the HTTP-version
field and remove slow matching logics for unknown version and HTTP major
version number (DIGIT '1').

src/http/one/Parser.cc
src/http/one/Parser.h
src/http/one/RequestParser.cc
src/tests/testHttp1Parser.cc

index c6b406a5b96ca1d421a365ea0c5632cb95d3853d..5d39c490895dd770ee4342490dc26b42138b81e1 100644 (file)
@@ -2,6 +2,9 @@
 #include "Debug.h"
 #include "http/one/Parser.h"
 
+/// RFC 7230 section 2.6 - 7 magic octets
+const SBuf Http::One::Parser::Http1magic("HTTP/1.");
+
 void
 Http::One::Parser::clear()
 {
index aacb0def387f13f01aaae65cd660bb9bea2410ab..9b9717853fcf3af295f573dd03bd7ef76ffc1ae8 100644 (file)
@@ -72,6 +72,9 @@ public:
     char *getHeaderField(const char *name);
 
 public:
+    /// RFC 7230 section 2.6 - 7 magic octets
+    static const SBuf Http1magic;
+
     SBuf buf;
 
 protected:
index e446a16c603181e033d186a5706b30dd9a7a0262..7640dd26b8996c88a2aa26f41681640f52904ff4 100644 (file)
@@ -80,6 +80,7 @@ Http::One::RequestParser::skipGarbageLines()
  * Governed by:
  *  RFC 1945 section 5.1
  *  RFC 2616 section 5.1
+ *  RFC 7230
  *
  * Parsing state is stored between calls. However the current implementation
  * begins parsing from scratch on every call.
@@ -240,48 +241,18 @@ Http::One::RequestParser::parseRequestFirstLine()
     req.v_start = last_whitespace + 1;
     req.v_end = line_end;
 
-    // We only accept HTTP protocol requests right now.
-    // TODO: accept other protocols; RFC 2326 (RTSP protocol) etc
-    if ((req.v_end - req.v_start +1) < 5 || buf.substr(req.v_start, 5).caseCmp(SBuf("HTTP/")) != 0) {
-#if USE_HTTP_VIOLATIONS
-        // being lax; old parser accepted strange versions
-        // there is a LOT of cases which are ambiguous, therefore we cannot use relaxed_header_parser here.
-        msgProtocol_ = Http::ProtocolVersion(0,9);
-        req.u_end = line_end;
-        request_parse_status = Http::scOkay; // treat as HTTP/0.9
-        return 1;
-#else
-        // protocol not supported / implemented.
+    /* RFC 2616 section 10.5.6 : handle unsupported HTTP major versions cleanly. */
+    if ((req.v_end - req.v_start +1) < (int)Http1magic.length() || !buf.substr(req.v_start, SBuf::npos).startsWith(Http1magic)) {
+        // non-HTTP/1 protocols not supported / implemented.
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
-#endif
     }
+    // NP: magic octets include the protocol name and major version DIGIT.
     msgProtocol_.protocol = AnyP::PROTO_HTTP;
+    msgProtocol_.major = 1;
 
-    int i = req.v_start + sizeof("HTTP/") -1;
+    int i = req.v_start + Http1magic.length() -1;
 
-    /* next should be 1 or more digits */
-    if (!isdigit(buf[i])) {
-        request_parse_status = Http::scHttpVersionNotSupported;
-        return -1;
-    }
-    int maj = 0;
-    for (; i <= line_end && (isdigit(buf[i])) && maj < 65536; ++i) {
-        maj = maj * 10;
-        maj = maj + (buf[i]) - '0';
-    }
-    // catch too-big values or missing remainders
-    if (maj >= 65536 || i > line_end) {
-        request_parse_status = Http::scHttpVersionNotSupported;
-        return -1;
-    }
-    msgProtocol_.major = maj;
-
-    /* next should be .; we -have- to have this as we have a whole line.. */
-    if (buf[i] != '.') {
-        request_parse_status = Http::scHttpVersionNotSupported;
-        return -1;
-    }
     // catch missing minor part
     if (++i > line_end) {
         request_parse_status = Http::scHttpVersionNotSupported;
@@ -304,13 +275,6 @@ Http::One::RequestParser::parseRequestFirstLine()
     }
     msgProtocol_.minor = min;
 
-    /* RFC 2616 section 10.5.6 : handle unsupported HTTP major versions cleanly. */
-    /* We currently only support 0.9, 1.0, 1.1 properly in this parser */
-    if ((maj == 0 && min != 9) || (maj > 1)) {
-        request_parse_status = Http::scHttpVersionNotSupported;
-        return -1;
-    }
-
     /*
      * Rightio - we have all the schtuff. Return true; we've got enough.
      */
index b5127866ac01b2b60da7325b7762f36f80618ff9..d93075672e3af2d386915a035b162eb0c5b8c720 100644 (file)
@@ -221,10 +221,8 @@ testHttp1Parser::testParseRequestLineProtocols()
         input.clear();
     }
 
-    // RFC 2616 : future version full-request
+    // RFC 7230 : future versions do not use request-line syntax
     {
-        // IETF HTTPbis WG has made this two-digits format invalid.
-        // it gets treated same as HTTP/0.9 for now
         input.append("GET / HTTP/10.12\r\n", 18);
         struct resultSet expect = {
             .parsed = false,
@@ -242,7 +240,7 @@ testHttp1Parser::testParseRequestLineProtocols()
             .uri = "/",
             .versionStart = 6,
             .versionEnd = 15,
-            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,10,12)
+            .version = AnyP::ProtocolVersion()
         };
         output.clear();
         testResults(__LINE__, input, output, expect);
@@ -251,8 +249,6 @@ testHttp1Parser::testParseRequestLineProtocols()
 
     // unknown non-HTTP protocol names
     {
-        // XXX: violations mode treats them as HTTP/0.9 requests! which is wrong.
-#if !USE_HTTP_VIOLATIONS
         input.append("GET / FOO/1.0\n", 14);
         struct resultSet expect = {
             .parsed = false,
@@ -275,7 +271,6 @@ testHttp1Parser::testParseRequestLineProtocols()
         output.clear();
         testResults(__LINE__, input, output, expect);
         input.clear();
-#endif
     }
 
     // no version
@@ -297,7 +292,7 @@ testHttp1Parser::testParseRequestLineProtocols()
             .uri = "/",
             .versionStart = 6,
             .versionEnd = 10,
-            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0)
+            .version = AnyP::ProtocolVersion()
         };
         output.clear();
         testResults(__LINE__, input, output, expect);
@@ -323,7 +318,7 @@ testHttp1Parser::testParseRequestLineProtocols()
             .uri = "/",
             .versionStart = 6,
             .versionEnd = 12,
-            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0)
+            .version = AnyP::ProtocolVersion()
         };
         output.clear();
         testResults(__LINE__, input, output, expect);
@@ -349,7 +344,7 @@ testHttp1Parser::testParseRequestLineProtocols()
             .uri = "/",
             .versionStart = 6,
             .versionEnd = 12,
-            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0)
+            .version = AnyP::ProtocolVersion()
         };
         output.clear();
         testResults(__LINE__, input, output, expect);
@@ -375,7 +370,7 @@ testHttp1Parser::testParseRequestLineProtocols()
             .uri = "/",
             .versionStart = 6,
             .versionEnd = 19,
-            .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0)
+            .version = AnyP::ProtocolVersion()
         };
         output.clear();
         testResults(__LINE__, input, output, expect);