]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
SourceLayout: separate HttpParser from HttpMsg and HttpRequest files
authorAmos Jeffries <squid3@treenet.co.nz>
Fri, 27 May 2011 13:56:42 +0000 (07:56 -0600)
committerAmos Jeffries <squid3@treenet.co.nz>
Fri, 27 May 2011 13:56:42 +0000 (07:56 -0600)
Paving the way for the parser to be used on replies or outside of HttpRequest.

There are no logic changes in this.

Also adds a stub file for event.cc

src/HttpMsg.cc
src/HttpMsg.h
src/HttpParser.cc [new file with mode: 0644]
src/HttpParser.h [new file with mode: 0644]
src/Makefile.am
src/client_side.h
src/tests/stub_event.cc [new file with mode: 0644]
src/tests/testHttpParser.cc [new file with mode: 0644]
src/tests/testHttpParser.h [new file with mode: 0644]
src/tests/testHttpRequest.cc
src/tests/testHttpRequest.h

index 874a1a3221db9884bcb27eb5b14b7b167124c82a..bd0e7a63d119a2f41515b9ee63f8b8fbbc39916e 100644 (file)
@@ -374,299 +374,3 @@ HttpMsg::_unlock()
     if (0 == lock_count)
         delete this;
 }
-
-
-void
-HttpParserInit(HttpParser *hdr, const char *buf, int bufsiz)
-{
-    hdr->clear();
-    hdr->state = 1;
-    hdr->buf = buf;
-    hdr->bufsiz = bufsiz;
-    debugs(74, 5, "httpParseInit: Request buffer is " << buf);
-}
-
-#if MSGDODEBUG
-/* XXX This should eventually turn into something inlined or #define'd */
-int
-HttpParserReqSz(HttpParser *hp)
-{
-    assert(hp->state == 1);
-    assert(hp->req_start != -1);
-    assert(hp->req_end != -1);
-    return hp->req_end - hp->req_start + 1;
-}
-
-
-/*
- * This +1 makes it 'right' but won't make any sense if
- * there's a 0 byte header? This won't happen normally - a valid header
- * is at -least- a blank line (\n, or \r\n.)
- */
-int
-HttpParserHdrSz(HttpParser *hp)
-{
-    assert(hp->state == 1);
-    assert(hp->hdr_start != -1);
-    assert(hp->hdr_end != -1);
-    return hp->hdr_end - hp->hdr_start + 1;
-}
-
-const char *
-HttpParserHdrBuf(HttpParser *hp)
-{
-    assert(hp->state == 1);
-    assert(hp->hdr_start != -1);
-    assert(hp->hdr_end != -1);
-    return hp->buf + hp->hdr_start;
-}
-
-int
-HttpParserRequestLen(HttpParser *hp)
-{
-    return hp->hdr_end - hp->req_start + 1;
-}
-#endif
-
-HttpParser::HttpParser(const char *buf, int len)
-{
-    HttpParserInit(this, buf, len);
-}
-
-void
-HttpParser::clear()
-{
-    state = 0;
-    request_parse_status = HTTP_STATUS_NONE;
-    buf = NULL; // NP: we do not own the buffer, merely reference to it.
-    bufsiz = 0;
-    req_start = req_end = -1;
-    hdr_start = hdr_end = -1;
-    m_start = m_end = -1;
-    u_start = u_end = -1;
-    v_start = v_end = -1;
-    v_maj = v_min = 0;
-}
-
-int
-HttpParser::parseRequestFirstLine()
-{
-    int second_word = -1; // track the suspected URI start
-    int first_whitespace = -1, last_whitespace = -1; // track the first and last SP byte
-    int line_end = -1; // tracks the last byte BEFORE terminal \r\n or \n sequence
-
-    debugs(74, 5, HERE << "parsing possible request: " << buf);
-
-    // Single-pass parse: (provided we have the whole line anyways)
-
-    req_start = 0;
-    if (Config.onoff.relaxed_header_parser) {
-        if (Config.onoff.relaxed_header_parser < 0 && buf[req_start] == ' ')
-            debugs(74, DBG_IMPORTANT, "WARNING: Invalid HTTP Request: " <<
-                   "Whitespace bytes received ahead of method. " <<
-                   "Ignored due to relaxed_header_parser.");
-        // Be tolerant of prefix spaces (other bytes are valid method values)
-        for (; req_start < bufsiz && buf[req_start] == ' '; req_start++);
-    }
-    req_end = -1;
-    for (int i = 0; i < bufsiz; i++) {
-        // track first and last whitespace (SP only)
-        if (buf[i] == ' ') {
-            last_whitespace = i;
-            if (first_whitespace < req_start)
-                first_whitespace = i;
-        }
-
-        // track next non-SP/non-HT byte after first_whitespace
-        if (second_word < first_whitespace && buf[i] != ' ' && buf[i] != '\t') {
-            second_word = i;
-        }
-
-        // locate line terminator
-        if (buf[i] == '\n') {
-            req_end = i;
-            line_end = i - 1;
-            break;
-        }
-        if (i < bufsiz - 1 && buf[i] == '\r') {
-            if (Config.onoff.relaxed_header_parser) {
-                if (Config.onoff.relaxed_header_parser < 0 && buf[i + 1] == '\r')
-                    debugs(74, DBG_IMPORTANT, "WARNING: Invalid HTTP Request: " <<
-                           "Series of carriage-return bytes received prior to line terminator. " <<
-                           "Ignored due to relaxed_header_parser.");
-
-                // Be tolerant of invalid multiple \r prior to terminal \n
-                if (buf[i + 1] == '\n' || buf[i + 1] == '\r')
-                    line_end = i - 1;
-                while (i < bufsiz - 1 && buf[i + 1] == '\r')
-                    i++;
-
-                if (buf[i + 1] == '\n') {
-                    req_end = i + 1;
-                    break;
-                }
-            } else {
-                if (buf[i + 1] == '\n') {
-                    req_end = i + 1;
-                    line_end = i - 1;
-                    break;
-                }
-            }
-
-            // RFC 2616 section 5.1
-            // "No CR or LF is allowed except in the final CRLF sequence"
-            request_parse_status = HTTP_BAD_REQUEST;
-            return -1;
-        }
-    }
-    if (req_end == -1) {
-        debugs(74, 5, "Parser: retval 0: from " << req_start <<
-               "->" << req_end << ": needs more data to complete first line.");
-        return 0;
-    }
-
-    // NP: we have now seen EOL, more-data (0) cannot occur.
-    //     From here on any failure is -1, success is 1
-
-
-    // Input Validation:
-
-    // Process what we now know about the line structure into field offsets
-    // generating HTTP status for any aborts as we go.
-
-    // First non-whitespace = beginning of method
-    if (req_start > line_end) {
-        request_parse_status = HTTP_BAD_REQUEST;
-        return -1;
-    }
-    m_start = req_start;
-
-    // First whitespace = end of method
-    if (first_whitespace > line_end || first_whitespace < req_start) {
-        request_parse_status = HTTP_BAD_REQUEST; // no method
-        return -1;
-    }
-    m_end = first_whitespace - 1;
-    if (m_end < m_start) {
-        request_parse_status = HTTP_BAD_REQUEST; // missing URI?
-        return -1;
-    }
-
-    // First non-whitespace after first SP = beginning of URL+Version
-    if (second_word > line_end || second_word < req_start) {
-        request_parse_status = HTTP_BAD_REQUEST; // missing URI
-        return -1;
-    }
-    u_start = second_word;
-
-    // RFC 1945: SP and version following URI are optional, marking version 0.9
-    // we identify this by the last whitespace being earlier than URI start
-    if (last_whitespace < second_word && last_whitespace >= req_start) {
-        v_maj = 0;
-        v_min = 9;
-        u_end = line_end;
-        request_parse_status = HTTP_OK; // HTTP/0.9
-        return 1;
-    } else {
-        // otherwise last whitespace is somewhere after end of URI.
-        u_end = last_whitespace;
-        // crop any trailing whitespace in the area we think of as URI
-        for (; u_end >= u_start && xisspace(buf[u_end]); u_end--);
-    }
-    if (u_end < u_start) {
-        request_parse_status = HTTP_BAD_REQUEST; // missing URI
-        return -1;
-    }
-
-    // Last whitespace SP = before start of protocol/version
-    if (last_whitespace >= line_end) {
-        request_parse_status = HTTP_BAD_REQUEST; // missing version
-        return -1;
-    }
-    v_start = last_whitespace + 1;
-    v_end = line_end;
-
-    // We only accept HTTP protocol requests right now.
-    // TODO: accept other protocols; RFC 2326 (RTSP protocol) etc
-    if ((v_end - v_start +1) < 5 || strncasecmp(&buf[v_start], "HTTP/", 5) != 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.
-        v_maj = 0;
-        v_min = 9;
-        u_end = line_end;
-        request_parse_status = HTTP_OK; // treat as HTTP/0.9
-        return 1;
-#else
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED; // protocol not supported / implemented.
-        return -1;
-#endif
-    }
-
-    int i = v_start + sizeof("HTTP/") -1;
-
-    /* next should be 1 or more digits */
-    if (!isdigit(buf[i])) {
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
-        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_HTTP_VERSION_NOT_SUPPORTED;
-        return -1;
-    }
-    v_maj = maj;
-
-    /* next should be .; we -have- to have this as we have a whole line.. */
-    if (buf[i] != '.') {
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
-        return -1;
-    }
-    // catch missing minor part
-    if (++i > line_end) {
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
-        return -1;
-    }
-
-    /* next should be one or more digits */
-    if (!isdigit(buf[i])) {
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
-        return -1;
-    }
-    int min = 0;
-    for (; i <= line_end && (isdigit(buf[i])) && min < 65536; i++) {
-        min = min * 10;
-        min = min + (buf[i]) - '0';
-    }
-    // catch too-big values or trailing garbage
-    if (min >= 65536 || i < line_end) {
-        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
-        return -1;
-    }
-    v_min = min;
-
-    /*
-     * Rightio - we have all the schtuff. Return true; we've got enough.
-     */
-    request_parse_status = HTTP_OK;
-    return 1;
-}
-
-int
-HttpParserParseReqLine(HttpParser *hmsg)
-{
-    PROF_start(HttpParserParseReqLine);
-    int retcode = hmsg->parseRequestFirstLine();
-    debugs(74, 5, "Parser: retval " << retcode << ": from " << hmsg->req_start <<
-           "->" << hmsg->req_end << ": method " << hmsg->m_start << "->" <<
-           hmsg->m_end << "; url " << hmsg->u_start << "->" << hmsg->u_end <<
-           "; version " << hmsg->v_start << "->" << hmsg->v_end << " (" << hmsg->v_maj <<
-           "/" << hmsg->v_min << ")");
-    PROF_stop(HttpParserParseReqLine);
-    return retcode;
-}
index 37f1307f0fb01fcf9e9ef9e72601819ff6f38c35..6020014a145f282dfe68ff3a14b21690fb9e6164 100644 (file)
@@ -132,67 +132,6 @@ protected:
 
 };
 
-/* Temporary parsing state; might turn into the replacement parser later on */
-class HttpParser
-{
-public:
-    HttpParser() { clear(); }
-    HttpParser(const char *buf, int len);
-
-    /// Set this parser back to a default state.
-    /// Will DROP any reference to a buffer (does not free).
-    void clear();
-
-    /**
-     * Attempt to parse the first line of a new request message.
-     *
-     * Governed by:
-     *  RFC 1945 section 5.1
-     *  RFC 2616 section 5.1
-     *
-     * Parsing state is stored between calls. However the current implementation
-     * begins parsing from scratch on every call.
-     * The return value tells you whether the parsing state fields are valid or not.
-     *
-     * \retval -1  an error occurred. request_parse_status indicates HTTP status result.
-     * \retval  1  successful parse
-     * \retval  0  more data is needed to complete the parse
-     */
-    int parseRequestFirstLine();
-
-public:
-    char state;
-    const char *buf;
-    int bufsiz;
-    int req_start, req_end;
-    int hdr_start, hdr_end;
-    int m_start, m_end;
-    int u_start, u_end;
-    int v_start, v_end;
-    int v_maj, v_min;
-
-    /** HTTP status code to be used on the invalid-request error page
-     * HTTP_STATUS_NONE indicates incomplete parse, HTTP_OK indicates no error.
-     */
-    http_status request_parse_status;
-};
-
-extern void HttpParserInit(HttpParser *, const char *buf, int len);
-extern int HttpParserParseReqLine(HttpParser *hp);
-
-#define MSGDODEBUG 0
-#if MSGDODEBUG
-extern int HttpParserReqSz(HttpParser *);
-extern int HttpParserHdrSz(HttpParser *);
-extern const char * HttpParserHdrBuf(HttpParser *);
-extern int HttpParserRequestLen(HttpParser *hp);
-#else
-#define        HttpParserReqSz(hp)     ( (hp)->req_end - (hp)->req_start + 1 )
-#define        HttpParserHdrSz(hp)     ( (hp)->hdr_end - (hp)->hdr_start + 1 )
-#define        HttpParserHdrBuf(hp)    ( (hp)->buf + (hp)->hdr_start )
-#define        HttpParserRequestLen(hp)        ( (hp)->hdr_end - (hp)->req_start + 1 )
-#endif
-
 SQUIDCEXTERN int httpMsgIsolateHeaders(const char **parse_start, int len, const char **blk_start, const char **blk_end);
 
 #define HTTPMSGUNLOCK(a) if(a){(a)->_unlock();(a)=NULL;}
diff --git a/src/HttpParser.cc b/src/HttpParser.cc
new file mode 100644 (file)
index 0000000..050c8c9
--- /dev/null
@@ -0,0 +1,293 @@
+#include "config.h"
+#include "Debug.h"
+#include "HttpParser.h"
+#include "structs.h"
+
+void
+HttpParser::clear()
+{
+    state = HTTP_PARSE_NONE;
+    request_parse_status = HTTP_STATUS_NONE;
+    buf = NULL;
+    bufsiz = 0;
+    req_start = req_end = -1;
+    hdr_start = hdr_end = -1;
+    m_start = m_end = -1;
+    u_start = u_end = -1;
+    v_start = v_end = -1;
+    v_maj = v_min = 0;
+}
+
+void
+HttpParser::reset(const char *aBuf, int len)
+{
+    clear(); // empty the state.
+    state = HTTP_PARSE_NEW;
+    buf = aBuf;
+    bufsiz = len;
+    debugs(74, 5, HERE << "Request buffer is " << buf);
+}
+
+int
+HttpParser::parseRequestFirstLine()
+{
+    int second_word = -1; // track the suspected URI start
+    int first_whitespace = -1, last_whitespace = -1; // track the first and last SP byte
+    int line_end = -1; // tracks the last byte BEFORE terminal \r\n or \n sequence
+
+    debugs(74, 5, HERE << "parsing possible request: " << buf);
+
+    // Single-pass parse: (provided we have the whole line anyways)
+
+    req_start = 0;
+    if (Config.onoff.relaxed_header_parser) {
+        if (Config.onoff.relaxed_header_parser < 0 && buf[req_start] == ' ')
+            debugs(74, DBG_IMPORTANT, "WARNING: Invalid HTTP Request: " <<
+                   "Whitespace bytes received ahead of method. " <<
+                   "Ignored due to relaxed_header_parser.");
+        // Be tolerant of prefix spaces (other bytes are valid method values)
+        for (; req_start < bufsiz && buf[req_start] == ' '; req_start++);
+    }
+    req_end = -1;
+    for (int i = 0; i < bufsiz; i++) {
+        // track first and last whitespace (SP only)
+        if (buf[i] == ' ') {
+            last_whitespace = i;
+            if (first_whitespace < req_start)
+                first_whitespace = i;
+        }
+
+        // track next non-SP/non-HT byte after first_whitespace
+        if (second_word < first_whitespace && buf[i] != ' ' && buf[i] != '\t') {
+            second_word = i;
+        }
+
+        // locate line terminator
+        if (buf[i] == '\n') {
+            req_end = i;
+            line_end = i - 1;
+            break;
+        }
+        if (i < bufsiz - 1 && buf[i] == '\r') {
+            if (Config.onoff.relaxed_header_parser) {
+                if (Config.onoff.relaxed_header_parser < 0 && buf[i + 1] == '\r')
+                    debugs(74, DBG_IMPORTANT, "WARNING: Invalid HTTP Request: " <<
+                           "Series of carriage-return bytes received prior to line terminator. " <<
+                           "Ignored due to relaxed_header_parser.");
+
+                // Be tolerant of invalid multiple \r prior to terminal \n
+                if (buf[i + 1] == '\n' || buf[i + 1] == '\r')
+                    line_end = i - 1;
+                while (i < bufsiz - 1 && buf[i + 1] == '\r')
+                    i++;
+
+                if (buf[i + 1] == '\n') {
+                    req_end = i + 1;
+                    break;
+                }
+            } else {
+                if (buf[i + 1] == '\n') {
+                    req_end = i + 1;
+                    line_end = i - 1;
+                    break;
+                }
+            }
+
+            // RFC 2616 section 5.1
+            // "No CR or LF is allowed except in the final CRLF sequence"
+            request_parse_status = HTTP_BAD_REQUEST;
+            return -1;
+        }
+    }
+    if (req_end == -1) {
+        debugs(74, 5, "Parser: retval 0: from " << req_start <<
+               "->" << req_end << ": needs more data to complete first line.");
+        return 0;
+    }
+
+    // NP: we have now seen EOL, more-data (0) cannot occur.
+    //     From here on any failure is -1, success is 1
+
+
+    // Input Validation:
+
+    // Process what we now know about the line structure into field offsets
+    // generating HTTP status for any aborts as we go.
+
+    // First non-whitespace = beginning of method
+    if (req_start > line_end) {
+        request_parse_status = HTTP_BAD_REQUEST;
+        return -1;
+    }
+    m_start = req_start;
+
+    // First whitespace = end of method
+    if (first_whitespace > line_end || first_whitespace < req_start) {
+        request_parse_status = HTTP_BAD_REQUEST; // no method
+        return -1;
+    }
+    m_end = first_whitespace - 1;
+    if (m_end < m_start) {
+        request_parse_status = HTTP_BAD_REQUEST; // missing URI?
+        return -1;
+    }
+
+    // First non-whitespace after first SP = beginning of URL+Version
+    if (second_word > line_end || second_word < req_start) {
+        request_parse_status = HTTP_BAD_REQUEST; // missing URI
+        return -1;
+    }
+    u_start = second_word;
+
+    // RFC 1945: SP and version following URI are optional, marking version 0.9
+    // we identify this by the last whitespace being earlier than URI start
+    if (last_whitespace < second_word && last_whitespace >= req_start) {
+        v_maj = 0;
+        v_min = 9;
+        u_end = line_end;
+        request_parse_status = HTTP_OK; // HTTP/0.9
+        return 1;
+    } else {
+        // otherwise last whitespace is somewhere after end of URI.
+        u_end = last_whitespace;
+        // crop any trailing whitespace in the area we think of as URI
+        for (; u_end >= u_start && xisspace(buf[u_end]); u_end--);
+    }
+    if (u_end < u_start) {
+        request_parse_status = HTTP_BAD_REQUEST; // missing URI
+        return -1;
+    }
+
+    // Last whitespace SP = before start of protocol/version
+    if (last_whitespace >= line_end) {
+        request_parse_status = HTTP_BAD_REQUEST; // missing version
+        return -1;
+    }
+    v_start = last_whitespace + 1;
+    v_end = line_end;
+
+    // We only accept HTTP protocol requests right now.
+    // TODO: accept other protocols; RFC 2326 (RTSP protocol) etc
+    if ((v_end - v_start +1) < 5 || strncasecmp(&buf[v_start], "HTTP/", 5) != 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.
+        v_maj = 0;
+        v_min = 9;
+        u_end = line_end;
+        request_parse_status = HTTP_OK; // treat as HTTP/0.9
+        return 1;
+#else
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED; // protocol not supported / implemented.
+        return -1;
+#endif
+    }
+
+    int i = v_start + sizeof("HTTP/") -1;
+
+    /* next should be 1 or more digits */
+    if (!isdigit(buf[i])) {
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
+        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_HTTP_VERSION_NOT_SUPPORTED;
+        return -1;
+    }
+    v_maj = maj;
+
+    /* next should be .; we -have- to have this as we have a whole line.. */
+    if (buf[i] != '.') {
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
+        return -1;
+    }
+    // catch missing minor part
+    if (++i > line_end) {
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
+        return -1;
+    }
+    /* next should be one or more digits */
+    if (!isdigit(buf[i])) {
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
+        return -1;
+    }
+    int min = 0;
+    for (; i <= line_end && (isdigit(buf[i])) && min < 65536; i++) {
+        min = min * 10;
+        min = min + (buf[i]) - '0';
+    }
+    // catch too-big values or trailing garbage
+    if (min >= 65536 || i < line_end) {
+        request_parse_status = HTTP_HTTP_VERSION_NOT_SUPPORTED;
+        return -1;
+    }
+    v_min = min;
+
+    /*
+     * Rightio - we have all the schtuff. Return true; we've got enough.
+     */
+    request_parse_status = HTTP_OK;
+    return 1;
+}
+
+int
+HttpParserParseReqLine(HttpParser *hmsg)
+{
+    PROF_start(HttpParserParseReqLine);
+    int retcode = hmsg->parseRequestFirstLine();
+    debugs(74, 5, "Parser: retval " << retcode << ": from " << hmsg->req_start <<
+           "->" << hmsg->req_end << ": method " << hmsg->m_start << "->" <<
+           hmsg->m_end << "; url " << hmsg->u_start << "->" << hmsg->u_end <<
+           "; version " << hmsg->v_start << "->" << hmsg->v_end << " (" << hmsg->v_maj <<
+           "/" << hmsg->v_min << ")");
+    PROF_stop(HttpParserParseReqLine);
+    return retcode;
+}
+
+#if MSGDODEBUG
+/* XXX This should eventually turn into something inlined or #define'd */
+int
+HttpParserReqSz(HttpParser *hp)
+{
+    assert(hp->state == HTTP_PARSE_NEW);
+    assert(hp->req_start != -1);
+    assert(hp->req_end != -1);
+    return hp->req_end - hp->req_start + 1;
+}
+
+/*
+ * This +1 makes it 'right' but won't make any sense if
+ * there's a 0 byte header? This won't happen normally - a valid header
+ * is at -least- a blank line (\n, or \r\n.)
+ */
+int
+HttpParserHdrSz(HttpParser *hp)
+{
+    assert(hp->state == HTTP_PARSE_NEW);
+    assert(hp->hdr_start != -1);
+    assert(hp->hdr_end != -1);
+    return hp->hdr_end - hp->hdr_start + 1;
+}
+
+const char *
+HttpParserHdrBuf(HttpParser *hp)
+{
+    assert(hp->state == HTTP_PARSE_NEW);
+    assert(hp->hdr_start != -1);
+    assert(hp->hdr_end != -1);
+    return hp->buf + hp->hdr_start;
+}
+
+int
+HttpParserRequestLen(HttpParser *hp)
+{
+    return hp->hdr_end - hp->req_start + 1;
+}
+#endif
+
diff --git a/src/HttpParser.h b/src/HttpParser.h
new file mode 100644 (file)
index 0000000..601f7ac
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef _SQUID_SRC_HTTPPARSER_H
+#define _SQUID_SRC_HTTPPARSER_H
+
+#include "HttpStatusCode.h"
+
+// Parser states
+#define HTTP_PARSE_NONE   0 // nothing. completely unset state.
+#define HTTP_PARSE_NEW    1 // initialized, but nothing usefully parsed yet.
+
+/** HTTP protocol parser.
+ *
+ * Works on a raw character I/O buffer and tokenizes the content into
+ * either an error state or, an HTTP procotol request major segments:
+ *
+ * \item Request Line (method, URL, protocol, version)
+ * \item Mime header block
+ */
+class HttpParser
+{
+public:
+    HttpParser() { clear(); }
+
+    /** Initialize a new parser.
+     * Presenting it a buffer to work on and the current length of available
+     * data.
+     * NOTE: This is *not* the buffer size, just the parse-able data length.
+     * The parse routines may be called again later with more data.
+     */
+    HttpParser(const char *aBuf, int len) { reset(aBuf,len); };
+
+    /// Set this parser back to a default state.
+    /// Will DROP any reference to a buffer (does not free).
+    void clear();
+
+    /// Reset the parser for use on a new buffer.
+    void reset(const char *aBuf, int len);
+
+    /**
+     * Attempt to parse the first line of a new request message.
+     *
+     * Governed by:
+     *  RFC 1945 section 5.1
+     *  RFC 2616 section 5.1
+     *
+     * Parsing state is stored between calls. However the current implementation
+     * begins parsing from scratch on every call.
+     * The return value tells you whether the parsing state fields are valid or not.
+     *
+     * \retval -1  an error occurred. request_parse_status indicates HTTP status result.
+     * \retval  1  successful parse. member fields contain the request-line items
+     * \retval  0  more data is needed to complete the parse
+     */
+    int parseRequestFirstLine();
+
+public:
+    uint8_t state;
+    const char *buf;
+    int bufsiz;
+    int req_start, req_end;
+    int hdr_start, hdr_end;
+    int m_start, m_end;
+    int u_start, u_end;
+    int v_start, v_end;
+    int v_maj, v_min;
+
+    /** HTTP status code to be used on the invalid-request error page
+     * HTTP_STATUS_NONE indicates incomplete parse, HTTP_OK indicates no error.
+     */
+    http_status request_parse_status;
+};
+
+// Legacy functions
+#define HttpParserInit(h,b,l) (h)->reset((b),(l))
+extern int HttpParserParseReqLine(HttpParser *hp);
+
+#define MSGDODEBUG 0
+#if MSGDODEBUG
+extern int HttpParserReqSz(HttpParser *);
+extern int HttpParserHdrSz(HttpParser *);
+extern const char * HttpParserHdrBuf(HttpParser *);
+extern int HttpParserRequestLen(HttpParser *hp);
+#else
+#define HttpParserReqSz(hp)     ( (hp)->req_end - (hp)->req_start + 1 )
+#define HttpParserHdrSz(hp)     ( (hp)->hdr_end - (hp)->hdr_start + 1 )
+#define HttpParserHdrBuf(hp)    ( (hp)->buf + (hp)->hdr_start )
+#define HttpParserRequestLen(hp)        ( (hp)->hdr_end - (hp)->req_start + 1 )
+#endif
+
+
+#endif /*  _SQUID_SRC_HTTPPARSER_H */
index 0118aa90e82d53b11ab7081d1b2a497358907b27..26a672937f44ce18d9ba116668f89439f1436d36 100644 (file)
@@ -361,6 +361,8 @@ squid_SOURCES = \
        HttpControlMsg.h \
        HttpMsg.cc \
        HttpMsg.h \
+       HttpParser.cc \
+       HttpParser.h \
        HttpReply.cc \
        HttpReply.h \
        HttpRequest.cc \
@@ -962,6 +964,7 @@ check_PROGRAMS+=\
        tests/testEvent \
        tests/testEventLoop \
        tests/test_http_range \
+       tests/testHttpParser \
        tests/testHttpReply \
        tests/testHttpRequest \
        tests/testStore \
@@ -1195,6 +1198,8 @@ tests_testBoilerplate_DEPENDENCIES = \
 tests_testCacheManager_SOURCES = \
        $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
+       HttpParser.cc \
+       HttpParser.h \
        HttpRequest.cc \
        HttpRequestMethod.cc \
        mem.cc \
@@ -1550,6 +1555,8 @@ tests_testEvent_SOURCES = \
        HttpHdrSc.cc \
        HttpHdrScTarget.cc \
        HttpMsg.cc \
+       HttpParser.cc \
+       HttpParser.h \
        HttpReply.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
@@ -1725,6 +1732,8 @@ tests_testEventLoop_SOURCES = \
        HttpHdrSc.cc \
        HttpHdrScTarget.cc \
        HttpMsg.cc \
+       HttpParser.cc \
+       HttpParser.h \
        HttpReply.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
@@ -1898,6 +1907,8 @@ tests_test_http_range_SOURCES = \
        HttpHeader.cc \
        HttpHeaderTools.cc \
        HttpMsg.cc \
+       HttpParser.cc \
+       HttpParser.h \
        HttpReply.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
@@ -2011,9 +2022,41 @@ tests_test_http_range_DEPENDENCIES = \
        $(SQUID_CPPUNIT_LA)
 
 
+tests_testHttpParser_SOURCES = \
+       Debug.h \
+       HttpParser.cc \
+       HttpParser.h \
+       MemBuf.cc \
+       MemBuf.h \
+       mem.cc \
+       structs.h \
+       tests/stub_cache_manager.cc \
+       tests/stub_debug.cc \
+       tests/stub_event.cc \
+       tests/stub_HelperChildConfig.cc \
+       tests/testHttpParser.cc \
+       tests/testHttpParser.h \
+       tests/testMain.cc \
+       time.cc
+nodist_tests_testHttpParser_SOURCES = \
+       $(TESTSOURCES)
+tests_testHttpParser_LDADD= \
+       SquidConfig.o \
+       base/libbase.la \
+       ip/libip.la \
+       $(top_builddir)/lib/libmiscutil.la \
+       $(SQUID_CPPUNIT_LIBS) \
+       $(COMPAT_LIB) \
+       $(XTRA_LIBS)
+tests_testHttpParser_LDFLAGS = $(LIBADD_DL)
+tests_testHttpParser_DEPENDENCIES = \
+       $(SQUID_CPPUNIT_LA)
+
 ## Tests of the HttpRequest module.
 tests_testHttpRequest_SOURCES = \
        $(ACL_REGISTRATION_SOURCES) \
+       HttpParser.cc \
+       HttpParser.h \
        HttpRequest.cc \
        HttpRequestMethod.cc \
        mem.cc \
@@ -2790,6 +2833,8 @@ tests_testURL_SOURCES = \
        HttpHeader.cc \
        HttpHeaderTools.cc \
        HttpMsg.cc \
+       HttpParser.cc \
+       HttpParser.h \
        HttpReply.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
index dbc8017aeb42825acbbf411f565532f0ad578ee0..72e7aa7c2cb2ef5e690f5be9b9915908e62fcba6 100644 (file)
@@ -43,6 +43,7 @@
 #include "eui/Eui48.h"
 #include "eui/Eui64.h"
 #include "HttpControlMsg.h"
+#include "HttpParser.h"
 #include "RefCount.h"
 #include "StoreIOBuffer.h"
 
@@ -50,7 +51,6 @@ class ConnStateData;
 class ClientHttpRequest;
 class clientStreamNode;
 class ChunkedCodingParser;
-class HttpParser;
 
 class ClientSocketContext : public RefCountable
 {
diff --git a/src/tests/stub_event.cc b/src/tests/stub_event.cc
new file mode 100644 (file)
index 0000000..defa64d
--- /dev/null
@@ -0,0 +1,30 @@
+#include "config.h"
+#include "event.h"
+
+#define STUB_API "event.cc"
+#include "tests/STUB.h"
+
+void eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata) STUB
+void eventAddIsh(const char *name, EVH * func, void *arg, double delta_ish, int) STUB
+void eventDelete(EVH * func, void *arg) STUB
+void eventInit(void) STUB
+void eventFreeMemory(void) STUB
+int eventFind(EVH *, void *) STUB_RETVAL(-1)
+
+// ev_entry::ev_entry(char const * name, EVH * func, void *arg, double when, int weight, bool cbdata) STUB
+// ev_entry::~ev_entry() STUB
+//    MEMPROXY_CLASS(ev_entry);
+//    EVH *func;
+
+//MEMPROXY_CLASS_INLINE(ev_entry);
+
+EventScheduler::EventScheduler() STUB
+EventScheduler::~EventScheduler() STUB
+void EventScheduler::cancel(EVH * func, void * arg) STUB
+void EventScheduler::clean() STUB
+int EventScheduler::checkDelay() STUB_RETVAL(-1)
+void EventScheduler::dump(StoreEntry *) STUB
+bool EventScheduler::find(EVH * func, void * arg) STUB_RETVAL(false)
+void EventScheduler::schedule(const char *name, EVH * func, void *arg, double when, int weight, bool cbdata) STUB
+int EventScheduler::checkEvents(int timeout) STUB_RETVAL(-1)
+EventScheduler *EventScheduler::GetInstance() STUB_RETVAL(NULL)
diff --git a/src/tests/testHttpParser.cc b/src/tests/testHttpParser.cc
new file mode 100644 (file)
index 0000000..942aa75
--- /dev/null
@@ -0,0 +1,912 @@
+#define SQUID_UNIT_TEST 1
+#include "config.h"
+
+#include <cppunit/TestAssert.h>
+
+#include "testHttpParser.h"
+#include "HttpParser.h"
+#include "Mem.h"
+#include "MemBuf.h"
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( testHttpParser );
+
+void
+testHttpParser::globalSetup()
+{
+    static bool setup_done = false;
+    if (setup_done)
+        return;
+    
+    Mem::Init();
+    setup_done = true;
+}
+
+void
+testHttpParser::testParseRequestLine()
+{
+    // ensure MemPools etc exist
+    globalSetup();
+
+    MemBuf input;
+    HttpParser output;
+    input.init();
+
+    // TEST: Do we comply with RFC 1945 section 5.1 ?
+    // TEST: Do we comply with RFC 2616 section 5.1 ?
+
+    // RFC 1945 : HTTP/0.9 simple-request
+    input.append("GET /\r\n", 7);
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET /\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start], (output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start], (output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+    input.reset();
+
+    // RFC 1945 and 2616 : HTTP/1.0 full-request
+    input.append("GET / HTTP/1.0\r\n", 16);
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.0\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+
+    // RFC 2616 : HTTP/1.1 full-request
+    input.append("GET / HTTP/1.1\r\n", 16);
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // RFC 2616 : future version full-request
+    input.append("GET / HTTP/10.12\r\n", 18);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/10.12\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(15, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/10.12", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(10, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(12, output.v_min);
+    input.reset();
+
+    // space padded URL
+    input.append("GET  /     HTTP/1.1\r\n", 21);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET  /     HTTP/1.1\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(11, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(18, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // space padded version
+    // RFC 1945 and 2616 specify version is followed by CRLF. No intermediary bytes.
+    // NP: the terminal whitespace is a special case: invalid for even HTTP/0.9 with no version tag
+    input.append("GET / HTTP/1.1 \n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1 \n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/ HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // whitespace inside URI. (nasty but happens)
+    input.append("GET /fo o/ HTTP/1.1\n", 20);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET /fo o/ HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(9, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/fo o/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(11, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(18, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // additional data in buffer
+    input.append("GET /     HTTP/1.1\nboo!", 23);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-5, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET /     HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end); // strangeness generated by following RFC
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(10, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(17, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // alternative EOL sequence: NL-only
+    input.append("GET / HTTP/1.1\n", 15);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // alternative EOL sequence: double-NL-only
+    input.append("GET / HTTP/1.1\n\n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-2, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // RELAXED alternative EOL sequence: multi-CR-NL
+    input.append("GET / HTTP/1.1\r\r\r\n", 18);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    Config.onoff.relaxed_header_parser = 1;
+    // Being tolerant we can ignore and elide these apparently benign CR
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\r\r\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // STRICT alternative EOL sequence: multi-CR-NL
+    input.append("GET / HTTP/1.1\r\r\r\n", 18);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    // strict mode treats these as several bare-CR in the request line which is explicitly invalid.
+    Config.onoff.relaxed_header_parser = 0;
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // RFC 2616 : . method
+    input.append(". / HTTP/1.1\n", 13);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp(". / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
+    CPPUNIT_ASSERT(memcmp(".", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(2, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(11, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // OPTIONS with * URL
+    input.append("OPTIONS * HTTP/1.1\n", 19);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("OPTIONS * HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(6, output.m_end);
+    CPPUNIT_ASSERT(memcmp("OPTIONS", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(8, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(8, output.u_end);
+    CPPUNIT_ASSERT(memcmp("*", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(10, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(17, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // unknown method
+    input.append("HELLOWORLD / HTTP/1.1\n", 22);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("HELLOWORLD / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(9, output.m_end);
+    CPPUNIT_ASSERT(memcmp("HELLOWORLD", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(11, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(11, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(13, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(20, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // This stage of the parser does not yet accept non-HTTP protocol names.
+    // violations mode treats them as HTTP/0.9 requests!
+    input.append("GET / FOO/1.0\n", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+#if USE_HTTP_VIOLATIONS
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(12, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/ FOO/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+#else
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+#endif
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / FOO/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
+    CPPUNIT_ASSERT(memcmp("FOO/1.0", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    input.reset();
+
+    // RELAXED space padded method (in strict mode SP is reserved so invalid as a method byte)
+    input.append(" GET / HTTP/1.1\n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    Config.onoff.relaxed_header_parser = 1;
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(1, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte)
+    input.append(" GET / HTTP/1.1\n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    Config.onoff.relaxed_header_parser = 0;
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp(" GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // tab padded method (NP: tab is not SP so treated as any other binary)
+    input.append("\tGET / HTTP/1.1\n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("\tGET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
+    CPPUNIT_ASSERT(memcmp("\tGET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    input.append("GET", 3);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    input.append("GET ", 4);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    input.append("GET / HT", 8);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    input.append("GET / HTTP/1.1", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // method-only
+    input.append("A\n", 2);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("A\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
+    input.append("/ HTTP/1.0\n", 11);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("/ HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(2, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(9, output.u_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+    input.reset();
+
+    // RELAXED no method (an invalid format)
+    input.append(" / HTTP/1.0\n", 12);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
+    Config.onoff.relaxed_header_parser = 1;
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(1, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("/ HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(1, output.m_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(3, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(10, output.u_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+    input.reset();
+
+    // STRICT no method (an invalid format)
+    input.append(" / HTTP/1.0\n", 12);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
+    Config.onoff.relaxed_header_parser = 0;
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp(" / HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // binary code in method (strange but ...)
+    input.append("GET\x0B / HTTP/1.1\n", 16);
+    //printf("TEST: %d-%d/%d '%.*s'\n", output.req_start, output.req_end, input.contentSize(), 16, input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET\x0B / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET\x0B", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // CR in method
+    // RFC 2616 sec 5.1 prohibits CR other than in terminator.
+    input.append("GET\r / HTTP/1.1\r\n", 16);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // binary code NUL! in method (strange but ...)
+    input.append("GET\0 / HTTP/1.1\n", 16);
+    //printf("TEST: %d-%d/%d '%.*s'\n", output.req_start, output.req_end, input.contentSize(), 16, input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET\0 / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET\0", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
+    input.reset();
+
+    // no URL (grammer otherwise correct)
+    input.append("GET  HTTP/1.1\n", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET  HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(12, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+    input.reset();
+
+    // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
+    input.append("GET HTTP/1.1\n", 13);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(11, output.u_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
+    input.reset();
+
+    // no version
+    input.append("GET / HTTP/\n", 12);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(10, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // no major version
+    input.append("GET / HTTP/.1\n", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // no version dot
+    input.append("GET / HTTP/11\n", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/11\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/11", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // negative major version (bug 3062)
+    input.append("GET / HTTP/-999999.1\n", 21);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/-999999.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(19, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/-999999.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // no minor version
+    input.append("GET / HTTP/1.\n", 14);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // negative major version (bug 3062 corollary)
+    input.append("GET / HTTP/1.-999999\n", 21);
+    //printf("TEST: '%s'\n",input.content());
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.-999999\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
+    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
+    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(19, output.v_end);
+    CPPUNIT_ASSERT(memcmp("HTTP/1.-999999", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // binary line
+    input.append("\xB\xC\xE\xF\n", 5);
+    //printf("TEST: binary-line\n");
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("\xB\xC\xE\xF\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // mixed whitespace line
+    // We accept non-space binary bytes for method so first \t shows up as that
+    // but remaining space and tabs are skipped searching for URI-start
+    input.append("\t \t \t\n", 6);
+    //printf("TEST: mixed whitespace\n");
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
+    CPPUNIT_ASSERT(memcmp("\t \t \t\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
+    CPPUNIT_ASSERT(memcmp("\t", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+
+    // mixed whitespace line with CR middle
+    // CR aborts on sight, so even initial \t method is not marked as above
+    // (not when parsing clean with whole line available anyway)
+    input.append("\t  \r \n", 6);
+    //printf("TEST: mixed whitespace with CR\n");
+    output.reset(input.content(), input.contentSize());
+    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
+    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
+    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
+    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
+    input.reset();
+}
diff --git a/src/tests/testHttpParser.h b/src/tests/testHttpParser.h
new file mode 100644 (file)
index 0000000..bba2eb6
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SQUID_SRC_TESTS_TESTHTTPPARSER_H
+#define SQUID_SRC_TESTS_TESTHTTPPARSER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class testHttpParser : public CPPUNIT_NS::TestFixture
+{
+    CPPUNIT_TEST_SUITE( testHttpParser );
+    CPPUNIT_TEST( testParseRequestLine );
+    CPPUNIT_TEST_SUITE_END();
+
+protected:
+    void globalSetup(); // MemPools init etc.
+    void testParseRequestLine();
+};
+
+#endif
index 04ea216913818e8dfe899dc3f46b1bcfb298d1ac..054d5d9b413ec2d789e14988c275f12f2515ba1e 100644 (file)
@@ -199,889 +199,3 @@ testHttpRequest::testSanityCheckStartLine()
     input.reset();
     error = HTTP_STATUS_NONE;
 }
-
-void
-testHttpRequest::testParseRequestLine()
-{
-    MemBuf input;
-    HttpParser output;
-    input.init();
-
-    // TEST: Do we comply with RFC 1945 section 5.1 ?
-    // TEST: Do we comply with RFC 2616 section 5.1 ?
-
-    // RFC 1945 : HTTP/0.9 simple-request
-    input.append("GET /\r\n", 7);
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET /\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start], (output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start], (output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-    input.reset();
-
-    // RFC 1945 and 2616 : HTTP/1.0 full-request
-    input.append("GET / HTTP/1.0\r\n", 16);
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.0\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-
-    // RFC 2616 : HTTP/1.1 full-request
-    input.append("GET / HTTP/1.1\r\n", 16);
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // RFC 2616 : future version full-request
-    input.append("GET / HTTP/10.12\r\n", 18);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/10.12\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(15, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/10.12", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(10, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(12, output.v_min);
-    input.reset();
-
-    // space padded URL
-    input.append("GET  /     HTTP/1.1\r\n", 21);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET  /     HTTP/1.1\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(11, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(18, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // space padded version
-    // RFC 1945 and 2616 specify version is followed by CRLF. No intermediary bytes.
-    // NP: the terminal whitespace is a special case: invalid for even HTTP/0.9 with no version tag
-    input.append("GET / HTTP/1.1 \n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1 \n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/ HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // whitespace inside URI. (nasty but happens)
-    input.append("GET /fo o/ HTTP/1.1\n", 20);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET /fo o/ HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(9, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/fo o/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(11, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(18, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // additional data in buffer
-    input.append("GET /     HTTP/1.1\nboo!", 23);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-5, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET /     HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end); // strangeness generated by following RFC
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(10, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(17, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // alternative EOL sequence: NL-only
-    input.append("GET / HTTP/1.1\n", 15);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // alternative EOL sequence: double-NL-only
-    input.append("GET / HTTP/1.1\n\n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-2, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // RELAXED alternative EOL sequence: multi-CR-NL
-    input.append("GET / HTTP/1.1\r\r\r\n", 18);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    Config.onoff.relaxed_header_parser = 1;
-    // Being tolerant we can ignore and elide these apparently benign CR
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\r\r\r\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // STRICT alternative EOL sequence: multi-CR-NL
-    input.append("GET / HTTP/1.1\r\r\r\n", 18);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    // strict mode treats these as several bare-CR in the request line which is explicitly invalid.
-    Config.onoff.relaxed_header_parser = 0;
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // RFC 2616 : . method
-    input.append(". / HTTP/1.1\n", 13);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp(". / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
-    CPPUNIT_ASSERT(memcmp(".", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(2, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(11, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // OPTIONS with * URL
-    input.append("OPTIONS * HTTP/1.1\n", 19);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("OPTIONS * HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(6, output.m_end);
-    CPPUNIT_ASSERT(memcmp("OPTIONS", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(8, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(8, output.u_end);
-    CPPUNIT_ASSERT(memcmp("*", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(10, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(17, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // unknown method
-    input.append("HELLOWORLD / HTTP/1.1\n", 22);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("HELLOWORLD / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(9, output.m_end);
-    CPPUNIT_ASSERT(memcmp("HELLOWORLD", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(11, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(11, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(13, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(20, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // This stage of the parser does not yet accept non-HTTP protocol names.
-    // violations mode treats them as HTTP/0.9 requests!
-    input.append("GET / FOO/1.0\n", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-#if USE_HTTP_VIOLATIONS
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(12, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/ FOO/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-#else
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-#endif
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / FOO/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
-    CPPUNIT_ASSERT(memcmp("FOO/1.0", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    input.reset();
-
-    // RELAXED space padded method (in strict mode SP is reserved so invalid as a method byte)
-    input.append(" GET / HTTP/1.1\n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    Config.onoff.relaxed_header_parser = 1;
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(1, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte)
-    input.append(" GET / HTTP/1.1\n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    Config.onoff.relaxed_header_parser = 0;
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp(" GET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // tab padded method (NP: tab is not SP so treated as any other binary)
-    input.append("\tGET / HTTP/1.1\n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("\tGET / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
-    CPPUNIT_ASSERT(memcmp("\tGET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    input.append("GET", 3);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    input.append("GET ", 4);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    input.append("GET / HT", 8);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    input.append("GET / HTTP/1.1", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(0, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_STATUS_NONE, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // method-only
-    input.append("A\n", 2);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("A\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
-    input.append("/ HTTP/1.0\n", 11);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("/ HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(2, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(9, output.u_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-    input.reset();
-
-    // RELAXED no method (an invalid format)
-    input.append(" / HTTP/1.0\n", 12);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
-    Config.onoff.relaxed_header_parser = 1;
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(1, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("/ HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(1, output.m_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(3, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(10, output.u_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.0", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-    input.reset();
-
-    // STRICT no method (an invalid format)
-    input.append(" / HTTP/1.0\n", 12);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
-    Config.onoff.relaxed_header_parser = 0;
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp(" / HTTP/1.0\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // binary code in method (strange but ...)
-    input.append("GET\x0B / HTTP/1.1\n", 16);
-    //printf("TEST: %d-%d/%d '%.*s'\n", output.req_start, output.req_end, input.contentSize(), 16, input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET\x0B / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET\x0B", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // CR in method
-    // RFC 2616 sec 5.1 prohibits CR other than in terminator.
-    input.append("GET\r / HTTP/1.1\r\n", 16);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // binary code NUL! in method (strange but ...)
-    input.append("GET\0 / HTTP/1.1\n", 16);
-    //printf("TEST: %d-%d/%d '%.*s'\n", output.req_start, output.req_end, input.contentSize(), 16, input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET\0 / HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(3, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET\0", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(7, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(14, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_min);
-    input.reset();
-
-    // no URL (grammer otherwise correct)
-    input.append("GET  HTTP/1.1\n", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET  HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(5, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(12, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-    input.reset();
-
-    // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
-    input.append("GET HTTP/1.1\n", 13);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_OK, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET HTTP/1.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(11, output.u_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.1", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(9, output.v_min);
-    input.reset();
-
-    // no version
-    input.append("GET / HTTP/\n", 12);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(10, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // no major version
-    input.append("GET / HTTP/.1\n", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // no version dot
-    input.append("GET / HTTP/11\n", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/11\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/11", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // negative major version (bug 3062)
-    input.append("GET / HTTP/-999999.1\n", 21);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/-999999.1\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(19, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/-999999.1", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // no minor version
-    input.append("GET / HTTP/1.\n", 14);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(12, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // negative major version (bug 3062 corollary)
-    input.append("GET / HTTP/1.-999999\n", 21);
-    //printf("TEST: '%s'\n",input.content());
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_HTTP_VERSION_NOT_SUPPORTED, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("GET / HTTP/1.-999999\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(2, output.m_end);
-    CPPUNIT_ASSERT(memcmp("GET", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(4, output.u_end);
-    CPPUNIT_ASSERT(memcmp("/", &output.buf[output.u_start],(output.u_end-output.u_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(6, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(19, output.v_end);
-    CPPUNIT_ASSERT(memcmp("HTTP/1.-999999", &output.buf[output.v_start],(output.v_end-output.v_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(1, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // binary line
-    input.append("\xB\xC\xE\xF\n", 5);
-    //printf("TEST: binary-line\n");
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("\xB\xC\xE\xF\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // mixed whitespace line
-    // We accept non-space binary bytes for method so first \t shows up as that
-    // but remaining space and tabs are skipped searching for URI-start
-    input.append("\t \t \t\n", 6);
-    //printf("TEST: mixed whitespace\n");
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req_end);
-    CPPUNIT_ASSERT(memcmp("\t \t \t\n", &output.buf[output.req_start],(output.req_end-output.req_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(0, output.m_end);
-    CPPUNIT_ASSERT(memcmp("\t", &output.buf[output.m_start],(output.m_end-output.m_start+1)) == 0);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-
-    // mixed whitespace line with CR middle
-    // CR aborts on sight, so even initial \t method is not marked as above
-    // (not when parsing clean with whole line available anyway)
-    input.append("\t  \r \n", 6);
-    //printf("TEST: mixed whitespace with CR\n");
-    HttpParserInit(&output, input.content(), input.contentSize());
-    CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
-    CPPUNIT_ASSERT_EQUAL(HTTP_BAD_REQUEST, output.request_parse_status);
-    CPPUNIT_ASSERT_EQUAL(0, output.req_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.req_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.m_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.u_end);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_start);
-    CPPUNIT_ASSERT_EQUAL(-1, output.v_end);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_maj);
-    CPPUNIT_ASSERT_EQUAL(0, output.v_min);
-    input.reset();
-}
index 2d7f081847ed12c14d6c79aa68d9cc0c2a4cb00c..efdec613a6247a581d11380327cdb7db6af3f4e1 100644 (file)
@@ -15,7 +15,6 @@ class testHttpRequest : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST( testCreateFromUrl );
     CPPUNIT_TEST( testIPv6HostColonBug );
     CPPUNIT_TEST( testSanityCheckStartLine );
-    CPPUNIT_TEST( testParseRequestLine );
     CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -26,7 +25,6 @@ protected:
     void testCreateFromUrl();
     void testIPv6HostColonBug();
     void testSanityCheckStartLine();
-    void testParseRequestLine();
 };
 
 #endif