=== modified file 'configure.ac'
--- configure.ac	2013-12-12 09:41:39 +0000
+++ configure.ac	2013-12-18 06:15:47 +0000
@@ -3429,6 +3429,7 @@
 	src/ipc/Makefile
 	src/ssl/Makefile
 	src/mgr/Makefile
+	src/parser/Makefile
 	src/snmp/Makefile
 	contrib/Makefile
 	icons/Makefile

=== modified file 'src/AccessLogEntry.h'
--- src/AccessLogEntry.h	2013-12-06 14:59:47 +0000
+++ src/AccessLogEntry.h	2013-12-23 16:20:05 +0000
@@ -36,7 +36,7 @@
 #include "HierarchyLogEntry.h"
 #include "http/ProtocolVersion.h"
 #include "HttpHeader.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "icp_opcode.h"
 #include "ip/Address.h"
 #include "LogTags.h"

=== modified file 'src/HttpMsg.h'
--- src/HttpMsg.h	2013-10-25 00:13:46 +0000
+++ src/HttpMsg.h	2013-12-23 16:27:13 +0000
@@ -33,10 +33,10 @@
 
 #include "base/Lock.h"
 #include "BodyPipe.h"
+#include "http/forward.h"
 #include "http/ProtocolVersion.h"
 #include "http/StatusCode.h"
 #include "HttpHeader.h"
-#include "HttpRequestMethod.h"
 
 /// common parts of HttpRequest and HttpReply
 class HttpMsg : public RefCountable
@@ -67,6 +67,7 @@
     bool persistent() const;
 
 public:
+    /// transport protocol version for this message
     Http::ProtocolVersion http_ver;
 
     HttpHeader header;
@@ -80,6 +81,7 @@
 
     int64_t content_length;
 
+    /// URL scheme protocol (if relevant)
     AnyP::ProtocolType protocol;
 
     HttpMsgParseState pstate;   /* the current parsing state */

=== modified file 'src/HttpRequest.h'
--- src/HttpRequest.h	2013-07-15 07:49:43 +0000
+++ src/HttpRequest.h	2013-12-23 16:26:48 +0000
@@ -36,7 +36,7 @@
 #include "err_type.h"
 #include "HierarchyLogEntry.h"
 #include "HttpMsg.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "Notes.h"
 #include "RequestFlags.h"
 

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2014-01-03 10:32:53 +0000
+++ src/Makefile.am	2014-01-04 23:15:54 +0000
@@ -46,8 +46,8 @@
 	LoadableModules.h \
 	LoadableModules.cc
 
-SUBDIRS	= base anyp comm eui acl format fs repl
-DIST_SUBDIRS = base anyp comm eui acl format fs repl
+SUBDIRS	= base anyp parser comm eui acl format fs repl
+DIST_SUBDIRS = base anyp parser comm eui acl format fs repl
 
 if ENABLE_AUTH
 SUBDIRS += auth
@@ -408,16 +408,12 @@
 	HttpControlMsg.h \
 	HttpMsg.cc \
 	HttpMsg.h \
-	HttpParser.cc \
-	HttpParser.h \
 	HttpReply.cc \
 	HttpReply.h \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
 	HttpRequest.h \
-	HttpRequestMethod.cc \
-	HttpRequestMethod.h \
 	ICP.h \
 	icp_opcode.h \
 	icp_v2.cc \
@@ -646,6 +642,7 @@
 	$(ESI_LIBS) \
 	$(SSL_LIBS) \
 	$(SNMP_LIBS) \
+	parser/libsquid-parser.la \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -743,7 +740,7 @@
 	dlink.cc \
 	HelperChildConfig.h \
 	tests/stub_HelperChildConfig.cc \
-	HttpRequestMethod.cc \
+	http/RequestMethod.cc \
 	RemovalPolicy.cc \
 	$(WIN32_SOURCE) \
 	fd.h \
@@ -1070,7 +1067,7 @@
 	tests/testEvent \
 	tests/testEventLoop \
 	tests/test_http_range \
-	tests/testHttpParser \
+	tests/testHttp1Parser \
 	tests/testHttpReply \
 	tests/testHttpRequest \
 	tests/testStore \
@@ -1249,7 +1246,6 @@
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	MasterXaction.cc \
@@ -1385,12 +1381,9 @@
 tests_testCacheManager_SOURCES = \
 	AccessLogEntry.cc \
 	debug.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	String.cc \
@@ -1670,7 +1663,6 @@
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	SquidList.h \
@@ -1898,13 +1890,10 @@
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	HttpReply.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
@@ -2146,13 +2135,10 @@
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	HttpReply.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
@@ -2390,13 +2376,10 @@
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	HttpReply.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	int.h \
@@ -2547,15 +2530,15 @@
 tests_test_http_range_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 
-tests_testHttpParser_SOURCES = \
+tests_testHttp1Parser_SOURCES = \
 	Debug.h \
-	HttpParser.cc \
-	HttpParser.h \
 	MemBuf.cc \
 	MemBuf.h \
 	tests/stub_MemObject.cc \
 	Mem.h \
 	tests/stub_mem.cc \
+	mime_header.cc \
+	mime_header.h \
 	String.cc \
 	cache_cf.h \
 	YesNoNone.h \
@@ -2573,16 +2556,17 @@
 	tests/stub_store_stats.cc \
 	tools.h \
 	tests/stub_tools.cc \
-	tests/testHttpParser.cc \
-	tests/testHttpParser.h \
+	tests/testHttp1Parser.cc \
+	tests/testHttp1Parser.h \
 	tests/testMain.cc \
 	tests/stub_time.cc \
 	wordlist.h \
 	wordlist.cc
-nodist_tests_testHttpParser_SOURCES = \
+nodist_tests_testHttp1Parser_SOURCES = \
 	$(TESTSOURCES)
-tests_testHttpParser_LDADD= \
+tests_testHttp1Parser_LDADD= \
 	http/libsquid-http.la \
+	anyp/libanyp.la \
 	SquidConfig.o \
 	base/libbase.la \
 	ip/libip.la \
@@ -2590,19 +2574,16 @@
 	$(SQUID_CPPUNIT_LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
-tests_testHttpParser_LDFLAGS = $(LIBADD_DL)
-tests_testHttpParser_DEPENDENCIES = \
+tests_testHttp1Parser_LDFLAGS = $(LIBADD_DL)
+tests_testHttp1Parser_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 
 ## Tests of the HttpRequest module.
 tests_testHttpRequest_SOURCES = \
 	AccessLogEntry.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	String.cc \
@@ -2873,7 +2854,6 @@
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpMsg.cc \
-	HttpRequestMethod.cc \
 	RequestFlags.cc \
 	RequestFlags.h \
 	int.h \
@@ -3140,7 +3120,6 @@
 	store_dir.cc \
 	repl_modules.h \
 	store.cc \
-	HttpRequestMethod.cc \
 	store_key_md5.h \
 	store_key_md5.cc \
 	Parsing.cc \
@@ -3298,7 +3277,6 @@
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	SquidList.h \
@@ -3511,13 +3489,10 @@
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
-	HttpParser.cc \
-	HttpParser.h \
 	HttpReply.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
 	HttpRequest.cc \
-	HttpRequestMethod.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \

=== modified file 'src/MemObject.h'
--- src/MemObject.h	2013-12-31 18:49:41 +0000
+++ src/MemObject.h	2014-01-04 23:15:54 +0000
@@ -33,7 +33,7 @@
 
 #include "CommRead.h"
 #include "dlink.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "RemovalPolicy.h"
 #include "stmem.h"
 #include "StoreIOBuffer.h"

=== modified file 'src/Store.h'
--- src/Store.h	2014-01-03 10:32:53 +0000
+++ src/Store.h	2014-01-04 23:16:39 +0000
@@ -39,8 +39,9 @@
 #include "comm/forward.h"
 #include "CommRead.h"
 #include "hash.h"
+#include "http/forward.h"
+#include "http/RequestMethod.h"
 #include "HttpReply.h"
-#include "HttpRequestMethod.h"
 #include "MemObject.h"
 #include "Range.h"
 #include "RemovalPolicy.h"

=== modified file 'src/acl/Method.h'
--- src/acl/Method.h	2013-10-25 00:13:46 +0000
+++ src/acl/Method.h	2013-12-23 16:20:15 +0000
@@ -35,7 +35,7 @@
 
 #include "acl/Strategised.h"
 #include "acl/Strategy.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 
 /// \ingroup ACLAPI
 class ACLMethodStrategy : public ACLStrategy<HttpRequestMethod>

=== modified file 'src/acl/MethodData.cc'
--- src/acl/MethodData.cc	2013-10-25 00:13:46 +0000
+++ src/acl/MethodData.cc	2013-12-23 16:21:24 +0000
@@ -36,7 +36,6 @@
 #include "acl/Checklist.h"
 #include "acl/MethodData.h"
 #include "cache_cf.h"
-#include "HttpRequestMethod.h"
 #include "wordlist.h"
 
 int ACLMethodData::ThePurgeCount = 0;

=== modified file 'src/acl/MethodData.h'
--- src/acl/MethodData.h	2012-09-01 14:38:36 +0000
+++ src/acl/MethodData.h	2013-12-23 16:20:33 +0000
@@ -36,7 +36,7 @@
 #include "acl/Acl.h"
 #include "acl/Data.h"
 #include "CbDataList.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 
 /// \ingroup ACLAPI
 class ACLMethodData : public ACLData<HttpRequestMethod>

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2013-10-25 00:13:46 +0000
+++ src/cache_cf.cc	2013-12-23 16:28:10 +0000
@@ -53,7 +53,6 @@
 #include "format/Format.h"
 #include "globals.h"
 #include "HttpHeaderTools.h"
-#include "HttpRequestMethod.h"
 #include "ident/Config.h"
 #include "ip/Intercept.h"
 #include "ip/QosConfig.h"

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2013-12-06 23:52:26 +0000
+++ src/client_side.cc	2014-01-04 23:15:54 +0000
@@ -104,6 +104,7 @@
 #include "FwdState.h"
 #include "globals.h"
 #include "http.h"
+#include "http/Http1Parser.h"
 #include "HttpHdrContRange.h"
 #include "HttpHeaderTools.h"
 #include "HttpReply.h"
@@ -205,7 +206,7 @@
 #endif
 static CTCB clientLifetimeTimeout;
 static ClientSocketContext *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
-static ClientSocketContext *parseHttpRequest(ConnStateData *, HttpParser *, HttpRequestMethod *, Http::ProtocolVersion *);
+static ClientSocketContext *parseHttpRequest(ConnStateData *, Http1::RequestParser &);
 #if USE_IDENT
 static IDCB clientIdentDone;
 #endif
@@ -2079,20 +2080,21 @@
 }
 
 static void
-prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
+prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, Http1::RequestParser &hp)
 {
     int vhost = conn->port->vhost;
     int vport = conn->port->vport;
-    char *host;
-    char ipbuf[MAX_IPSTRLEN];
+    static char ipbuf[MAX_IPSTRLEN];
 
     http->flags.accel = true;
 
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
 
-    if (strncasecmp(url, "cache_object://", 15) == 0)
+    static const SBuf cache_object("cache_object://");
+    if (hp.requestUri().startsWith(cache_object))
         return; /* already in good shape */
 
+    const char *url = SBuf(hp.requestUri()).c_str(); // XXX: performance regression. convert to SBuf parse
     if (*url != '/') {
         if (conn->port->vhost)
             return; /* already in good shape */
@@ -2103,7 +2105,7 @@
 #if SHOULD_REJECT_UNKNOWN_URLS
 
         if (!url) {
-            hp->request_parse_status = Http::scBadRequest;
+            hp.request_parse_status = Http::scBadRequest;
             return parseHttpRequestAbort(conn, "error:invalid-request");
         }
 #endif
@@ -2120,7 +2122,8 @@
 
     const bool switchedToHttps = conn->switchedToHttps();
     const bool tryHostHeader = vhost || switchedToHttps;
-    if (tryHostHeader && (host = mime_get_header(req_hdr, "Host")) != NULL) {
+    char *host = NULL;
+    if (tryHostHeader && (host = hp.getHeaderField("Host"))) {
         debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
         char thost[256];
         if (vport > 0) {
@@ -2135,7 +2138,7 @@
                 host = thost;
             }
         } // else nothing to alter port-wise.
-        int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+        const int url_sz = hp.requestUri().length() + 32 + Config.appendDomainLen +
                      strlen(host);
         http->uri = (char *)xcalloc(url_sz, 1);
         const char *protocol = switchedToHttps ?
@@ -2144,7 +2147,7 @@
         debugs(33, 5, "ACCEL VHOST REWRITE: '" << http->uri << "'");
     } else if (conn->port->defaultsite /* && !vhost */) {
         debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
-        int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+        const int url_sz = hp.requestUri().length() + 32 + Config.appendDomainLen +
                      strlen(conn->port->defaultsite);
         http->uri = (char *)xcalloc(url_sz, 1);
         char vportStr[32];
@@ -2158,7 +2161,7 @@
     } else if (vport > 0 /* && (!vhost || no Host:) */) {
         debugs(33, 5, "ACCEL VPORT REWRITE: http_port IP + vport=" << vport);
         /* Put the local socket IP address as the hostname, with whatever vport we found  */
-        int url_sz = strlen(url) + 32 + Config.appendDomainLen;
+        const int url_sz = hp.requestUri().length() + 32 + Config.appendDomainLen;
         http->uri = (char *)xcalloc(url_sz, 1);
         http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
         snprintf(http->uri, url_sz, "%s://%s:%d%s",
@@ -2169,30 +2172,30 @@
 }
 
 static void
-prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
+prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, Http1::RequestParser &hp)
 {
-    char *host;
-    char ipbuf[MAX_IPSTRLEN];
+    static char ipbuf[MAX_IPSTRLEN];
 
-    if (*url != '/')
+    // TODO Must() on URI length>0 when the parser supports throw. For now avoid assert().
+    if (!hp.requestUri().length() && hp.requestUri()[0] != '/')
         return; /* already in good shape */
 
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
 
-    if ((host = mime_get_header(req_hdr, "Host")) != NULL) {
-        int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+    if (const char *host = hp.getHeaderField("Host")) {
+        const int url_sz = hp.requestUri().length() + 32 + Config.appendDomainLen +
                      strlen(host);
         http->uri = (char *)xcalloc(url_sz, 1);
-        snprintf(http->uri, url_sz, "%s://%s%s", URLScheme(conn->port->transport.protocol).const_str(), host, url);
+        snprintf(http->uri, url_sz, "%s://%s%s", URLScheme(conn->port->transport.protocol).const_str(), host, SBuf(hp.requestUri()).c_str());
         debugs(33, 5, "TRANSPARENT HOST REWRITE: '" << http->uri <<"'");
     } else {
         /* Put the local socket IP address as the hostname.  */
-        int url_sz = strlen(url) + 32 + Config.appendDomainLen;
+        const int url_sz = hp.requestUri().length() + 32 + Config.appendDomainLen;
         http->uri = (char *)xcalloc(url_sz, 1);
         http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
         snprintf(http->uri, url_sz, "%s://%s:%d%s",
                  URLScheme(http->getConn()->port->transport.protocol).const_str(),
-                 ipbuf, http->getConn()->clientConnection->local.port(), url);
+                 ipbuf, http->getConn()->clientConnection->local.port(), SBuf(hp.requestUri()).c_str());
         debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'");
     }
 }
@@ -2202,7 +2205,7 @@
  *  \note Sets result->flags.parsed_ok to 0 if failed to parse the request,
  *          to 1 if the request was correctly parsed.
  *  \param[in] csd a ConnStateData. The caller must make sure it is not null
- *  \param[in] hp an HttpParser
+ *  \param[in] hp an Http1::RequestParser
  *  \param[out] mehtod_p will be set as a side-effect of the parsing.
  *          Pointed-to value will be set to Http::METHOD_NONE in case of
  *          parsing failure
@@ -2211,91 +2214,40 @@
  *          a ClientSocketContext structure on success or failure.
  */
 static ClientSocketContext *
-parseHttpRequest(ConnStateData *csd, HttpParser *hp, HttpRequestMethod * method_p, Http::ProtocolVersion *http_ver)
+parseHttpRequest(ConnStateData *csd, Http1::RequestParser &hp)
 {
-    char *req_hdr = NULL;
-    char *end;
-    size_t req_sz;
-    ClientHttpRequest *http;
-    ClientSocketContext *result;
-    StoreIOBuffer tempBuffer;
-    int r;
-
-    /* pre-set these values to make aborting simpler */
-    *method_p = Http::METHOD_NONE;
-
-    /* NP: don't be tempted to move this down or remove again.
-     * It's the only DDoS protection old-String has against long URL */
-    if ( hp->bufsiz <= 0) {
-        debugs(33, 5, "Incomplete request, waiting for end of request line");
-        return NULL;
-    } else if ( (size_t)hp->bufsiz >= Config.maxRequestHeaderSize && headersEnd(hp->buf, Config.maxRequestHeaderSize) == 0) {
-        debugs(33, 5, "parseHttpRequest: Too large request");
-        hp->request_parse_status = Http::scHeaderTooLarge;
-        return parseHttpRequestAbort(csd, "error:request-too-large");
-    }
-
-    /* Attempt to parse the first line; this'll define the method, url, version and header begin */
-    r = HttpParserParseReqLine(hp);
-
-    if (r == 0) {
-        debugs(33, 5, "Incomplete request, waiting for end of request line");
-        return NULL;
-    }
-
-    if (r == -1) {
-        return parseHttpRequestAbort(csd, "error:invalid-request");
-    }
-
-    /* Request line is valid here .. */
-    *http_ver = Http::ProtocolVersion(hp->req.v_maj, hp->req.v_min);
-
-    /* This call scans the entire request, not just the headers */
-    if (hp->req.v_maj > 0) {
-        if ((req_sz = headersEnd(hp->buf, hp->bufsiz)) == 0) {
-            debugs(33, 5, "Incomplete request, waiting for end of headers");
+    /* Attempt to parse the first line; this will define where the method, url, version and header begin */
+    {
+        const bool parsedOk = hp.parse();
+
+        if (!hp.isDone()) {
+            debugs(33, 5, "Incomplete request, waiting for end of request line");
             return NULL;
         }
-    } else {
-        debugs(33, 3, "parseHttpRequest: Missing HTTP identifier");
-        req_sz = HttpParserReqSz(hp);
-    }
-
-    /* We know the whole request is in hp->buf now */
-
-    assert(req_sz <= (size_t) hp->bufsiz);
-
-    /* Will the following be true with HTTP/0.9 requests? probably not .. */
-    /* So the rest of the code will need to deal with '0'-byte headers (ie, none, so don't try parsing em) */
-    assert(req_sz > 0);
-
-    hp->hdr_end = req_sz - 1;
-
-    hp->hdr_start = hp->req.end + 1;
-
-    /* Enforce max_request_size */
-    if (req_sz >= Config.maxRequestHeaderSize) {
-        debugs(33, 5, "parseHttpRequest: Too large request");
-        hp->request_parse_status = Http::scHeaderTooLarge;
-        return parseHttpRequestAbort(csd, "error:request-too-large");
-    }
-
-    /* Set method_p */
-    *method_p = HttpRequestMethod(&hp->buf[hp->req.m_start], &hp->buf[hp->req.m_end]+1);
+
+        if (!parsedOk) {
+            if (hp.request_parse_status == Http::scHeaderTooLarge)
+                return parseHttpRequestAbort(csd, "error:request-too-large");
+
+            return parseHttpRequestAbort(csd, "error:invalid-request");
+        }
+    }
+
+    /* We know the whole request is in hp.buf now */
 
     /* deny CONNECT via accelerated ports */
-    if (*method_p == Http::METHOD_CONNECT && csd->port && csd->port->flags.accelSurrogate) {
+    if (hp.method() == Http::METHOD_CONNECT && csd->port && csd->port->flags.accelSurrogate) {
         debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->transport.protocol << " Accelerator port " << csd->port->s.port());
         /* XXX need a way to say "this many character length string" */
-        debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->buf);
-        hp->request_parse_status = Http::scMethodNotAllowed;
+        debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp.buf);
+        hp.request_parse_status = Http::scMethodNotAllowed;
         return parseHttpRequestAbort(csd, "error:method-not-allowed");
     }
 
-    if (*method_p == Http::METHOD_NONE) {
+    if (hp.method() == Http::METHOD_NONE) {
         /* XXX need a way to say "this many character length string" */
-        debugs(33, DBG_IMPORTANT, "clientParseRequestMethod: Unsupported method in request '" << hp->buf << "'");
-        hp->request_parse_status = Http::scMethodNotAllowed;
+        debugs(33, DBG_IMPORTANT, "clientParseRequestMethod: Unsupported method in request '" << hp.buf << "'");
+        hp.request_parse_status = Http::scMethodNotAllowed;
         return parseHttpRequestAbort(csd, "error:unsupported-request-method");
     }
 
@@ -2303,24 +2255,18 @@
      * Process headers after request line
      * TODO: Use httpRequestParse here.
      */
-    /* XXX this code should be modified to take a const char * later! */
-    req_hdr = (char *) hp->buf + hp->req.end + 1;
-
-    debugs(33, 3, "parseHttpRequest: req_hdr = {" << req_hdr << "}");
-
-    end = (char *) hp->buf + hp->hdr_end;
-
-    debugs(33, 3, "parseHttpRequest: end = {" << end << "}");
-
-    debugs(33, 3, "parseHttpRequest: prefix_sz = " <<
-           (int) HttpParserRequestLen(hp) << ", req_line_sz = " <<
-           HttpParserReqSz(hp));
+    debugs(33, 3, Raw("req_hdr", hp.rawHeaderBuf(), hp.headerBlockSize()));
+    debugs(33, 3, "prefix_sz = " << hp.messageHeaderSize() <<
+           ", request-line-size=" << hp.firstLineSize() <<
+           ", mime-header-size=" << hp.headerBlockSize());
 
     /* Ok, all headers are received */
-    http = new ClientHttpRequest(csd);
-
-    http->req_sz = HttpParserRequestLen(hp);
-    result = ClientSocketContextNew(csd->clientConnection, http);
+    ClientHttpRequest *http = new ClientHttpRequest(csd);
+
+    http->req_sz = hp.messageHeaderSize();
+    ClientSocketContext *result = ClientSocketContextNew(csd->clientConnection, http);
+
+    StoreIOBuffer tempBuffer;
     tempBuffer.data = result->reqbuf;
     tempBuffer.length = HTTP_REQBUF_SZ;
 
@@ -2330,25 +2276,10 @@
                      clientReplyStatus, newServer, clientSocketRecipient,
                      clientSocketDetach, newClient, tempBuffer);
 
-    debugs(33, 5, "parseHttpRequest: Request Header is\n" <<(hp->buf) + hp->hdr_start);
+    debugs(33, 5, "parseHttpRequest: Request Header is\n" << hp.rawHeaderBuf());
 
     /* set url */
-    /*
-     * XXX this should eventually not use a malloc'ed buffer; the transformation code
-     * below needs to be modified to not expect a mutable nul-terminated string.
-     */
-    char *url = (char *)xmalloc(hp->req.u_end - hp->req.u_start + 16);
-
-    memcpy(url, hp->buf + hp->req.u_start, hp->req.u_end - hp->req.u_start + 1);
-
-    url[hp->req.u_end - hp->req.u_start + 1] = '\0';
-
-#if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION
-
-    if ((t = strchr(url, '#')))	/* remove HTML anchors */
-        *t = '\0';
-
-#endif
+    const char *url = SBuf(hp.requestUri()).c_str();
 
     debugs(33,5, HERE << "repare absolute URL from " <<
            (csd->transparent()?"intercept":(csd->port->flags.accelSurrogate ? "accel":"")));
@@ -2365,7 +2296,7 @@
      */
     if (csd->transparent()) {
         /* intercept or transparent mode, properly working with no failures */
-        prepareTransparentURL(csd, http, url, req_hdr);
+        prepareTransparentURL(csd, http, hp);
 
     } else if (internalCheck(url)) {
         /* internal URL mode */
@@ -2377,13 +2308,13 @@
 
     } else if (csd->port->flags.accelSurrogate || csd->switchedToHttps()) {
         /* accelerator mode */
-        prepareAcceleratedURL(csd, http, url, req_hdr);
+        prepareAcceleratedURL(csd, http, hp);
     }
 
     if (!http->uri) {
         /* No special rewrites have been applied above, use the
          * requested url. may be rewritten later, so make extra room */
-        int url_sz = strlen(url) + Config.appendDomainLen + 5;
+        int url_sz = hp.requestUri().length() + Config.appendDomainLen + 5;
         http->uri = (char *)xcalloc(url_sz, 1);
         strcpy(http->uri, url);
     }
@@ -2392,10 +2323,12 @@
 
     // XXX: crop this dump at the end of headers. No need for extras
     debugs(11, 2, "HTTP Client " << csd->clientConnection);
-    debugs(11, 2, "HTTP Client REQUEST:\n---------\n" << (hp->buf) + hp->req.m_start << "\n----------");
+    debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
+           hp.method() << " " << hp.requestUri() << " " << hp.messageProtocol() << "\n" <<
+           hp.rawHeaderBuf() <<
+           "\n----------");
 
     result->flags.parsed_ok = 1;
-    xfree(url);
     return result;
 }
 
@@ -2504,27 +2437,6 @@
         memmove(conn->in.buf, conn->in.buf + byteCount, conn->in.notYetUsed);
 }
 
-/// respond with ERR_TOO_BIG if request header exceeds request_header_max_size
-void
-ConnStateData::checkHeaderLimits()
-{
-    if (in.notYetUsed < Config.maxRequestHeaderSize)
-        return; // can accumulte more header data
-
-    debugs(33, 3, "Request header is too large (" << in.notYetUsed << " > " <<
-           Config.maxRequestHeaderSize << " bytes)");
-
-    ClientSocketContext *context = parseHttpRequestAbort(this, "error:request-too-large");
-    clientStreamNode *node = context->getClientReplyContext();
-    clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
-    assert (repContext);
-    repContext->setReplyToError(ERR_TOO_BIG,
-                                Http::scBadRequest, Http::METHOD_NONE, NULL,
-                                clientConnection->remote, NULL, NULL, NULL);
-    context->registerWithConn();
-    context->pullData();
-}
-
 void
 ConnStateData::clientAfterReadingRequests()
 {
@@ -2638,15 +2550,16 @@
 #endif // USE_SSL
 
 static void
-clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, Http::ProtocolVersion http_ver)
+clientProcessRequest(ConnStateData *conn, Http1::RequestParser &hp, ClientSocketContext *context)
 {
     ClientHttpRequest *http = context->http;
     HttpRequest::Pointer request;
-    bool notedUseOfBuffer = false;
     bool chunked = false;
     bool mustReplyToOptions = false;
     bool unsupportedTe = false;
     bool expectBody = false;
+    const AnyP::ProtocolVersion &http_ver = hp.messageProtocol();
+    const HttpRequestMethod &method = hp.method();
 
     /* We have an initial client stream in place should it be needed */
     /* setup our private context */
@@ -2654,13 +2567,13 @@
 
     if (context->flags.parsed_ok == 0) {
         clientStreamNode *node = context->getClientReplyContext();
-        debugs(33, 2, "clientProcessRequest: Invalid Request");
+        debugs(33, 2, "Invalid Request");
         conn->quitAfterError(NULL);
         // setLogUri should called before repContext->setReplyToError
         setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
-        switch (hp->request_parse_status) {
+        switch (hp.request_parse_status) {
         case Http::scHeaderTooLarge:
             repContext->setReplyToError(ERR_TOO_BIG, Http::scBadRequest, method, http->uri, conn->clientConnection->remote, NULL, conn->in.buf, NULL);
             break;
@@ -2669,7 +2582,7 @@
                                         conn->clientConnection->remote, NULL, conn->in.buf, NULL);
             break;
         default:
-            repContext->setReplyToError(ERR_INVALID_REQ, hp->request_parse_status, method, http->uri,
+            repContext->setReplyToError(ERR_INVALID_REQ, hp.request_parse_status, method, http->uri,
                                         conn->clientConnection->remote, NULL, conn->in.buf, NULL);
         }
         assert(context->http->out.offset == 0);
@@ -2697,25 +2610,23 @@
             (http_ver.major > 1) ) {
 
         clientStreamNode *node = context->getClientReplyContext();
-        debugs(33, 5, "Unsupported HTTP version discovered. :\n" << HttpParserHdrBuf(hp));
+        debugs(33, 5, "Unsupported HTTP version discovered. :\n" << hp.messageProtocol());
         conn->quitAfterError(request.getRaw());
         // setLogUri should called before repContext->setReplyToError
         setLogUri(http, http->uri,  true);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, method, http->uri,
-                                    conn->clientConnection->remote, NULL, HttpParserHdrBuf(hp), NULL);
+                                    conn->clientConnection->remote, NULL, hp.rawHeaderBuf(), NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         goto finish;
     }
 
     /* compile headers */
-    /* we should skip request line! */
-    /* XXX should actually know the damned buffer size here */
-    if (http_ver.major >= 1 && !request->parseHeader(HttpParserHdrBuf(hp), HttpParserHdrSz(hp))) {
+    if (http_ver.major >= 1 && !request->parseHeader(hp.rawHeaderBuf(), hp.headerBlockSize())) {
         clientStreamNode *node = context->getClientReplyContext();
-        debugs(33, 5, "Failed to parse request headers:\n" << HttpParserHdrBuf(hp));
+        debugs(33, 5, "Failed to parse request headers:\n" << hp.rawHeaderBuf());
         conn->quitAfterError(request.getRaw());
         // setLogUri should called before repContext->setReplyToError
         setLogUri(http, http->uri,  true);
@@ -2786,7 +2697,11 @@
 #endif /* FOLLOW_X_FORWARDED_FOR */
     request->my_addr = conn->clientConnection->local;
     request->myportname = conn->port->name;
-    request->http_ver = http_ver;
+    // XXX: for non-HTTP messages instantiate a different HttpMsg child type
+    // for now Squid only supports HTTP requests
+    assert(request->http_ver.protocol == http_ver.protocol);
+    request->http_ver.major = http_ver.major;
+    request->http_ver.minor = http_ver.minor;
 
     // Link this HttpRequest to ConnStateData relatively early so the following complex handling can use it
     // TODO: this effectively obsoletes a lot of conn->FOO copying. That needs cleaning up later.
@@ -2864,10 +2779,6 @@
         request->body_pipe = conn->expectRequestBody(
                                  chunked ? -1 : request->content_length);
 
-        // consume header early so that body pipe gets just the body
-        connNoteUseOfBuffer(conn, http->req_sz);
-        notedUseOfBuffer = true;
-
         /* Is it too large? */
         if (!chunked && // if chunked, we will check as we accumulate
                 clientIsRequestBodyTooLargeForPolicy(request->content_length)) {
@@ -2900,9 +2811,6 @@
     http->doCallouts();
 
 finish:
-    if (!notedUseOfBuffer)
-        connNoteUseOfBuffer(conn, http->req_sz);
-
     /*
      * DPW 2007-05-18
      * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
@@ -2958,7 +2866,6 @@
 bool
 ConnStateData::clientParseRequests()
 {
-    HttpRequestMethod method;
     bool parsed_req = false;
 
     debugs(33, 5, HERE << clientConnection << ": attempting to parse");
@@ -2966,7 +2873,7 @@
     // Loop while we have read bytes that are not needed for producing the body
     // On errors, bodyPipe may become nil, but readMore will be cleared
     while (in.notYetUsed > 0 && !bodyPipe && flags.readMore) {
-        connStripBufferWhitespace(this);
+        connStripBufferWhitespace(this); // XXX: should not be needed anymore.
 
         /* Don't try to parse if the buffer is empty */
         if (in.notYetUsed == 0)
@@ -2982,21 +2889,24 @@
 
         /* Begin the parsing */
         PROF_start(parseHttpRequest);
-        HttpParserInit(&parser_, in.buf, in.notYetUsed);
+
+        // parser is incremental. Generate new parser state if we,
+        // a) dont have one already
+        // b) have completed the previous request parsing already
+        if (!parser_ || parser_->isDone())
+            parser_ = new Http1::RequestParser(in.buf, in.notYetUsed);
+        else // update the buffer space being parsed
+            parser_->bufsiz = in.notYetUsed;
 
         /* Process request */
-        Http::ProtocolVersion http_ver;
-        ClientSocketContext *context = parseHttpRequest(this, &parser_, &method, &http_ver);
+        ClientSocketContext *context = parseHttpRequest(this, *parser_);
+        if (parser_->messageOffset()) {
+            // nothing but prefix garbage in the buffer. consume it.
+            connNoteUseOfBuffer(this, parser_->messageOffset());
+            parser_->noteBufferShift(parser_->messageOffset());
+        }
         PROF_stop(parseHttpRequest);
 
-        /* partial or incomplete request */
-        if (!context) {
-            // TODO: why parseHttpRequest can just return parseHttpRequestAbort
-            // (which becomes context) but checkHeaderLimits cannot?
-            checkHeaderLimits();
-            break;
-        }
-
         /* status -1 or 1 */
         if (context) {
             debugs(33, 5, HERE << clientConnection << ": parsed a request");
@@ -3004,7 +2914,10 @@
                                              CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
             commSetConnTimeout(clientConnection, Config.Timeout.lifetime, timeoutCall);
 
-            clientProcessRequest(this, &parser_, context, method, http_ver);
+            // Request has now been shifted out of the buffer.
+            // Consume header early so that next action starts with just the next bytes.
+            connNoteUseOfBuffer(this, parser_->messageHeaderSize() + parser_->messageOffset());
+            clientProcessRequest(this, *parser_, context);
 
             parsed_req = true; // XXX: do we really need to parse everything right NOW ?
 

=== modified file 'src/client_side.h'
--- src/client_side.h	2013-08-22 18:39:41 +0000
+++ src/client_side.h	2014-01-04 15:11:57 +0000
@@ -35,7 +35,7 @@
 
 #include "comm.h"
 #include "HttpControlMsg.h"
-#include "HttpParser.h"
+#include "http/forward.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
@@ -201,7 +201,6 @@
     void addContextToQueue(ClientSocketContext * context);
     int getConcurrentRequestCount() const;
     bool isOpen() const;
-    void checkHeaderLimits();
 
     // HttpControlMsgSink API
     virtual void sendControlMsg(HttpControlMsg msg);
@@ -398,9 +397,8 @@
     Auth::UserRequest::Pointer auth_;
 #endif
 
-    HttpParser parser_;
-
-    // XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
+    /// the parser state for current HTTP/1.x input buffer processing
+    Http1::RequestParserPointer parser_;
 
 #if USE_SSL
     bool switchedToHttps_;

=== modified file 'src/htcp.h'
--- src/htcp.h	2012-12-30 12:53:01 +0000
+++ src/htcp.h	2013-12-23 16:27:51 +0000
@@ -33,11 +33,9 @@
 #if USE_HTCP
 
 #include "HttpHeader.h"
-#include "HttpRequestMethod.h"
+#include "http/forward.h"
 #include "ip/forward.h"
 
-class HttpRequest;
-
 /// \ingroup ServerProtocolHTCP
 class HtcpReplyData
 {

=== renamed file 'src/HttpParser.cc' => 'src/http/Http1Parser.cc'
--- src/HttpParser.cc	2013-03-16 04:57:43 +0000
+++ src/http/Http1Parser.cc	2014-01-04 18:26:27 +0000
@@ -1,54 +1,167 @@
 #include "squid.h"
 #include "Debug.h"
-#include "HttpParser.h"
+#include "http/Http1Parser.h"
+#include "http/RequestMethod.h"
+#include "mime_header.h"
 #include "profiler/Profiler.h"
 #include "SquidConfig.h"
 
 void
-HttpParser::clear()
+Http1::Parser::clear()
 {
-    state = HTTP_PARSE_NONE;
-    request_parse_status = Http::scNone;
+    completedState_ = HTTP_PARSE_NONE;
     buf = NULL;
     bufsiz = 0;
+    parseOffset_ = 0;
+    msgProtocol_ = AnyP::ProtocolVersion();
+    mimeHeaderBlock_.clear();
+}
+
+void
+Http1::RequestParser::clear()
+{
+    Http1::Parser::clear();
+
+    request_parse_status = Http::scNone;
     req.start = req.end = -1;
-    hdr_start = hdr_end = -1;
     req.m_start = req.m_end = -1;
     req.u_start = req.u_end = -1;
     req.v_start = req.v_end = -1;
-    req.v_maj = req.v_min = 0;
+    method_ = HttpRequestMethod();
 }
 
 void
-HttpParser::reset(const char *aBuf, int len)
+Http1::Parser::reset(const char *aBuf, int len)
 {
     clear(); // empty the state.
-    state = HTTP_PARSE_NEW;
+    completedState_ = HTTP_PARSE_NEW;
     buf = aBuf;
     bufsiz = len;
-    debugs(74, 5, HERE << "Request buffer is " << buf);
-}
-
+    debugs(74, DBG_DATA, "Parse " << Raw("buf", buf, bufsiz));
+}
+
+void
+Http1::RequestParser::noteBufferShift(int64_t n)
+{
+    bufsiz -= n;
+
+    // if parsing done, ignore buffer changes.
+    if (completedState_ == HTTP_PARSE_DONE)
+        return;
+
+    // shift the parser resume point to match buffer content
+    parseOffset_ -= n;
+
+#if WHEN_INCREMENTAL_PARSING
+
+    // if have not yet finished request-line
+    if (completedState_ == HTTP_PARSE_NEW) {
+        // check for and adjust the known request-line offsets.
+
+        /* TODO: when the first-line is parsed incrementally we
+         * will need to recalculate the offsets for req.*
+         * For now, they are all re-calculated based on parserOffset_
+         * with each parse attempt.
+         */
+    }
+
+    // if finished request-line but not mime header
+    // adjust the mime header states
+    if (completedState_ == HTTP_PARSE_FIRST) {
+        /* TODO: when the mime-header is parsed incrementally we
+         * will need to store the initial offset of mime-header block
+         * instead of locatign it from req.end or parseOffset_.
+         * Since req.end may no longer be valid, and parseOffset_ may
+         * have moved into the mime-block interior.
+         */
+    }
+#endif
+}
+
+/**
+ * Attempt to parse the first line of a new request message.
+ *
+ * Governed by RFC 2616 section 4.1
+ *  "
+ *    In the interest of robustness, servers SHOULD ignore any empty
+ *    line(s) received where a Request-Line is expected. In other words, if
+ *    the server is reading the protocol stream at the beginning of a
+ *    message and receives a CRLF first, it should ignore the CRLF.
+ *
+ *    ... To restate what is explicitly forbidden by the
+ *    BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an
+ *    extra CRLF.
+ *  "
+ *
+ * Parsing state is stored between calls to avoid repeating buffer scans.
+ * \return true if garbage whitespace was found
+ */
+bool
+Http1::RequestParser::skipGarbageLines()
+{
+    req.start = parseOffset_; // avoid re-parsing any portion we managed to complete
+
+#if WHEN_RFC_COMPLIANT // CRLF or bare-LF is what RFC 2616 tolerant parsers do ...
+    if (Config.onoff.relaxed_header_parser) {
+        if (Config.onoff.relaxed_header_parser < 0 && (buf[req.start] == '\r' || buf[req.start] == '\n'))
+            debugs(74, DBG_IMPORTANT, "WARNING: Invalid HTTP Request: " <<
+                   "CRLF bytes received ahead of request-line. " <<
+                   "Ignored due to relaxed_header_parser.");
+        // Be tolerant of prefix empty lines
+        for (; req.start < bufsiz && (buf[req.start] == '\n' || ((buf[req.start] == '\r' && (buf[req.start+1] == '\n')); ++req.start);
+        parseOffset_ = req.start;
+    }
+#endif
+
+    /* XXX: this is a Squid-specific tolerance
+     * it appears never to have been relevant outside out unit-tests
+     * because the ConnStateData parser loop starts with consumeWhitespace()
+     * which absorbs any SP HTAB VTAB CR LF characters.
+     * But unit-tests called the HttpParser method directly without that pruning.
+     */
+#if USE_HTTP_VIOLATIONS
+    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);
+        parseOffset_ = req.start;
+    }
+#endif
+
+    return (parseOffset_ > 0);
+}
+
+/**
+ * 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
-HttpParser::parseRequestFirstLine()
+Http1::RequestParser::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);
+    debugs(74, 5, "parsing possible request: bufsiz=" << bufsiz << ", offset=" << parseOffset_);
+    debugs(74, DBG_DATA, Raw("(buf+offset)", buf+parseOffset_, bufsiz-parseOffset_));
 
     // 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.start = parseOffset_; // avoid re-parsing any portion we managed to complete
     req.end = -1;
     for (int i = 0; i < bufsiz; ++i) {
         // track first and last whitespace (SP only)
@@ -100,7 +213,16 @@
             return -1;
         }
     }
+
     if (req.end == -1) {
+        // DoS protection against long first-line
+        if ( (size_t)bufsiz >= Config.maxRequestHeaderSize) {
+            debugs(33, 5, "Too large request-line");
+            // XXX: return URL-too-log status code if second_whitespace is not yet found.
+            request_parse_status = Http::scHeaderTooLarge;
+            return -1;
+        }
+
         debugs(74, 5, "Parser: retval 0: from " << req.start <<
                "->" << req.end << ": needs more data to complete first line.");
         return 0;
@@ -111,6 +233,13 @@
 
     // Input Validation:
 
+    // DoS protection against long first-line
+    if ((size_t)(req.end-req.start) >= Config.maxRequestHeaderSize) {
+        debugs(33, 5, "Too large request-line");
+        request_parse_status = Http::scHeaderTooLarge;
+        return -1;
+    }
+
     // Process what we now know about the line structure into field offsets
     // generating HTTP status for any aborts as we go.
 
@@ -132,6 +261,9 @@
         return -1;
     }
 
+    /* Set method_ */
+    method_ = HttpRequestMethod(&buf[req.m_start], &buf[req.m_end]+1);
+
     // First non-whitespace after first SP = beginning of URL+Version
     if (second_word > line_end || second_word < req.start) {
         request_parse_status = Http::scBadRequest; // missing URI
@@ -142,10 +274,11 @@
     // 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) {
-        req.v_maj = 0;
-        req.v_min = 9;
+        msgProtocol_ = Http::ProtocolVersion(0,9);
         req.u_end = line_end;
         request_parse_status = Http::scOkay; // HTTP/0.9
+        completedState_ = HTTP_PARSE_FIRST;
+        parseOffset_ = line_end;
         return 1;
     } else {
         // otherwise last whitespace is somewhere after end of URI.
@@ -157,6 +290,7 @@
         request_parse_status = Http::scBadRequest; // missing URI
         return -1;
     }
+    uri_.assign(&buf[req.u_start], req.u_end - req.u_start + 1);
 
     // Last whitespace SP = before start of protocol/version
     if (last_whitespace >= line_end) {
@@ -172,10 +306,11 @@
 #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.
-        req.v_maj = 0;
-        req.v_min = 9;
+        msgProtocol_ = Http::ProtocolVersion(0,9);
         req.u_end = line_end;
         request_parse_status = Http::scOkay; // treat as HTTP/0.9
+        completedState_ = HTTP_PARSE_FIRST;
+        parseOffset_ = req.end;
         return 1;
 #else
         // protocol not supported / implemented.
@@ -183,6 +318,7 @@
         return -1;
 #endif
     }
+    msgProtocol_.protocol = AnyP::PROTO_HTTP;
 
     int i = req.v_start + sizeof("HTTP/") -1;
 
@@ -201,7 +337,7 @@
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
-    req.v_maj = maj;
+    msgProtocol_.major = maj;
 
     /* next should be .; we -have- to have this as we have a whole line.. */
     if (buf[i] != '.') {
@@ -228,67 +364,138 @@
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
-    req.v_min = min;
+    msgProtocol_.minor = min;
 
     /*
      * Rightio - we have all the schtuff. Return true; we've got enough.
      */
     request_parse_status = Http::scOkay;
+    parseOffset_ = req.end+1; // req.end is the \n byte. Next parse step needs to start *after* that byte.
+    completedState_ = HTTP_PARSE_FIRST;
     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->req.m_start << "->" <<
-           hmsg->req.m_end << "; url " << hmsg->req.u_start << "->" << hmsg->req.u_end <<
-           "; version " << hmsg->req.v_start << "->" << hmsg->req.v_end << " (" << hmsg->req.v_maj <<
-           "/" << hmsg->req.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
-
+bool
+Http1::RequestParser::parse()
+{
+    // stage 1: locate the request-line
+    if (completedState_ == HTTP_PARSE_NEW) {
+        if (skipGarbageLines() && (size_t)bufsiz < parseOffset_)
+            return false;
+    }
+
+    // stage 2: parse the request-line
+    if (completedState_ == HTTP_PARSE_NEW) {
+        PROF_start(HttpParserParseReqLine);
+        int retcode = parseRequestFirstLine();
+        debugs(74, 5, "request-line: retval " << retcode << ": from " << req.start << "->" << req.end << " " << Raw("line", &buf[req.start], req.end-req.start));
+        debugs(74, 5, "request-line: method " << req.m_start << "->" << req.m_end << " (" << method_ << ")");
+        debugs(74, 5, "request-line: url " << req.u_start << "->" << req.u_end << " (" << uri_ << ")");
+        debugs(74, 5, "request-line: proto " << req.v_start << "->" << req.v_end << " (" << msgProtocol_ << ")");
+        debugs(74, 5, "Parser: parse-offset=" << parseOffset_);
+        PROF_stop(HttpParserParseReqLine);
+        if (retcode < 0) {
+            completedState_ = HTTP_PARSE_DONE;
+            return false;
+        }
+    }
+
+    // stage 3: locate the mime header block
+    if (completedState_ == HTTP_PARSE_FIRST) {
+        // HTTP/1.x request-line is valid and parsing completed.
+        if (msgProtocol_.major == 1) {
+            /* NOTE: HTTP/0.9 requests do not have a mime header block.
+             *       So the rest of the code will need to deal with '0'-byte headers
+             *       (ie, none, so don't try parsing em)
+             */
+            int64_t mimeHeaderBytes = 0;
+            if ((mimeHeaderBytes = headersEnd(buf+parseOffset_, bufsiz-parseOffset_)) == 0) {
+                if (bufsiz-parseOffset_ >= Config.maxRequestHeaderSize) {
+                    debugs(33, 5, "Too large request");
+                    request_parse_status = Http::scHeaderTooLarge;
+                    completedState_ = HTTP_PARSE_DONE;
+                } else
+                    debugs(33, 5, "Incomplete request, waiting for end of headers");
+                return false;
+            }
+            mimeHeaderBlock_.assign(&buf[req.end+1], mimeHeaderBytes);
+
+        } else
+            debugs(33, 3, "Missing HTTP/1.x identifier");
+
+        // NP: planned name for this stage is HTTP_PARSE_MIME
+        // but we do not do any further stages here yet so go straight to DONE
+        completedState_ = HTTP_PARSE_DONE;
+
+        // Squid could handle these headers, but admin does not want to
+        if (messageHeaderSize() >= Config.maxRequestHeaderSize) {
+            debugs(33, 5, "Too large request");
+            request_parse_status = Http::scHeaderTooLarge;
+            return false;
+        }
+    }
+
+    return isDone();
+}
+
+// arbitrary maximum-length for headers which can be found by Http1Parser::getHeaderField()
+#define GET_HDR_SZ	1024
+
+char *
+Http1::Parser::getHeaderField(const char *name)
+{
+    LOCAL_ARRAY(char, header, GET_HDR_SZ);
+    const char *p = NULL;
+    char *q = NULL;
+    char got = 0;
+    const int namelen = name ? strlen(name) : 0;
+
+    if (!headerBlockSize() || !name)
+        return NULL;
+
+    debugs(25, 5, "looking for '" << name << "'");
+
+    for (p = rawHeaderBuf(); *p; p += strcspn(p, "\n\r")) {
+        if (strcmp(p, "\r\n\r\n") == 0 || strcmp(p, "\n\n") == 0)
+            return NULL;
+
+        while (xisspace(*p))
+            ++p;
+
+        if (strncasecmp(p, name, namelen))
+            continue;
+
+        if (!xisspace(p[namelen]) && p[namelen] != ':')
+            continue;
+
+        int l = strcspn(p, "\n\r") + 1;
+
+        if (l > GET_HDR_SZ)
+            l = GET_HDR_SZ;
+
+        xstrncpy(header, p, l);
+
+        debugs(25, 5, "checking '" << header << "'");
+
+        q = header;
+
+        q += namelen;
+
+        if (*q == ':') {
+            ++q;
+            got = 1;
+        }
+
+        while (xisspace(*q)) {
+            ++q;
+            got = 1;
+        }
+
+        if (got) {
+            debugs(25, 5, "returning '" << q << "'");
+            return q;
+        }
+    }
+
+    return NULL;
+}

=== renamed file 'src/HttpParser.h' => 'src/http/Http1Parser.h'
--- src/HttpParser.h	2013-03-16 04:57:43 +0000
+++ src/http/Http1Parser.h	2014-01-04 23:14:55 +0000
@@ -1,97 +1,161 @@
-#ifndef _SQUID_SRC_HTTPPARSER_H
-#define _SQUID_SRC_HTTPPARSER_H
+#ifndef _SQUID_SRC_HTTP_ONEREQUESTPARSER_H
+#define _SQUID_SRC_HTTP_ONEREQUESTPARSER_H
 
+#include "base/RefCount.h"
+#include "http/forward.h"
+#include "http/ProtocolVersion.h"
+#include "http/RequestMethod.h"
 #include "http/StatusCode.h"
+#include "SBuf.h"
+
+namespace Http {
+namespace One {
 
 // Parser states
 #define HTTP_PARSE_NONE   0 // nothing. completely unset state.
 #define HTTP_PARSE_NEW    1 // initialized, but nothing usefully parsed yet.
+#define HTTP_PARSE_FIRST  2 // have parsed request first line
+#define HTTP_PARSE_MIME   3 // have located end of mime header block
+#define HTTP_PARSE_DONE   99 // have done with parsing so far
 
 /** 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:
+ * Works on a raw character I/O buffer and separates the content into
+ * either an error state or HTTP procotol major sections:
  *
- * \item Request Line (method, URL, protocol, version)
- * \item Mime header block
+ * \item first-line (request-line / simple-request / status-line)
+ * \item mime-header block
  */
-class HttpParser
+class Parser : public RefCountable
 {
 public:
-    HttpParser() { clear(); }
+    Parser() { clear(); }
 
     /** Initialize a new parser.
-     * Presenting it a buffer to work on and the current length of available
-     * data.
+     * 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); };
+    Parser(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();
+    virtual void clear();
 
     /// Reset the parser for use on a new buffer.
     void reset(const char *aBuf, int len);
 
+    /** Adjust parser state to account for a buffer shift of n bytes.
+     *
+     * The leftmost n bytes bytes have been dropped and all other
+     * bytes shifted left n positions.
+     */
+    virtual void noteBufferShift(int64_t n) = 0;
+
+    /** Whether the parser is already done processing the buffer.
+     * Use to determine between incomplete data and errors results
+     * from the parse.
+     */
+    bool isDone() const {return completedState_==HTTP_PARSE_DONE;}
+
+    /// number of bytes in buffer before the message
+    virtual int64_t messageOffset() const = 0;
+
+    /// size in bytes of the first line including CRLF terminator
+    virtual int64_t firstLineSize() const = 0;
+
+    /// size in bytes of the message headers including CRLF terminator(s)
+    /// but excluding first-line bytes
+    int64_t headerBlockSize() const {return mimeHeaderBlock_.length();}
+
+    /// size in bytes of HTTP message block, includes first-line and mime headers
+    /// excludes any body/entity/payload bytes
+    /// excludes any garbage prefix before the first-line
+    int64_t messageHeaderSize() const {return firstLineSize() + headerBlockSize();}
+
+    /// buffer containing HTTP mime headers, excluding message first-line.
+    const char *rawHeaderBuf() {return mimeHeaderBlock_.c_str();}
+
+    /// attempt to parse a message from the buffer
+    virtual bool parse() = 0;
+
+    /// the protocol label for this message
+    const AnyP::ProtocolVersion & messageProtocol() const {return msgProtocol_;}
+
     /**
-     * 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
+     * \return A pointer to a field-value of the first matching field-name, or NULL.
      */
-    int parseRequestFirstLine();
+    char *getHeaderField(const char *name);
 
 public:
-    uint8_t state;
     const char *buf;
     int bufsiz;
 
+protected:
+    /// what stage the parser is currently up to
+    uint8_t completedState_;
+
+    /// what protocol label has been found in the first line
+    AnyP::ProtocolVersion msgProtocol_;
+
+    /// byte offset for non-parsed region of the buffer
+    size_t parseOffset_;
+
+    /// buffer holding the mime headers
+    SBuf mimeHeaderBlock_;
+};
+
+/** HTTP protocol request 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 RequestParser : public Http1::Parser
+{
+public:
+    /* Http::One::Parser API */
+    RequestParser() : Parser() {}
+    RequestParser(const char *aBuf, int len) : Parser(aBuf, len) {}
+    virtual void clear();
+    virtual void noteBufferShift(int64_t n);
+    virtual int64_t messageOffset() const {return req.start;}
+    virtual int64_t firstLineSize() const {return req.end - req.start + 1;}
+    virtual bool parse();
+
+    /// the HTTP method if this is a request message
+    const HttpRequestMethod & method() const {return method_;}
+
+    /// the request-line URI if this is a request message, or an empty string.
+    const SBuf &requestUri() const {return uri_;}
+
+    /** HTTP status code to be used on the invalid-request error page
+     * Http::scNone indicates incomplete parse, Http::scOkay indicates no error.
+     */
+    Http::StatusCode request_parse_status;
+
+private:
+    bool skipGarbageLines();
+    int parseRequestFirstLine();
+
     /// Offsets for pieces of the (HTTP request) Request-Line as per RFC 2616
     struct request_offsets {
         int start, end;
         int m_start, m_end; // method
         int u_start, u_end; // url
         int v_start, v_end; // version (full text)
-        int v_maj, v_min;   // version numerics
     } req;
 
-    // Offsets for pieces of the MiME Header segment
-    int hdr_start, hdr_end;
-
-    // TODO: Offsets for pieces of the (HTTP reply) Status-Line as per RFC 2616
-
-    /** HTTP status code to be used on the invalid-request error page
-     * Http::scNone indicates incomplete parse, Http::scOkay indicates no error.
-     */
-    Http::StatusCode request_parse_status;
+    /// what request method has been found on the first line
+    HttpRequestMethod method_;
+
+    /// raw copy of the origina client reqeust-line URI field
+    SBuf uri_;
 };
 
-// Legacy functions
-#define HttpParserInit(h,b,l) (h)->reset((b),(l))
-int HttpParserParseReqLine(HttpParser *hp);
-
-#define MSGDODEBUG 0
-#if MSGDODEBUG
-int HttpParserReqSz(HttpParser *);
-int HttpParserHdrSz(HttpParser *);
-const char * HttpParserHdrBuf(HttpParser *);
-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 */
+} // namespace One
+} // namespace Http
+
+#endif /*  _SQUID_SRC_HTTP_HTTP1PARSER_H */

=== modified file 'src/http/Makefile.am'
--- src/http/Makefile.am	2013-03-18 04:55:51 +0000
+++ src/http/Makefile.am	2014-01-02 23:24:27 +0000
@@ -4,9 +4,14 @@
 noinst_LTLIBRARIES = libsquid-http.la
 
 libsquid_http_la_SOURCES = \
+	forward.h \
+	Http1Parser.cc \
+	Http1Parser.h \
 	MethodType.cc \
 	MethodType.h \
 	ProtocolVersion.h \
+	RequestMethod.cc \
+	RequestMethod.h \
 	StatusCode.cc \
 	StatusCode.h \
 	StatusLine.cc \

=== renamed file 'src/HttpRequestMethod.cc' => 'src/http/RequestMethod.cc'
--- src/HttpRequestMethod.cc	2013-12-18 00:48:33 +0000
+++ src/http/RequestMethod.cc	2013-12-23 16:27:27 +0000
@@ -3,7 +3,7 @@
  */
 
 #include "squid.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "SquidConfig.h"
 #include "wordlist.h"
 

=== renamed file 'src/HttpRequestMethod.h' => 'src/http/RequestMethod.h'
--- src/HttpRequestMethod.h	2012-10-26 11:36:45 +0000
+++ src/http/RequestMethod.h	2013-12-23 18:02:41 +0000
@@ -1,11 +1,9 @@
 #ifndef SQUID_HTTPREQUESTMETHOD_H
 #define SQUID_HTTPREQUESTMETHOD_H
 
+#include "http/forward.h"
 #include "http/MethodType.h"
 #include "SquidString.h"
-#include "SquidString.h"
-
-class SquidConfig;
 
 #include <iosfwd>
 
@@ -15,14 +13,10 @@
  * It has a runtime extension facility to allow it to
  * efficiently support new methods
  */
-class HttpRequestMethod
+class HttpRequestMethod : public RefCountable
 {
-
 public:
-//    static void Configure(SquidConfig &Config);
-
     HttpRequestMethod() : theMethod(Http::METHOD_NONE), theImage() {}
-
     HttpRequestMethod(Http::MethodType const aMethod) : theMethod(aMethod), theImage() {}
 
     /**

=== added file 'src/http/forward.h'
--- src/http/forward.h	1970-01-01 00:00:00 +0000
+++ src/http/forward.h	2014-01-04 11:39:16 +0000
@@ -0,0 +1,27 @@
+#ifndef SQUID_SRC_HTTP_FORWARD_H
+#define SQUID_SRC_HTTP_FORWARD_H
+
+#include "base/RefCount.h"
+
+// TODO move these classes into Http namespace
+class HttpRequestMethod;
+typedef RefCount<HttpRequestMethod> HttpRequestMethodPointer;
+
+class HttpRequest;
+typedef RefCount<HttpRequest> HttpRequestPointer;
+
+class HttpReply;
+typedef RefCount<HttpReply> HttpReplyPointer;
+
+namespace Http {
+
+namespace One {
+class RequestParser;
+typedef RefCount<Http::One::RequestParser> RequestParserPointer;
+} // namespace One
+
+} // namespace Http
+
+namespace Http1 = Http::One;
+
+#endif /* SQUID_SRC_HTTP_FORWARD_H */

=== modified file 'src/mgr/ActionParams.h'
--- src/mgr/ActionParams.h	2012-10-26 11:36:45 +0000
+++ src/mgr/ActionParams.h	2013-12-23 16:25:42 +0000
@@ -6,7 +6,7 @@
 #ifndef SQUID_MGR_ACTION_PARAMS_H
 #define SQUID_MGR_ACTION_PARAMS_H
 
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "ipc/forward.h"
 #include "mgr/QueryParams.h"
 #include "RequestFlags.h"

=== modified file 'src/mgr/ActionWriter.h'
--- src/mgr/ActionWriter.h	2012-09-01 14:38:36 +0000
+++ src/mgr/ActionWriter.h	2013-12-23 16:26:01 +0000
@@ -7,7 +7,6 @@
 #define SQUID_MGR_ACTION_WRITER_H
 
 #include "comm/forward.h"
-#include "HttpRequestMethod.h"
 #include "mgr/StoreToCommWriter.h"
 
 namespace Mgr

=== modified file 'src/mgr/Filler.h'
--- src/mgr/Filler.h	2012-09-01 14:38:36 +0000
+++ src/mgr/Filler.h	2013-12-23 16:26:11 +0000
@@ -7,7 +7,6 @@
 #define SQUID_MGR_FILLER_H
 
 #include "comm/forward.h"
-#include "HttpRequestMethod.h"
 #include "mgr/Action.h"
 #include "mgr/StoreToCommWriter.h"
 

=== modified file 'src/mime.cc'
--- src/mime.cc	2013-12-19 04:53:35 +0000
+++ src/mime.cc	2014-01-04 23:15:54 +0000
@@ -51,8 +51,6 @@
 #include <sys/stat.h>
 #endif
 
-#define GET_HDR_SZ 1024
-
 /* forward declarations */
 static void mimeFreeMemory(void);
 static char const *mimeGetIcon(const char *fn);

=== modified file 'src/mime_header.cc'
--- src/mime_header.cc	2012-08-29 12:36:10 +0000
+++ src/mime_header.cc	2013-12-31 03:43:08 +0000
@@ -31,91 +31,9 @@
  */
 
 #include "squid.h"
-
-#define GET_HDR_SZ 1024
 #include "Debug.h"
 #include "profiler/Profiler.h"
 
-/*
- * returns a pointer to a field-value of the first matching field-name where
- * field-value matches prefix if any
- */
-char *
-mime_get_header_field(const char *mime, const char *name, const char *prefix)
-{
-    LOCAL_ARRAY(char, header, GET_HDR_SZ);
-    const char *p = NULL;
-    char *q = NULL;
-    char got = 0;
-    const int namelen = name ? strlen(name) : 0;
-    const int preflen = prefix ? strlen(prefix) : 0;
-    int l;
-
-    if (NULL == mime)
-        return NULL;
-
-    assert(NULL != name);
-
-    debugs(25, 5, "mime_get_header: looking for '" << name << "'");
-
-    for (p = mime; *p; p += strcspn(p, "\n\r")) {
-        if (strcmp(p, "\r\n\r\n") == 0 || strcmp(p, "\n\n") == 0)
-            return NULL;
-
-        while (xisspace(*p))
-            ++p;
-
-        if (strncasecmp(p, name, namelen))
-            continue;
-
-        if (!xisspace(p[namelen]) && p[namelen] != ':')
-            continue;
-
-        l = strcspn(p, "\n\r") + 1;
-
-        if (l > GET_HDR_SZ)
-            l = GET_HDR_SZ;
-
-        xstrncpy(header, p, l);
-
-        debugs(25, 5, "mime_get_header: checking '" << header << "'");
-
-        q = header;
-
-        q += namelen;
-
-        if (*q == ':') {
-            ++q;
-            got = 1;
-        }
-
-        while (xisspace(*q)) {
-            ++q;
-            got = 1;
-        }
-
-        if (got && prefix) {
-            /* we could process list entries here if we had strcasestr(). */
-            /* make sure we did not match a part of another field-value */
-            got = !strncasecmp(q, prefix, preflen) && !xisalpha(q[preflen]);
-        }
-
-        if (got) {
-            debugs(25, 5, "mime_get_header: returning '" << q << "'");
-            return q;
-        }
-    }
-
-    return NULL;
-}
-
-/* returns a pointer to a field-value of the first matching field-name */
-char *
-mime_get_header(const char *mime, const char *name)
-{
-    return mime_get_header_field(mime, name, NULL);
-}
-
 size_t
 headersEnd(const char *mime, size_t l)
 {

=== modified file 'src/mime_header.h'
--- src/mime_header.h	2012-09-21 14:57:30 +0000
+++ src/mime_header.h	2013-12-31 03:43:08 +0000
@@ -33,8 +33,6 @@
 #ifndef SQUID_MIME_HEADER_H_
 #define SQUID_MIME_HEADER_H_
 
-char *mime_get_header(const char *mime, const char *header);
-char *mime_get_header_field(const char *mime, const char *name, const char *prefix);
 size_t headersEnd(const char *, size_t);
 
 #endif /* SQUID_MIME_HEADER_H_ */

=== modified file 'src/tests/stub_client_side.cc'
--- src/tests/stub_client_side.cc	2013-06-27 15:58:46 +0000
+++ src/tests/stub_client_side.cc	2014-01-04 15:12:25 +0000
@@ -39,7 +39,6 @@
 void ConnStateData::addContextToQueue(ClientSocketContext * context) STUB
 int ConnStateData::getConcurrentRequestCount() const STUB_RETVAL(0)
 bool ConnStateData::isOpen() const STUB_RETVAL(false)
-void ConnStateData::checkHeaderLimits() STUB
 void ConnStateData::sendControlMsg(HttpControlMsg msg) STUB
 char *ConnStateData::In::addressToReadInto() const STUB_RETVAL(NULL)
 int64_t ConnStateData::mayNeedToReadMoreBody() const STUB_RETVAL(0)

=== renamed file 'src/tests/testHttpParser.cc' => 'src/tests/testHttp1Parser.cc'
--- src/tests/testHttpParser.cc	2013-11-18 17:03:55 +0000
+++ src/tests/testHttp1Parser.cc	2014-01-04 14:51:10 +0000
@@ -3,16 +3,21 @@
 
 #include <cppunit/TestAssert.h>
 
-#include "HttpParser.h"
+#define private public
+#define protected public
+
+#include "testHttp1Parser.h"
+#include "http/Http1Parser.h"
+#include "http/RequestMethod.h"
 #include "Mem.h"
 #include "MemBuf.h"
 #include "SquidConfig.h"
-#include "testHttpParser.h"
+#include "testHttp1Parser.h"
 
-CPPUNIT_TEST_SUITE_REGISTRATION( testHttpParser );
+CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser );
 
 void
-testHttpParser::globalSetup()
+testHttp1Parser::globalSetup()
 {
     static bool setup_done = false;
     if (setup_done)
@@ -20,16 +25,21 @@
 
     Mem::Init();
     setup_done = true;
+
+    // default to strict parser. set for loose parsing specifically where behaviour differs.
+    Config.onoff.relaxed_header_parser = 0;
+
+    Config.maxRequestHeaderSize = 1024; // XXX: unit test the RequestParser handling of this limit
 }
 
 void
-testHttpParser::testParseRequestLineProtocols()
+testHttp1Parser::testParseRequestLineProtocols()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http1::RequestParser output;
     input.init();
 
     // TEST: Do we comply with RFC 1945 section 5.1 ?
@@ -39,7 +49,8 @@
     {
         input.append("GET /\r\n", 7);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -47,13 +58,13 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start], (output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start], (output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
         input.reset();
     }
 
@@ -62,21 +73,22 @@
     {
         input.append("POST /\r\n", 7);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
-        CPPUNIT_ASSERT_EQUAL(0,memcmp("GET /\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
+        CPPUNIT_ASSERT_EQUAL(0,memcmp("POST /\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
-        CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
-        CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start], (output.req.m_end-output.req.m_start+1)));
-        CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
-        CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
+        CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(0, memcmp("POST", &output.buf[output.req.m_start], (output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_POST), output.method_);
+        CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
+        CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start], (output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 #endif
@@ -85,7 +97,9 @@
     {
         input.append("GET / HTTP/1.0\r\n", 16);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -93,14 +107,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -108,7 +122,9 @@
     {
         input.append("GET / HTTP/1.1\r\n", 16);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -116,22 +132,25 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
     // RFC 2616 : future version full-request
-    {    input.append("GET / HTTP/1.2\r\n", 16);
+    {
+        input.append("GET / HTTP/1.2\r\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -139,24 +158,26 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.2", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(2, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2), output.msgProtocol_);
         input.reset();
     }
 
     // RFC 2616 : future version full-request
     {
-        // XXX: IETF HTTPbis WG has made this two-digits format invalid.
+        // IETF HTTPbis WG has made this two-digits format invalid.
+        // it gets treated same as HTTP/0.9 for now
         input.append("GET / HTTP/10.12\r\n", 18);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parse()); // BUG: declares true
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -164,14 +185,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(15, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/10.12", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(10, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(12, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,10,12), output.msgProtocol_);
         input.reset();
     }
 
@@ -182,19 +203,19 @@
         //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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(12, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/ FOO/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
 #else
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
 #endif
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -202,6 +223,7 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
@@ -214,7 +236,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -222,14 +245,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(10, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -238,7 +261,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -246,14 +270,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -262,7 +286,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -270,14 +295,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/11", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -286,7 +311,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -294,14 +320,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(19, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/-999999.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -310,7 +336,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -318,14 +345,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -334,7 +361,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -342,26 +370,26 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(19, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.-999999", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
         input.reset();
     }
 }
 
 void
-testHttpParser::testParseRequestLineStrange()
+testHttp1Parser::testParseRequestLineStrange()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http1::RequestParser output;
     input.init();
 
     // space padded URL
@@ -369,7 +397,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -377,14 +407,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(11, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(18, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -393,7 +423,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -401,14 +433,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(9, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/fo o/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(11, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(18, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -417,7 +449,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-5, output.req.end);
@@ -425,26 +459,26 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end); // strangeness generated by following RFC
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(10, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(17, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 }
 
 void
-testHttpParser::testParseRequestLineTerminators()
+testHttp1Parser::testParseRequestLineTerminators()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http1::RequestParser output;
     input.init();
 
     // alternative EOL sequence: NL-only
@@ -452,7 +486,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -460,14 +496,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -476,7 +512,8 @@
         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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-2, output.req.end);
@@ -484,14 +521,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -502,7 +539,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -510,15 +549,16 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
+        Config.onoff.relaxed_header_parser = 0;
     }
 
     // STRICT alternative EOL sequence: multi-CR-NL
@@ -528,7 +568,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
@@ -538,8 +579,7 @@
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -550,7 +590,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -558,13 +599,13 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(13, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/ HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -573,81 +614,85 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 }
 
 void
-testHttpParser::testParseRequestLineMethods()
+testHttp1Parser::testParseRequestLineMethods()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http1::RequestParser output;
     input.init();
 
     // RFC 2616 : . method
@@ -655,7 +700,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -663,14 +710,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp(".", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(".", NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(2, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(4, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(11, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -679,7 +726,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -687,14 +736,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(6, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("OPTIONS", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_OPTIONS), output.method_);
         CPPUNIT_ASSERT_EQUAL(8, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(8, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("*", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(10, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(17, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -703,7 +752,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -711,14 +762,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(9, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HELLOWORLD", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("HELLOWORLD",NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(11, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(11, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(13, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(20, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -727,19 +778,20 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("A\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -747,19 +799,20 @@
     {
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -769,7 +822,9 @@
         //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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(1, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -777,15 +832,16 @@
         CPPUNIT_ASSERT_EQUAL(1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
+        Config.onoff.relaxed_header_parser = 0;
     }
 
     // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte)
@@ -794,19 +850,20 @@
         //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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp(" GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -815,7 +872,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -823,26 +882,26 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("\tGET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(&output.buf[output.req.m_start],&output.buf[output.req.m_end+1]), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 }
 
 void
-testHttpParser::testParseRequestLineInvalid()
+testHttp1Parser::testParseRequestLineInvalid()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http1::RequestParser output;
     input.init();
 
     // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
@@ -851,7 +910,8 @@
         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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -859,13 +919,13 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("/",NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(2, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(9, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
         input.reset();
     }
 
@@ -874,9 +934,11 @@
         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)
+        // BUG: 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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
+//        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_NEW, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(1, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -884,14 +946,15 @@
         CPPUNIT_ASSERT_EQUAL(1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(1, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("/",NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(3, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(10, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
         input.reset();
+        Config.onoff.relaxed_header_parser = 0;
     }
 
     // STRICT no method (an invalid format)
@@ -901,19 +964,20 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp(" / HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
         input.reset();
     }
 
@@ -922,7 +986,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -930,14 +996,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\x0B", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+//        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("GET\0x0B",NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -947,18 +1013,19 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -967,7 +1034,9 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(false, output.isDone());
+        CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -975,14 +1044,14 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\0", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+//        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("GET\0",NULL), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(1, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
         input.reset();
     }
 
@@ -991,7 +1060,8 @@
         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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -999,13 +1069,13 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(12, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
         input.reset();
     }
 
@@ -1014,7 +1084,8 @@
         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(true, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -1022,13 +1093,13 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
         CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(11, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(9, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
         input.reset();
     }
 
@@ -1037,19 +1108,20 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("\xB\xC\xE\xF\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -1060,7 +1132,8 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
@@ -1068,12 +1141,12 @@
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("\t", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(&output.buf[output.req.m_start],&output.buf[output.req.m_end+1]), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 
@@ -1084,18 +1157,81 @@
         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(false, output.parse());
+        CPPUNIT_ASSERT_EQUAL(true, output.isDone());
         CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
         CPPUNIT_ASSERT_EQUAL(0, output.req.start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
+        CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
         CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_maj);
-        CPPUNIT_ASSERT_EQUAL(0, output.req.v_min);
+        CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
         input.reset();
     }
 }
+
+void
+testHttp1Parser::testDripFeed()
+{
+    // Simulate a client drip-feeding Squid a few bytes at a time.
+    // extend the size of the buffer from 0 bytes to full request length
+    // calling the parser repeatedly as visible data grows.
+
+    MemBuf mb;
+    mb.init(1024, 1024);
+    mb.append("            ", 12);
+    int garbageEnd = mb.contentSize();
+    mb.append("GET http://example.com/ HTTP/1.1\r\n", 34);
+    int reqLineEnd = mb.contentSize();
+    mb.append("Host: example.com\r\n\r\n.", 22);
+
+    Http1::RequestParser hp(mb.content(), 0);
+
+    // only relaxed parser accepts the garbage whitespace
+    Config.onoff.relaxed_header_parser = 1;
+
+    for (; hp.bufsiz <= mb.contentSize(); ++hp.bufsiz) {
+        bool parseResult = hp.parse();
+
+#if WHEN_TEST_DEBUG_IS_NEEDED
+        printf("%d/%d :: %d, %d, %d '%c'\n", hp.bufsiz, mb.contentSize(),
+               garbageEnd, reqLineEnd, parseResult,
+               mb.content()[hp.bufsiz]);
+#endif
+
+	// before end of garbage found its a moving offset.
+	if (hp.bufsiz < garbageEnd) {
+            CPPUNIT_ASSERT_EQUAL(hp.bufsiz, (int)hp.parseOffset_);
+            CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
+            continue;
+        }
+
+	// before request line found, parse announces incomplete
+        if (hp.bufsiz < reqLineEnd) {
+            CPPUNIT_ASSERT_EQUAL(garbageEnd, (int)hp.parseOffset_);
+            CPPUNIT_ASSERT_EQUAL(false, parseResult);
+            CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
+            CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_NEW, hp.completedState_);
+            continue;
+        }
+
+	// before request headers entirely found, parse announces incomplete
+        if (hp.bufsiz < mb.contentSize()-1) {
+            CPPUNIT_ASSERT_EQUAL(reqLineEnd, (int)hp.parseOffset_);
+            CPPUNIT_ASSERT_EQUAL(false, parseResult);
+            CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
+            // TODO: add all the other usual tests for request-line details
+            CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, hp.completedState_);
+            continue;
+        }
+
+        // once request line is found (AND the following \n) current parser announces success
+        CPPUNIT_ASSERT_EQUAL(reqLineEnd, (int)hp.parseOffset_);
+        CPPUNIT_ASSERT_EQUAL(true, parseResult);
+        CPPUNIT_ASSERT_EQUAL(true, hp.isDone());
+    }
+}

=== renamed file 'src/tests/testHttpParser.h' => 'src/tests/testHttp1Parser.h'
--- src/tests/testHttpParser.h	2012-06-13 03:17:53 +0000
+++ src/tests/testHttp1Parser.h	2013-12-23 11:36:29 +0000
@@ -1,16 +1,17 @@
-#ifndef SQUID_SRC_TESTS_TESTHTTPPARSER_H
-#define SQUID_SRC_TESTS_TESTHTTPPARSER_H
+#ifndef SQUID_SRC_TESTS_TESTHTTP1PARSER_H
+#define SQUID_SRC_TESTS_TESTHTTP1PARSER_H
 
 #include <cppunit/extensions/HelperMacros.h>
 
-class testHttpParser : public CPPUNIT_NS::TestFixture
+class testHttp1Parser : public CPPUNIT_NS::TestFixture
 {
-    CPPUNIT_TEST_SUITE( testHttpParser );
+    CPPUNIT_TEST_SUITE( testHttp1Parser );
     CPPUNIT_TEST( testParseRequestLineTerminators );
     CPPUNIT_TEST( testParseRequestLineMethods );
     CPPUNIT_TEST( testParseRequestLineProtocols );
     CPPUNIT_TEST( testParseRequestLineStrange );
     CPPUNIT_TEST( testParseRequestLineInvalid );
+    CPPUNIT_TEST( testDripFeed );
     CPPUNIT_TEST_SUITE_END();
 
 protected:
@@ -22,6 +23,8 @@
     void testParseRequestLineProtocols();   // protocol tokens handled correctly
     void testParseRequestLineStrange();     // strange but valid lines accepted
     void testParseRequestLineInvalid();     // rejection of invalid lines happens
+
+    void testDripFeed(); // test incremental parse works
 };
 
 #endif

=== modified file 'src/tests/testHttpRequestMethod.cc'
--- src/tests/testHttpRequestMethod.cc	2013-12-18 03:00:01 +0000
+++ src/tests/testHttpRequestMethod.cc	2013-12-23 16:24:57 +0000
@@ -3,7 +3,7 @@
 #include "squid.h"
 #include <cppunit/TestAssert.h>
 
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "Mem.h"
 #include "SquidConfig.h"
 #include "testHttpRequestMethod.h"


