=== 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
@@ -19,41 +19,41 @@
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 #ifndef SQUID_HTTPACCESSLOGENTRY_H
 #define SQUID_HTTPACCESSLOGENTRY_H
 
 #include "anyp/PortCfg.h"
 #include "base/RefCount.h"
 #include "comm/Connection.h"
 #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"
 #include "MessageSizes.h"
 #include "Notes.h"
 #if ICAP_CLIENT
 #include "adaptation/icap/Elements.h"
 #endif
 #if USE_SSL
 #include "ssl/gadgets.h"
 #endif
 
 /* forward decls */
 class HttpReply;
 class HttpRequest;
 class CustomLog;
 
 class AccessLogEntry: public RefCountable
 {
 

=== 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
@@ -16,87 +16,89 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_HTTPMSG_H
 #define SQUID_HTTPMSG_H
 
 #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
 {
 
 public:
     typedef RefCount<HttpMsg> Pointer;
 
     HttpMsg(http_hdr_owner_type owner);
     virtual ~HttpMsg();
 
     virtual void reset() = 0; // will have body when http*Clean()s are gone
 
     void packInto(Packer * p, bool full_uri) const;
 
     ///< produce a message copy, except for a few connection-specific settings
     virtual HttpMsg *clone() const = 0; ///< \todo rename: not a true copy?
 
     /// [re]sets Content-Length header and cached value
     void setContentLength(int64_t clen);
 
     /**
      * \retval true  the message sender asks to keep the connection open.
      * \retval false the message sender will close the connection.
      *
      * Factors other than the headers may result in connection closure.
      */
     bool persistent() const;
 
 public:
+    /// transport protocol version for this message
     Http::ProtocolVersion http_ver;
 
     HttpHeader header;
 
     HttpHdrCc *cache_control;
 
     /* Unsupported, writable, may disappear/change in the future
      * For replies, sums _stored_ status-line, headers, and <CRLF>.
      * Also used to report parsed header size if parse() is successful */
     int hdr_sz;
 
     int64_t content_length;
 
+    /// URL scheme protocol (if relevant)
     AnyP::ProtocolType protocol;
 
     HttpMsgParseState pstate;   /* the current parsing state */
 
     BodyPipe::Pointer body_pipe; // optional pipeline to receive message body
 
     // returns true and sets hdr_sz on success
     // returns false and sets *error to zero when needs more data
     // returns false and sets *error to a positive Http::StatusCode on error
     bool parse(MemBuf *buf, bool eol, Http::StatusCode *error);
 
     bool parseCharBuf(const char *buf, ssize_t end);
 
     int httpMsgParseStep(const char *buf, int len, int atEnd);
 
     virtual int httpMsgParseError();
 
     virtual bool expectingBody(const HttpRequestMethod&, int64_t&) const = 0;
 
     void firstLineBuf(MemBuf&);

=== 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
@@ -19,41 +19,41 @@
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_HTTPREQUEST_H
 #define SQUID_HTTPREQUEST_H
 
 #include "base/CbcPointer.h"
 #include "Debug.h"
 #include "err_type.h"
 #include "HierarchyLogEntry.h"
 #include "HttpMsg.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "Notes.h"
 #include "RequestFlags.h"
 
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #if USE_ADAPTATION
 #include "adaptation/History.h"
 #endif
 #if ICAP_CLIENT
 #include "adaptation/icap/History.h"
 #endif
 #if USE_SQUID_EUI
 #include "eui/Eui48.h"
 #include "eui/Eui64.h"
 #endif
 
 class ConnStateData;
 
 /*  Http Request */

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2013-12-17 17:05:17 +0000
+++ src/Makefile.am	2013-12-30 22:04:52 +0000
@@ -389,50 +389,46 @@
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrSc.h \
 	HttpHdrScTarget.cc \
 	HttpHdrScTarget.h \
 	HttpHdrContRange.cc \
 	HttpHdrContRange.h \
 	HttpHeaderStat.h \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderMask.h \
 	HttpHeaderRange.h \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	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 \
 	icp_v3.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	ipcache.h \
 	$(LEAKFINDERSOURCE) \
 	SquidList.h \
 	SquidList.cc \
 	LogTags.h \
 	lookup_t.h \
 	main.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	Mem.h \
@@ -723,41 +720,41 @@
 	int.h \
 	int.cc \
 	Mem.h \
 	mem.cc \
 	MemBuf.cc \
 	MemBuf.cci \
 	MemBuf.h \
 	Parsing.h \
 	store_key_md5.h \
 	store_key_md5.cc \
 	tests/stub_StoreMeta.cc \
 	StoreMetaUnpacker.cc \
 	String.cc \
 	SquidNew.cc \
 	tests/stub_time.cc \
 	ufsdump.cc \
 	dlink.h \
 	dlink.cc \
 	HelperChildConfig.h \
 	tests/stub_HelperChildConfig.cc \
-	HttpRequestMethod.cc \
+	http/RequestMethod.cc \
 	RemovalPolicy.cc \
 	$(WIN32_SOURCE) \
 	fd.h \
 	tests/stub_fd.cc
 ufsdump_LDADD = \
 	ident/libident.la \
 	acl/libacls.la \
 	eui/libeui.la \
 	acl/libstate.la \
 	acl/libapi.la \
 	base/libbase.la \
 	libsquid.la \
 	ip/libip.la \
 	fs/libfs.la \
 	ipc/libipc.la \
 	mgr/libmgr.la \
 	$(XTRA_OBJS) \
 	$(REPL_OBJS) \
 	$(CRYPTLIB) \
 	$(REGEXLIB) \
@@ -1050,41 +1047,41 @@
 
 test_tools.cc: $(top_srcdir)/test-suite/test_tools.cc
 	cp $(top_srcdir)/test-suite/test_tools.cc .
 
 # stock tools for unit tests - library independent versions of dlink_list 
 # etc.
 # globals.cc is needed by test_tools.cc.
 # Neither of these should be disted from here.
 TESTSOURCES= \
 	tests/STUB.h \
 	test_tools.cc \
 	globals.cc
 
 check_PROGRAMS+=\
 	tests/testBoilerplate \
 	tests/testCacheManager \
 	tests/testDiskIO \
 	tests/testEvent \
 	tests/testEventLoop \
 	tests/test_http_range \
-	tests/testHttpParser \
+	tests/testHttp1Parser \
 	tests/testHttpReply \
 	tests/testHttpRequest \
 	tests/testStore \
 	tests/testString \
 	tests/testURL \
 	tests/testSBuf \
 	tests/testSBufList \
 	tests/testConfigParser \
 	tests/testStatHist \
 	tests/testVector
 
 if HAVE_FS_ROCK
 check_PROGRAMS += tests/testRock
 endif
 if HAVE_FS_UFS
 check_PROGRAMS += tests/testUfs
 endif
 
 ## NP: required to run the above list. check_PROGRAMS only builds the binaries...
 TESTS += $(check_PROGRAMS)
@@ -1228,41 +1225,40 @@
 	tests/stub_fatal.cc \
 	FileMap.h \
 	filemap.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	HttpBody.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	Notes.cc \
 	Notes.h \
 	SquidList.h \
 	SquidList.cc \
 	mem_node.cc \
 	Packer.cc \
 	Parsing.cc \
 	SquidMath.cc \
 	StatCounters.cc \
 	StatCounters.h \
 	StatHist.h \
 	StrList.h \
 	StrList.cc \
 	tests/stub_StatHist.cc \
 	stmem.cc \
 	$(SBUF_SOURCE) \
@@ -1362,46 +1358,43 @@
 tests_testBoilerplate_SOURCES = \
 	tests/testBoilerplate.cc \
 	tests/testMain.cc \
 	tests/testBoilerplate.h \
 	tests/stub_time.cc
 nodist_tests_testBoilerplate_SOURCES = \
 	$(TESTSOURCES)
 tests_testBoilerplate_LDADD= \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SSLLIB) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_testBoilerplate_LDFLAGS = $(LIBADD_DL)
 tests_testBoilerplate_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 
 ## Tests of the CacheManager module.
 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 \
 	tests/testCacheManager.cc \
 	tests/testCacheManager.h \
 	tests/testMain.cc \
 	tests/stub_main_cc.cc \
 	tests/stub_ipc_Forwarder.cc \
 	tests/stub_store_stats.cc \
 	tests/stub_EventLoop.cc \
 	time.cc \
 	BodyPipe.cc \
 	cache_manager.cc \
 	cache_cf.h \
 	AuthReg.h \
 	YesNoNone.h \
 	YesNoNone.cc \
 	RefreshPattern.h \
 	cache_cf.cc \
 	CacheDigest.h \
@@ -1644,41 +1637,40 @@
 	fde.cc \
 	FileMap.h \
 	filemap.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHdrRange.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	MemBuf.cc \
 	MemObject.cc \
 	mem_node.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	Notes.h \
 	Notes.cc \
 	Packer.cc \
 	Parsing.cc \
 	refresh.h \
 	refresh.cc \
 	RemovalPolicy.cc \
 	RequestFlags.h \
 	RequestFlags.cc \
@@ -1869,47 +1861,44 @@
 	HelperReply.h \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	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) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	Mem.h \
 	tests/stub_mem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
@@ -2115,47 +2104,44 @@
 	HelperReply.h \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	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) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	MemBuf.cc \
 	MemObject.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	mem_node.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
@@ -2357,47 +2343,44 @@
 	HelperReply.h \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	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 \
 	int.cc \
 	internal.h \
 	internal.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	MemBuf.cc \
 	MemObject.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	mem_node.cc \
 	mime.h \
 	mime.cc \
 	mime_header.h \
@@ -2513,90 +2496,88 @@
 	$(ESI_LIBS) \
 	$(SSL_LIBS) \
 	ipc/libipc.la \
 	base/libbase.la \
 	mgr/libmgr.la \
 	$(SNMP_LIBS) \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(REGEXLIB) \
 	$(SQUID_CPPUNIT_LIBS) \
 	$(SQUID_CPPUNIT_LA) \
 	$(SSLLIB) \
 	$(KRB5LIBS) \
 	$(COMPAT_LIB) \
 	$(XTRA_LIBS)
 tests_test_http_range_LDFLAGS = $(LIBADD_DL)
 tests_test_http_range_DEPENDENCIES = \
 	$(SQUID_CPPUNIT_LA)
 
-tests_testHttpParser_SOURCES = \
+tests_testHttp1Parser_SOURCES = \
 	Debug.h \
-	HttpParser.cc \
-	HttpParser.h \
 	MemBuf.cc \
 	MemBuf.h \
 	Mem.h \
 	tests/stub_mem.cc \
+	mime_header.cc \
+	mime_header.h \
 	String.cc \
 	cache_cf.h \
 	YesNoNone.h \
 	$(SBUF_SOURCE) \
 	tests/stub_SBufDetailedStats.cc \
 	tests/stub_cache_cf.cc \
 	tests/stub_cache_manager.cc \
 	tests/stub_debug.cc \
 	tests/stub_event.cc \
 	tests/stub_HelperChildConfig.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 \
 	$(top_builddir)/lib/libmiscutil.la \
 	$(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 \
 	tests/testHttpRequest.h \
 	tests/testHttpRequest.cc \
 	tests/testHttpRequestMethod.h \
 	tests/testHttpRequestMethod.cc \
 	tests/testMain.cc \
 	tests/stub_DiskIOModule.cc \
 	tests/stub_libauth.cc \
 	tests/stub_main_cc.cc \
 	tests/stub_ipc_Forwarder.cc \
 	tests/stub_libeui.cc \
 	tests/stub_store_stats.cc \
 	tests/stub_EventLoop.cc \
 	time.cc \
 	BodyPipe.cc \
 	cache_manager.cc \
 	cache_cf.h \
 	AuthReg.h \
@@ -2830,41 +2811,40 @@
 	event.cc \
 	EventLoop.cc \
 	fatal.h \
 	tests/stub_fatal.cc \
 	FileMap.h \
 	filemap.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpMsg.cc \
-	HttpRequestMethod.cc \
 	RequestFlags.cc \
 	RequestFlags.h \
 	int.h \
 	int.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	Mem.h \
 	tests/stub_mem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	Notes.h \
 	Notes.cc \
 	Packer.cc \
 	Parsing.cc \
 	RemovalPolicy.cc \
 	refresh.h \
 	refresh.cc \
@@ -3092,41 +3072,40 @@
 	StoreIOState.cc \
 	StoreMetaUnpacker.cc \
 	$(STOREMETA_SOURCE) \
 	StoreFileSystem.cc \
 	store_io.cc \
 	store_swapout.cc \
 	store_swapmeta.cc \
 	$(UNLINKDSOURCE) \
 	$(WIN32_SOURCE) \
 	event.cc \
 	$(DELAY_POOL_SOURCE) \
 	CacheDigest.h \
 	tests/stub_CacheDigest.cc \
 	ConfigParser.cc \
 	EventLoop.cc \
 	HttpMsg.cc \
 	RemovalPolicy.cc \
 	store_dir.cc \
 	repl_modules.h \
 	store.cc \
-	HttpRequestMethod.cc \
 	store_key_md5.h \
 	store_key_md5.cc \
 	Parsing.cc \
 	ConfigOption.cc \
 	SwapDir.cc \
 	tests/stub_acl.cc \
 	cache_cf.h \
 	YesNoNone.h \
 	tests/stub_cache_cf.cc \
 	tests/stub_helper.cc \
 	cbdata.cc \
 	$(SBUF_SOURCE) \
 	SBufDetailedStats.h \
 	tests/stub_SBufDetailedStats.cc \
 	String.cc \
 	tests/stub_debug.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	tests/stub_libauth.cc \
 	mem_node.cc \
@@ -3248,41 +3227,40 @@
 	fd.cc \
 	fde.h \
 	fde.cc \
 	FileMap.h \
 	filemap.cc \
 	HttpHeaderFieldStat.h \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHdrCc.cc \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	HttpHeaderTools.h \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
-	HttpRequestMethod.cc \
 	int.h \
 	int.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	Mem.h \
 	mem.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mem_node.cc \
 	Notes.h \
 	Notes.cc \
 	Packer.cc \
 	Parsing.cc \
 	RemovalPolicy.cc \
 	RequestFlags.cc \
 	RequestFlags.h \
 	StatCounters.h \
 	StatCounters.cc \
@@ -3457,47 +3435,44 @@
 	HelperReply.h \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpHeaderFieldStat.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.h \
 	HttpHeader.cc \
 	HttpHeaderFieldInfo.h \
 	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) \
 	ipcache.cc \
 	int.h \
 	int.cc \
 	internal.h \
 	internal.cc \
 	SquidList.h \
 	SquidList.cc \
 	MasterXaction.cc \
 	MasterXaction.h \
 	multicast.h \
 	multicast.cc \
 	Mem.h \
 	tests/stub_mem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.h \

=== modified file 'src/MemObject.h'
--- src/MemObject.h	2012-09-22 20:07:31 +0000
+++ src/MemObject.h	2013-12-23 16:26:23 +0000
@@ -16,41 +16,41 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_MEMOBJECT_H
 #define SQUID_MEMOBJECT_H
 
 #include "CommRead.h"
 #include "dlink.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "RemovalPolicy.h"
 #include "stmem.h"
 #include "StoreIOBuffer.h"
 #include "StoreIOState.h"
 
 #if USE_DELAY_POOLS
 #include "DelayId.h"
 #endif
 
 typedef void STMCB (void *data, StoreIOBuffer wroteBuffer);
 
 class store_client;
 class HttpRequest;
 class HttpReply;
 
 class MemObject
 {
 
 public:
     static size_t inUseCount();

=== modified file 'src/Store.h'
--- src/Store.h	2013-07-15 07:49:43 +0000
+++ src/Store.h	2013-12-23 16:25:31 +0000
@@ -22,42 +22,42 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 #ifndef SQUID_STORE_H
 #define SQUID_STORE_H
 
 /**
  \defgroup StoreAPI  Store API
  \ingroup FileSystems
  */
 
 #include "base/RefCount.h"
 #include "comm/forward.h"
 #include "CommRead.h"
 #include "hash.h"
+#include "http/forward.h"
 #include "HttpReply.h"
-#include "HttpRequestMethod.h"
 #include "Range.h"
 #include "RemovalPolicy.h"
 #include "StoreIOBuffer.h"
 #include "StoreStats.h"
 
 #if USE_SQUID_ESI
 #include "esi/Element.h"
 #endif
 
 #if HAVE_OSTREAM
 #include <ostream>
 #endif
 
 class AsyncCall;
 class HttpRequest;
 class MemObject;
 class Packer;
 class RequestFlags;
 class StoreClient;
 class StoreSearch;

=== 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
@@ -18,41 +18,41 @@
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #ifndef SQUID_ACLMETHOD_H
 #define SQUID_ACLMETHOD_H
 
 #include "acl/Strategised.h"
 #include "acl/Strategy.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 
 /// \ingroup ACLAPI
 class ACLMethodStrategy : public ACLStrategy<HttpRequestMethod>
 {
 
 public:
     virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
     virtual bool requiresRequest() const {return true;}
 
     static ACLMethodStrategy *Instance();
 
     /**
      * Not implemented to prevent copies of the instance.
      \par
      * Not private to prevent brain dead g+++ warnings about
      * private constructors with no friends
      */
     ACLMethodStrategy(ACLMethodStrategy const &);
 
 private:

=== 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
@@ -19,41 +19,40 @@
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "acl/Checklist.h"
 #include "acl/MethodData.h"
 #include "cache_cf.h"
-#include "HttpRequestMethod.h"
 #include "wordlist.h"
 
 int ACLMethodData::ThePurgeCount = 0;
 
 ACLMethodData::ACLMethodData() : values (NULL)
 {}
 
 ACLMethodData::ACLMethodData(ACLMethodData const &old) : values (NULL)
 {
     assert (!old.values);
 }
 
 ACLMethodData::~ACLMethodData()
 {
     if (values)
         delete values;
 }
 
 /// todo make this a pass-by-reference now that HTTPRequestMethods a full class?
 bool

=== 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
@@ -19,41 +19,41 @@
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #ifndef SQUID_ACLMETHODDATA_H
 #define SQUID_ACLMETHODDATA_H
 
 #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>
 {
 
 public:
     MEMPROXY_CLASS(ACLMethodData);
 
     ACLMethodData();
     ACLMethodData(ACLMethodData const &);
     ACLMethodData &operator= (ACLMethodData const &);
     virtual ~ACLMethodData();
     bool match(HttpRequestMethod);
     wordlist *dump();
     void parse();
     bool empty() const;
     virtual ACLData<HttpRequestMethod> *clone() const;
 
     CbDataList<HttpRequestMethod> *values;
 

=== 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
@@ -36,41 +36,40 @@
 #include "acl/AclDenyInfoList.h"
 #include "acl/AclNameList.h"
 #include "acl/AclSizeLimit.h"
 #include "acl/Gadgets.h"
 #include "acl/MethodData.h"
 #include "acl/Tree.h"
 #include "anyp/PortCfg.h"
 #include "AuthReg.h"
 #include "base/RunnersRegistry.h"
 #include "cache_cf.h"
 #include "CachePeer.h"
 #include "CachePeerDomainList.h"
 #include "ConfigParser.h"
 #include "CpuAffinityMap.h"
 #include "DiskIO/DiskIOModule.h"
 #include "eui/Config.h"
 #include "ExternalACL.h"
 #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"
 #include "ip/tools.h"
 #include "ipc/Kids.h"
 #include "log/Config.h"
 #include "log/CustomLog.h"
 #include "Mem.h"
 #include "MemBuf.h"
 #include "mgr/ActionPasswordList.h"
 #include "mgr/Registration.h"
 #include "neighbors.h"
 #include "NeighborTypeDomainList.h"
 #include "Parsing.h"
 #include "PeerDigest.h"
 #include "RefreshPattern.h"
 #include "rfc1738.h"
 #include "SquidConfig.h"
 #include "SquidString.h"
 #include "ssl/ProxyCerts.h"

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2013-12-06 14:59:47 +0000
+++ src/client_side.cc	2013-12-31 15:59:25 +0000
@@ -87,40 +87,41 @@
 #include "ChunkedCodingParser.h"
 #include "client_db.h"
 #include "client_side.h"
 #include "client_side_reply.h"
 #include "client_side_request.h"
 #include "ClientRequestContext.h"
 #include "clientStream.h"
 #include "comm.h"
 #include "comm/Connection.h"
 #include "comm/Loops.h"
 #include "comm/TcpAcceptor.h"
 #include "comm/Write.h"
 #include "CommCalls.h"
 #include "errorpage.h"
 #include "fd.h"
 #include "fde.h"
 #include "fqdncache.h"
 #include "FwdState.h"
 #include "globals.h"
 #include "http.h"
+#include "http/Http1Parser.h"
 #include "HttpHdrContRange.h"
 #include "HttpHeaderTools.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "ident/Config.h"
 #include "ident/Ident.h"
 #include "internal.h"
 #include "ipc/FdNotes.h"
 #include "ipc/StartListening.h"
 #include "log/access_log.h"
 #include "Mem.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "mime_header.h"
 #include "profiler/Profiler.h"
 #include "rfc1738.h"
 #include "SquidConfig.h"
 #include "SquidTime.h"
 #include "StatCounters.h"
 #include "StatHist.h"
@@ -188,41 +189,41 @@
 };
 
 static void clientListenerConnectionOpened(AnyP::PortCfg *s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
 
 /* our socket-related context */
 
 CBDATA_CLASS_INIT(ClientSocketContext);
 
 /* Local functions */
 /* ClientSocketContext */
 static ClientSocketContext *ClientSocketContextNew(const Comm::ConnectionPointer &clientConn, ClientHttpRequest *);
 /* other */
 static IOCB clientWriteComplete;
 static IOCB clientWriteBodyComplete;
 static IOACB httpAccept;
 #if USE_SSL
 static IOACB httpsAccept;
 #endif
 static CTCB clientLifetimeTimeout;
 static ClientSocketContext *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
-static ClientSocketContext *parseHttpRequest(ConnStateData *, HttpParser *, HttpRequestMethod *, Http::ProtocolVersion *);
+static ClientSocketContext *parseHttpRequest(ConnStateData *, const Http::Http1ParserPointer &);
 #if USE_IDENT
 static IDCB clientIdentDone;
 #endif
 static CSCB clientSocketRecipient;
 static CSD clientSocketDetach;
 static void clientSetKeepaliveFlag(ClientHttpRequest *);
 static int clientIsContentLengthValid(HttpRequest * r);
 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
 
 static void clientUpdateStatHistCounters(LogTags logType, int svc_time);
 static void clientUpdateStatCounters(LogTags logType);
 static void clientUpdateHierCounters(HierarchyLogEntry *);
 static bool clientPingHasFinished(ping_data const *aPing);
 void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &);
 #ifndef PURIFY
 static bool connIsUsable(ConnStateData * conn);
 #endif
 static int responseFinishedOrFailed(HttpReply * rep, StoreIOBuffer const &receivedData);
 static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn);
 static void clientUpdateSocketStats(LogTags logType, size_t size);
@@ -2062,357 +2063,312 @@
             char *tmp_uri = static_cast<char*>(xmalloc(strlen(uri) + 1));
             char *q = tmp_uri;
             t = uri;
             while (*t) {
                 if (!xisspace(*t)) {
                     *q = *t;
                     ++q;
                 }
                 ++t;
             }
             *q = '\0';
             http->log_uri = xstrndup(rfc1738_escape_unescaped(tmp_uri), MAX_URL);
             xfree(tmp_uri);
         }
         break;
         }
     }
 }
 
 static void
-prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
+prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http::Http1ParserPointer &hp)
 {
     int vhost = conn->port->vhost;
     int vport = conn->port->vport;
     char *host;
     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 = hp->requestUri().c_str();
     if (*url != '/') {
         if (conn->port->vhost)
             return; /* already in good shape */
 
         /* else we need to ignore the host name */
         url = strstr(url, "//");
 
 #if SHOULD_REJECT_UNKNOWN_URLS
 
         if (!url) {
             hp->request_parse_status = Http::scBadRequest;
             return parseHttpRequestAbort(conn, "error:invalid-request");
         }
 #endif
 
         if (url)
             url = strchr(url + 2, '/');
 
         if (!url)
             url = (char *) "/";
     }
 
     if (vport < 0)
         vport = http->getConn()->clientConnection->local.port();
 
     const bool switchedToHttps = conn->switchedToHttps();
     const bool tryHostHeader = vhost || switchedToHttps;
-    if (tryHostHeader && (host = mime_get_header(req_hdr, "Host")) != NULL) {
+    if (tryHostHeader && (host = hp->getHeaderField("Host")) != NULL) {
         debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
         char thost[256];
         if (vport > 0) {
             thost[0] = '\0';
             char *t = NULL;
             if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) {
                 strncpy(thost, host, (t-host));
                 snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport);
                 host = thost;
             } else if (!t) {
                 snprintf(thost, sizeof(thost), "%s:%d",host, vport);
                 host = thost;
             }
         } // else nothing to alter port-wise.
         int url_sz = strlen(url) + 32 + Config.appendDomainLen +
                      strlen(host);
         http->uri = (char *)xcalloc(url_sz, 1);
         const char *protocol = switchedToHttps ?
                                "https" : URLScheme(conn->port->transport.protocol).const_str();
         snprintf(http->uri, url_sz, "%s://%s%s", protocol, host, url);
         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 +
+        int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
                      strlen(conn->port->defaultsite);
         http->uri = (char *)xcalloc(url_sz, 1);
         char vportStr[32];
         vportStr[0] = '\0';
         if (vport > 0) {
             snprintf(vportStr, sizeof(vportStr),":%d",vport);
         }
         snprintf(http->uri, url_sz, "%s://%s%s%s",
                  URLScheme(conn->port->transport.protocol).const_str(), conn->port->defaultsite, vportStr, url);
         debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: '" << http->uri <<"'");
     } 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;
+        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(conn->port->transport.protocol).const_str(),
                  ipbuf, vport, url);
         debugs(33, 5, "ACCEL VPORT REWRITE: '" << http->uri << "'");
     }
 }
 
 static void
-prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr)
+prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, const Http::Http1ParserPointer &hp)
 {
     char *host;
     char ipbuf[MAX_IPSTRLEN];
 
-    if (*url != '/')
+    if (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 ((host = hp->getHeaderField("Host")) != NULL) {
+        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, 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;
+        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(), hp->requestUri().c_str());
         debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'");
     }
 }
 
 /** Parse an HTTP request
  *
  *  \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 Http::Http1Parser
  *  \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
  *  \param[out] http_ver will be set as a side-effect of the parsing
  *  \return NULL on incomplete requests,
  *          a ClientSocketContext structure on success or failure.
  */
 static ClientSocketContext *
-parseHttpRequest(ConnStateData *csd, HttpParser *hp, HttpRequestMethod * method_p, Http::ProtocolVersion *http_ver)
+parseHttpRequest(ConnStateData *csd, const Http::Http1ParserPointer &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;
-    }
+    /* Attempt to parse the first line; this will define where the method, url, version and header begin */
+    {
+        bool parsedOk = hp->parseRequest();
 
-    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");
+        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);
+
+        if (!parsedOk)
+            return parseHttpRequestAbort(csd, "error:invalid-request");
     }
 
     /* We know the whole request is in hp->buf now */
-
+    req_sz = hp->messageHeaderSize();
     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);
-
     /* 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;
         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;
         return parseHttpRequestAbort(csd, "error:unsupported-request-method");
     }
 
     /*
      * 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);
+    http->req_sz = hp->messageHeaderSize();
     result = ClientSocketContextNew(csd->clientConnection, http);
     tempBuffer.data = result->reqbuf;
     tempBuffer.length = HTTP_REQBUF_SZ;
 
     ClientStreamData newServer = new clientReplyContext(http);
     ClientStreamData newClient = result;
     clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
                      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 = hp->requestUri().c_str();
 
     debugs(33,5, HERE << "repare absolute URL from " <<
            (csd->transparent()?"intercept":(csd->port->flags.accelSurrogate ? "accel":"")));
     /* Rewrite the URL in transparent or accelerator mode */
     /* NP: there are several cases to traverse here:
      *  - standard mode (forward proxy)
      *  - transparent mode (TPROXY)
      *  - transparent mode with failures
      *  - intercept mode (NAT)
      *  - intercept mode with failures
      *  - accelerator mode (reverse proxy)
      *  - internal URL
      *  - mixed combos of the above with internal URL
      */
     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 */
         /* prepend our name & port */
         http->uri = xstrdup(internalLocalUri(NULL, url));
         // We just re-wrote the URL. Must replace the Host: header.
         //  But have not parsed there yet!! flag for local-only handling.
         http->flags.internal = true;
 
     } 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;
         http->uri = (char *)xcalloc(url_sz, 1);
         strcpy(http->uri, url);
     }
 
     debugs(33, 5, "parseHttpRequest: Complete request received");
 
     // 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;
 }
 
 int
 ConnStateData::getAvailableBufferLength() const
 {
     assert (in.allocatedSize > in.notYetUsed); // allocated more than used
     const size_t result = in.allocatedSize - in.notYetUsed - 1;
     // huge request_header_max_size may lead to more than INT_MAX unused space
     assert (static_cast<ssize_t>(result) <= INT_MAX);
     return result;
 }
 
 bool
 ConnStateData::maybeMakeSpaceAvailable()
 {
     if (getAvailableBufferLength() < 2) {
         size_t newSize;
         if (in.allocatedSize >= Config.maxRequestBufferSize) {
             debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
@@ -2621,124 +2577,126 @@
                     srvCert, NULL);
                 err->detail = errDetail;
                 // Save the original request for logging purposes.
                 if (!context->http->al->request) {
                     context->http->al->request = request;
                     HTTPMSGLOCK(context->http->al->request);
                 }
                 repContext->setReplyToError(request->method, err);
                 assert(context->http->out.offset == 0);
                 context->pullData();
                 return true;
             }
         }
     }
 
     return false;
 }
 #endif // USE_SSL
 
 static void
-clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, Http::ProtocolVersion http_ver)
+clientProcessRequest(ConnStateData *conn, const Http::Http1ParserPointer &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 HttpRequestMethodPointer method = hp->method();
 
     /* We have an initial client stream in place should it be needed */
     /* setup our private context */
     context->registerWithConn();
 
     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) {
         case Http::scHeaderTooLarge:
-            repContext->setReplyToError(ERR_TOO_BIG, Http::scBadRequest, method, http->uri, conn->clientConnection->remote, NULL, conn->in.buf, NULL);
+            repContext->setReplyToError(ERR_TOO_BIG, Http::scBadRequest, *method, http->uri, conn->clientConnection->remote, NULL, conn->in.buf, NULL);
             break;
         case Http::scMethodNotAllowed:
-            repContext->setReplyToError(ERR_UNSUP_REQ, Http::scMethodNotAllowed, method, http->uri,
+            repContext->setReplyToError(ERR_UNSUP_REQ, Http::scMethodNotAllowed, *method, http->uri,
                                         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);
         context->pullData();
         goto finish;
     }
 
-    if ((request = HttpRequest::CreateFromUrlAndMethod(http->uri, method)) == NULL) {
+    if ((request = HttpRequest::CreateFromUrlAndMethod(http->uri, *method)) == NULL) {
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 5, "Invalid URL: " << http->uri);
         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_INVALID_URL, Http::scBadRequest, method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
+        repContext->setReplyToError(ERR_INVALID_URL, Http::scBadRequest, *method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         goto finish;
     }
 
     /* RFC 2616 section 10.5.6 : handle unsupported HTTP major versions cleanly. */
     /* We currently only support 0.9, 1.0, 1.1 properly */
     if ( (http_ver.major == 0 && http_ver.minor != 9) ||
             (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->rawHeaderBuf());
         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);
+        repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, *method, http->uri,
+                                    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);
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
-        repContext->setReplyToError(ERR_INVALID_REQ, Http::scBadRequest, method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
+        repContext->setReplyToError(ERR_INVALID_REQ, Http::scBadRequest, *method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         goto finish;
     }
 
     request->clientConnectionManager = conn;
 
     request->flags.accelerated = http->flags.accel;
     request->flags.sslBumped=conn->switchedToHttps();
     request->flags.ignoreCc = conn->port->ignore_cc;
     // TODO: decouple http->flags.accel from request->flags.sslBumped
     request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
                               !conn->port->allow_direct : 0;
 #if USE_AUTH
     if (request->flags.sslBumped) {
         if (conn->getAuth() != NULL)
             request->auth_user_request = conn->getAuth();
     }
 #endif
 
@@ -2769,55 +2727,59 @@
             request->port = getMyPort();
             http->flags.internal = true;
         }
     }
 
     if (http->flags.internal) {
         request->protocol = AnyP::PROTO_HTTP;
         request->login[0] = '\0';
     }
 
     request->flags.internal = http->flags.internal;
     setLogUri (http, urlCanonicalClean(request.getRaw()));
     request->client_addr = conn->clientConnection->remote; // XXX: remove reuest->client_addr member.
 #if FOLLOW_X_FORWARDED_FOR
     // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
     // not a details about teh TCP connection itself
     request->indirect_client_addr = conn->clientConnection->remote;
 #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.
     request->clientConnectionManager = conn;
 
     if (request->header.chunked()) {
         chunked = true;
     } else if (request->header.has(HDR_TRANSFER_ENCODING)) {
         const String te = request->header.getList(HDR_TRANSFER_ENCODING);
         // HTTP/1.1 requires chunking to be the last encoding if there is one
         unsupportedTe = te.size() && te != "identity";
     } // else implied identity coding
 
-    mustReplyToOptions = (method == Http::METHOD_OPTIONS) &&
+    mustReplyToOptions = (*method == Http::METHOD_OPTIONS) &&
                          (request->header.getInt64(HDR_MAX_FORWARDS) == 0);
     if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
         clientStreamNode *node = context->getClientReplyContext();
         conn->quitAfterError(request.getRaw());
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_UNSUP_REQ, Http::scNotImplemented, request->method, NULL,
                                     conn->clientConnection->remote, request.getRaw(), NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         goto finish;
     }
 
     if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
         clientStreamNode *node = context->getClientReplyContext();
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         conn->quitAfterError(request.getRaw());
         repContext->setReplyToError(ERR_INVALID_REQ,
                                     Http::scLengthRequired, request->method, NULL,
@@ -2941,87 +2903,92 @@
     const int concurrentRequestLimit = Config.pipeline_max_prefetch + 1;
 
     // when queue filled already we cant add more.
     if (existingRequestCount >= concurrentRequestLimit) {
         debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
         debugs(33, 5, clientConnection << " deferring new request until one is done");
         return true;
     }
 
     return false;
 }
 
 /**
  * Attempt to parse one or more requests from the input buffer.
  * If a request is successfully parsed, even if the next request
  * is only partially parsed, it will return TRUE.
  */
 bool
 ConnStateData::clientParseRequests()
 {
-    HttpRequestMethod method;
     bool parsed_req = false;
 
     debugs(33, 5, HERE << clientConnection << ": attempting to parse");
 
     // 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)
             break;
 
         /* Limit the number of concurrent requests */
         if (concurrentRequestQueueFilled())
             break;
 
         /* Should not be needed anymore */
         /* Terminate the string */
         in.buf[in.notYetUsed] = '\0';
 
         /* 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 Http::Http1Parser(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_);
         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");
             AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
                                              CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
             commSetConnTimeout(clientConnection, Config.Timeout.lifetime, timeoutCall);
 
-            clientProcessRequest(this, &parser_, context, method, http_ver);
+            clientProcessRequest(this, parser_, context);
 
             parsed_req = true; // XXX: do we really need to parse everything right NOW ?
 
             if (context->mayUseConnection()) {
                 debugs(33, 3, HERE << "Not parsing new requests, as this request may need the connection");
                 break;
             }
         }
     }
 
     /* XXX where to 'finish' the parsing pass? */
     return parsed_req;
 }
 
 void
 ConnStateData::clientReadRequest(const CommIoCbParams &io)
 {
     debugs(33,5,HERE << io.conn << " size " << io.size);
     Must(reading());
     reader = NULL;

=== modified file 'src/client_side.h'
--- src/client_side.h	2013-08-22 18:39:41 +0000
+++ src/client_side.h	2013-12-23 11:32:15 +0000
@@ -18,41 +18,41 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_CLIENTSIDE_H
 #define SQUID_CLIENTSIDE_H
 
 #include "comm.h"
 #include "HttpControlMsg.h"
-#include "HttpParser.h"
+#include "http/forward.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
 class ConnStateData;
 class ClientHttpRequest;
 class clientStreamNode;
 class ChunkedCodingParser;
 class HelperReply;
 namespace AnyP
 {
 class PortCfg;
 } // namespace Anyp
 
 /**
  * Badly named.
  * This is in fact the processing context for a single HTTP request.
@@ -381,43 +381,42 @@
 protected:
     void startDechunkingRequest();
     void finishDechunkingRequest(bool withSuccess);
     void abortChunkedRequestBody(const err_type error);
     err_type handleChunkedRequestBody(size_t &putSize);
 
     void startPinnedConnectionMonitoring();
     void clientPinnedConnectionRead(const CommIoCbParams &io);
 
 private:
     int connReadWasError(comm_err_t flag, int size, int xerrno);
     int connFinishedWithConn(int size);
     void clientAfterReadingRequests();
     bool concurrentRequestQueueFilled() const;
 
 #if USE_AUTH
     /// some user details that can be used to perform authentication on this connection
     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
+    Http::Http1ParserPointer parser_;
 
 #if USE_SSL
     bool switchedToHttps_;
     /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
     String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
     String sslCommonName; ///< CN name for SSL certificate generation
     String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
 
     /// HTTPS server cert. fetching state for bump-ssl-server-first
     Ssl::ServerBump *sslServerBump;
     Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
 #endif
 
     /// the reason why we no longer write the response or nil
     const char *stoppedSending_;
     /// the reason why we no longer read the request or nil
     const char *stoppedReceiving_;
 
     AsyncCall::Pointer reader; ///< set when we are reading
     BodyPipe::Pointer bodyPipe; // set when we are reading request body

=== 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
@@ -16,45 +16,43 @@
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_HTCP_H
 #define SQUID_HTCP_H
 
 #if USE_HTCP
 
 #include "HttpHeader.h"
-#include "HttpRequestMethod.h"
+#include "http/forward.h"
 #include "ip/forward.h"
 
-class HttpRequest;
-
 /// \ingroup ServerProtocolHTCP
 class HtcpReplyData
 {
 
 public:
     HtcpReplyData();
     int hit;
     HttpHeader hdr;
     uint32_t msg_id;
     double version;
 
     struct cto_t {
         /* cache-to-origin */
         double rtt;
         int samp;
         int hops;
     } cto;
 };
 
 /// \ingroup ServerProtocolHTCP

=== renamed file 'src/HttpParser.cc' => 'src/http/Http1Parser.cc'
--- src/HttpParser.cc	2013-03-16 04:57:43 +0000
+++ src/http/Http1Parser.cc	2013-12-31 14:47:57 +0000
@@ -1,71 +1,139 @@
 #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()
+Http::Http1Parser::clear()
 {
-    state = HTTP_PARSE_NONE;
+    completedState_ = HTTP_PARSE_NONE;
     request_parse_status = Http::scNone;
     buf = NULL;
     bufsiz = 0;
+    parseOffset_ = 0;
     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;
+    msgProtocol_ = AnyP::ProtocolVersion();
+    method_ = NULL;
+    mimeHeaderBlock_.clear();
 }
 
 void
-HttpParser::reset(const char *aBuf, int len)
+Http::Http1Parser::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, "Request parse " << Raw("buf", buf, bufsiz));
 }
 
-int
-HttpParser::parseRequestFirstLine()
+/**
+ * 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
+Http::Http1Parser::skipGarbageLines()
 {
-    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
+    req.start = parseOffset_; // avoid re-parsing any portion we managed to complete
 
-    debugs(74, 5, HERE << "parsing possible request: " << buf);
-
-    // Single-pass parse: (provided we have the whole line anyways)
+#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
 
-    req.start = 0;
+    /* 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
+Http::Http1Parser::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, "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 = 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)
         if (buf[i] == ' ') {
             last_whitespace = i;
             if (first_whitespace < req.start)
                 first_whitespace = i;
         }
 
         // track next non-SP/non-HT byte after first_whitespace
         if (second_word < first_whitespace && buf[i] != ' ' && buf[i] != '\t') {
             second_word = i;
         }
 
         // locate line terminator
         if (buf[i] == '\n') {
             req.end = i;
             line_end = i - 1;
             break;
         }
@@ -115,180 +183,246 @@
     // generating HTTP status for any aborts as we go.
 
     // First non-whitespace = beginning of method
     if (req.start > line_end) {
         request_parse_status = Http::scBadRequest;
         return -1;
     }
     req.m_start = req.start;
 
     // First whitespace = end of method
     if (first_whitespace > line_end || first_whitespace < req.start) {
         request_parse_status = Http::scBadRequest; // no method
         return -1;
     }
     req.m_end = first_whitespace - 1;
     if (req.m_end < req.m_start) {
         request_parse_status = Http::scBadRequest; // missing URI?
         return -1;
     }
 
+    /* Set method_ */
+    method_ = new 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
         return -1;
     }
     req.u_start = second_word;
 
     // RFC 1945: SP and version following URI are optional, marking version 0.9
     // we identify this by the last whitespace being earlier than URI start
     if (last_whitespace < second_word && last_whitespace >= req.start) {
-        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.
         req.u_end = last_whitespace;
         // crop any trailing whitespace in the area we think of as URI
         for (; req.u_end >= req.u_start && xisspace(buf[req.u_end]); --req.u_end);
     }
     if (req.u_end < req.u_start) {
         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) {
         request_parse_status = Http::scBadRequest; // missing version
         return -1;
     }
     req.v_start = last_whitespace + 1;
     req.v_end = line_end;
 
     // We only accept HTTP protocol requests right now.
     // TODO: accept other protocols; RFC 2326 (RTSP protocol) etc
     if ((req.v_end - req.v_start +1) < 5 || strncasecmp(&buf[req.v_start], "HTTP/", 5) != 0) {
 #if USE_HTTP_VIOLATIONS
         // being lax; old parser accepted strange versions
         // there is a LOT of cases which are ambiguous, therefore we cannot use relaxed_header_parser here.
-        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.
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
 #endif
     }
+    msgProtocol_.protocol = AnyP::PROTO_HTTP;
 
     int i = req.v_start + sizeof("HTTP/") -1;
 
     /* next should be 1 or more digits */
     if (!isdigit(buf[i])) {
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
     int maj = 0;
     for (; i <= line_end && (isdigit(buf[i])) && maj < 65536; ++i) {
         maj = maj * 10;
         maj = maj + (buf[i]) - '0';
     }
     // catch too-big values or missing remainders
     if (maj >= 65536 || i > line_end) {
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
-    req.v_maj = maj;
+    msgProtocol_.major = maj;
 
     /* next should be .; we -have- to have this as we have a whole line.. */
     if (buf[i] != '.') {
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
     // catch missing minor part
     if (++i > line_end) {
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
     /* next should be one or more digits */
     if (!isdigit(buf[i])) {
         request_parse_status = Http::scHttpVersionNotSupported;
         return -1;
     }
     int min = 0;
     for (; i <= line_end && (isdigit(buf[i])) && min < 65536; ++i) {
         min = min * 10;
         min = min + (buf[i]) - '0';
     }
     // catch too-big values or trailing garbage
     if (min >= 65536 || i < line_end) {
         request_parse_status = Http::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)
+bool
+Http::Http1Parser::parseRequest()
 {
-    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;
-}
+    // stage 1: locate the request-line
+    if (completedState_ == HTTP_PARSE_NEW) {
+        if (skipGarbageLines() && (size_t)bufsiz < parseOffset_)
+            return 0;
+    }
+
+    // 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;
+        }
+    }
 
-#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;
-}
+    // 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) {
+                debugs(33, 5, "Incomplete request, waiting for end of headers");
+                return false;
+            }
+            mimeHeaderBlock_.assign(&buf[req.end+1], mimeHeaderBytes);
 
-/*
- * 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;
-}
+        } else
+            debugs(33, 3, "Missing HTTP/1.x identifier");
 
-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;
+        // 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;
+    }
+
+    return isDone();
 }
 
-int
-HttpParserRequestLen(HttpParser *hp)
+// arbitrary maximum-length for headers which can be found by Http1Parser::getHeaderField()
+#define GET_HDR_SZ	1024
+
+char *
+Http::Http1Parser::getHeaderField(const char *name)
 {
-    return hp->hdr_end - hp->req.start + 1;
-}
-#endif
+    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	2013-12-31 15:54:41 +0000
@@ -1,97 +1,135 @@
-#ifndef _SQUID_SRC_HTTPPARSER_H
-#define _SQUID_SRC_HTTPPARSER_H
+#ifndef _SQUID_SRC_HTTP_HTTP1PARSER_H
+#define _SQUID_SRC_HTTP_HTTP1PARSER_H
 
+#include "base/RefCount.h"
+#include "http/forward.h"
+#include "http/ProtocolVersion.h"
 #include "http/StatusCode.h"
+#include "SBuf.h"
+
+namespace Http {
 
 // 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:
  *
  * \item Request Line (method, URL, protocol, version)
  * \item Mime header block
  */
-class HttpParser
+class Http1Parser : public RefCountable
 {
 public:
-    HttpParser() { clear(); }
+    typedef RefCount<Http1Parser> Pointer;
+
+    Http1Parser() { clear(); }
 
     /** Initialize a new parser.
      * Presenting it a buffer to work on and the current length of available
      * data.
      * NOTE: This is *not* the buffer size, just the parse-able data length.
      * The parse routines may be called again later with more data.
      */
-    HttpParser(const char *aBuf, int len) { reset(aBuf,len); };
+    Http1Parser(const char *aBuf, int len) { reset(aBuf,len); };
 
     /// Set this parser back to a default state.
     /// Will DROP any reference to a buffer (does not free).
     void clear();
 
     /// Reset the parser for use on a new buffer.
     void reset(const char *aBuf, int len);
 
+    /** Whether the parser is already done processing the buffer.
+     * Use to determine between incomplete data and errors results
+     * from the parse methods.
+     */
+    bool isDone() const {return completedState_==HTTP_PARSE_DONE;}
+
+    /// size in bytes of the first line (request-line)
+    /// including CRLF terminator
+    int64_t firstLineSize() const {return req.end - req.start + 1;}
+
+    /// size in bytes of the message headers including CRLF terminator(s)
+    /// but excluding request-line bytes
+    int64_t headerBlockSize() const {return mimeHeaderBlock_.length();}
+
+    /// size in bytes of HTTP message block, includes request-line and mime headers
+    /// excludes any body/entity/payload bytes
+    /// excludes any garbage prefix before the request-line
+    int64_t messageHeaderSize() const {return firstLineSize() + headerBlockSize();}
+
+    /// buffer containing HTTP mime headers, excluding request or status line.
+    const char *rawHeaderBuf() {return mimeHeaderBlock_.c_str();}
+
+    /** Attempt to parse a request.
+     * \return true if a valid request was parsed.
+     * \note Use isDone() method to determine between incomplete parse and errors.
+     */
+    bool parseRequest();
+
     /**
-     * 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;
 
+    /// the protocol label for this message
+    const AnyP::ProtocolVersion & messageProtocol() const {return msgProtocol_;}
+
+    /// the HTTP method if this is a request method
+    const HttpRequestMethodPointer & method() const {return method_;}
+
+    /// the request-line URI if this is a request, or an empty string.
+    SBuf requestUri() const {return uri_;}
+
+    // 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;
+
+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;
+    /// byte offset for non-parsed region of the buffer
+    size_t parseOffset_;
 
-    // TODO: Offsets for pieces of the (HTTP reply) Status-Line as per RFC 2616
+    /// what stage the parser is currently up to
+    uint8_t completedState_;
 
-    /** 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 protocol label has been found in the first line
+    AnyP::ProtocolVersion msgProtocol_;
+
+    /// what request method has been found on the first line
+    HttpRequestMethodPointer method_;
+
+    /// raw copy of the origina client reqeust-line URI field
+    SBuf uri_;
+
+    /// buffer holding the mime headers
+    SBuf mimeHeaderBlock_;
 };
 
-// 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
+} // namespace Http
 
-#endif /*  _SQUID_SRC_HTTPPARSER_H */
+#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	2013-12-31 03:40:37 +0000
@@ -1,19 +1,24 @@
 include $(top_srcdir)/src/Common.am
 include $(top_srcdir)/src/TestHeaders.am
 
 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 \
 	StatusLine.h
 
 MethodType.cc: MethodType.h $(top_srcdir)/src/mk-string-arrays.awk
 	($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk < $(srcdir)/MethodType.h | \
 		sed -e 's%METHOD_%%' -e 's%_C%-C%' >$@) || ($(RM) -f $@ && exit 1)
 
 CLEANFILES += MethodType.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
@@ -1,26 +1,26 @@
 /*
  * DEBUG: section 73    HTTP Request
  */
 
 #include "squid.h"
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "SquidConfig.h"
 #include "wordlist.h"
 
 static Http::MethodType &
 operator++ (Http::MethodType &aMethod)
 {
     int tmp = (int)aMethod;
     aMethod = (Http::MethodType)(++tmp);
     return aMethod;
 }
 
 /**
  * Construct a HttpRequestMethod from a NULL terminated string such as "GET"
  * or from a range of chars, * such as "GET" from "GETFOOBARBAZ"
  * (pass in pointer to G and pointer to F.)
  */
 HttpRequestMethod::HttpRequestMethod(char const *begin, char const *end) : theMethod (Http::METHOD_NONE)
 {
     if (begin == NULL)
         return;

=== 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,45 +1,39 @@
 #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>
 
 /**
  * This class represents an HTTP Request METHOD
  * - i.e. PUT, POST, GET etc.
  * 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() {}
 
     /**
      \param begin    string to convert to request method.
      \param end      end of the method string (relative to begin). Use NULL if this is unknown.
      *
      \note DO NOT give end a default (ie NULL). That will cause silent char* conversion clashes.
      */
     HttpRequestMethod(char const * begin, char const * end);
 
     HttpRequestMethod & operator = (const HttpRequestMethod& aMethod) {
         theMethod = aMethod.theMethod;
         theImage = aMethod.theImage;
         return *this;
     }
 
     HttpRequestMethod & operator = (Http::MethodType const aMethod) {
         theMethod = aMethod;
         theImage.clean();
         return *this;

=== added file 'src/http/forward.h'
--- src/http/forward.h	1970-01-01 00:00:00 +0000
+++ src/http/forward.h	2013-12-23 16:22:03 +0000
@@ -0,0 +1,26 @@
+#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 {
+
+class Http1Parser;
+typedef RefCount<Http1Parser> Http1ParserPointer;
+
+//class ParserBase;
+//typedef RefCount<Http::ParserBase> HttpParserPointer;
+
+} // namespace Http
+
+#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
@@ -1,29 +1,29 @@
 /*
  * DEBUG: section 16    Cache Manager API
  *
  */
 
 #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"
 
 namespace Mgr
 {
 
 /// Cache Manager Action parameters extracted from the user request
 class ActionParams
 {
 public:
     ActionParams();
 
     explicit ActionParams(const Ipc::TypedMsgHdr &msg); ///< load from msg
     void pack(Ipc::TypedMsgHdr &msg) const; ///< store into msg
 
 public:
     /* details of the client HTTP request that caused the action */
     String httpUri; ///< HTTP request URI
     HttpRequestMethod httpMethod; ///< HTTP request method

=== 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
@@ -1,30 +1,29 @@
 /*
  * DEBUG: section 16    Cache Manager API
  *
  */
 
 #ifndef SQUID_MGR_ACTION_WRITER_H
 #define SQUID_MGR_ACTION_WRITER_H
 
 #include "comm/forward.h"
-#include "HttpRequestMethod.h"
 #include "mgr/StoreToCommWriter.h"
 
 namespace Mgr
 {
 
 /// Creates Store entry, fills it using action's fillEntry(), and
 /// Comm-writes it using parent StoreToCommWriter.
 class ActionWriter: public StoreToCommWriter
 {
 public:
     ActionWriter(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn);
 
 protected:
     /* AsyncJob API */
     virtual void start();
 
 private:
     Action::Pointer action; ///< action that fills the entry
 
     CBDATA_CLASS2(ActionWriter);

=== 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
@@ -1,30 +1,29 @@
 /*
  * DEBUG: section 16    Cache Manager API
  *
  */
 
 #ifndef SQUID_MGR_FILLER_H
 #define SQUID_MGR_FILLER_H
 
 #include "comm/forward.h"
-#include "HttpRequestMethod.h"
 #include "mgr/Action.h"
 #include "mgr/StoreToCommWriter.h"
 
 namespace Mgr
 {
 
 /// provides Coordinator with a local cache manager response
 class Filler: public StoreToCommWriter
 {
 public:
     Filler(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn, unsigned int aRequestId);
 
 protected:
     /* AsyncJob API */
     virtual void start();
     virtual void swanSong();
 
 private:
     Action::Pointer action; ///< action that will run() and sendResponse()
     unsigned int requestId; ///< the ID of the Request we are responding to

=== modified file 'src/mime.cc'
--- src/mime.cc	2013-03-23 11:47:20 +0000
+++ src/mime.cc	2013-12-31 03:43:08 +0000
@@ -34,42 +34,40 @@
 #include "disk.h"
 #include "fde.h"
 #include "globals.h"
 #include "HttpHdrCc.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "internal.h"
 #include "Mem.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "mime.h"
 #include "RequestFlags.h"
 #include "SquidConfig.h"
 #include "Store.h"
 #include "StoreClient.h"
 
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 
-#define GET_HDR_SZ 1024
-
 /* forward declarations */
 static void mimeFreeMemory(void);
 static char const *mimeGetIcon(const char *fn);
 
 class MimeIcon : public StoreClient
 {
 public:
     explicit MimeIcon(const char *aName);
     ~MimeIcon();
     void setName(char const *);
     char const * getName() const;
     void load();
     void created(StoreEntry *newEntry);
     MEMPROXY_CLASS(MimeIcon);
 
 private:
     const char *icon_;
     char *url_;
 };
 MEMPROXY_CLASS_INLINE(MimeIcon);

=== 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
@@ -14,125 +14,43 @@
  *  incorporates software developed and/or copyrighted by other
  *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #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)
 {
     size_t e = 0;
     int state = 1;
 
     PROF_start(headersEnd);
 
     while (e < l && state < 3) {
         switch (state) {
 
         case 0:
 
             if ('\n' == mime[e])
                 state = 1;
 
             break;
 
         case 1:
             if ('\r' == mime[e])

=== 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
@@ -16,25 +16,23 @@
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #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_ */

=== 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	2013-12-30 13:53:06 +0000
@@ -1,1101 +1,1232 @@
 #define SQUID_UNIT_TEST 1
 #include "squid.h"
 
 #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)
         return;
 
     Mem::Init();
     setup_done = true;
 }
 
 void
-testHttpParser::testParseRequestLineProtocols()
+testHttp1Parser::testParseRequestLineProtocols()
 {
     // ensure MemPools etc exist
     globalSetup();
 
     MemBuf input;
-    HttpParser output;
+    Http::Http1Parser output;
     input.init();
 
     // TEST: Do we comply with RFC 1945 section 5.1 ?
     // TEST: Do we comply with RFC 2616 section 5.1 ?
 
     // RFC 1945 : HTTP/0.9 simple-request
     {
         input.append("GET /\r\n", 7);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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, 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();
     }
 
     // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
 #if 0
     {
         input.append("POST /\r\n", 7);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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
 
     // RFC 1945 and 2616 : HTTP/1.0 request
     {
         input.append("GET / HTTP/1.0\r\n", 16);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.0\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(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();
     }
 
     // RFC 2616 : HTTP/1.1 request
     {
         input.append("GET / HTTP/1.1\r\n", 16);
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\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(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.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.2\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(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.parseRequest()); // 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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/10.12\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(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();
     }
 
     // This stage of the parser does not yet accept non-HTTP protocol names.
     {
         // violations mode treats them as HTTP/0.9 requests!
         input.append("GET / FOO/1.0\n", 14);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
 #if USE_HTTP_VIOLATIONS
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / FOO/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(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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("FOO/1.0", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
         input.reset();
     }
 
     // no version
     {
         input.append("GET / HTTP/\n", 12);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/\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(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();
     }
 
     // no major version
     {
         input.append("GET / HTTP/.1\n", 14);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/.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(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();
     }
 
     // no version dot
     {
         input.append("GET / HTTP/11\n", 14);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/11\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(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();
     }
 
     // negative major version (bug 3062)
     {
         input.append("GET / HTTP/-999999.1\n", 21);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/-999999.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(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();
     }
 
     // no minor version
     {
         input.append("GET / HTTP/1.\n", 14);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/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(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();
     }
 
     // negative major version (bug 3062 corollary)
     {
         input.append("GET / HTTP/1.-999999\n", 21);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.-999999\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(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;
+    Http::Http1Parser output;
     input.init();
 
     // space padded URL
     {
         input.append("GET  /     HTTP/1.1\r\n", 21);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET  /     HTTP/1.1\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(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();
     }
 
     // whitespace inside URI. (nasty but happens)
     {
         input.append("GET /fo o/ HTTP/1.1\n", 20);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0,memcmp("GET /fo o/ 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(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();
     }
 
     // additional data in buffer
     {
         input.append("GET /     HTTP/1.1\nboo!", 23);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         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(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;
+    Http::Http1Parser output;
     input.init();
 
     // alternative EOL sequence: NL-only
     {
         input.append("GET / HTTP/1.1\n", 15);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         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(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();
     }
 
     // alternative EOL sequence: double-NL-only
     {
         input.append("GET / HTTP/1.1\n\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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);
         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(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();
     }
 
     // RELAXED alternative EOL sequence: multi-CR-NL
     {
         input.append("GET / HTTP/1.1\r\r\r\n", 18);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
         Config.onoff.relaxed_header_parser = 1;
         // Being tolerant we can ignore and elide these apparently benign CR
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\r\r\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(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
     {
         input.append("GET / HTTP/1.1\r\r\r\n", 18);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
         // strict mode treats these as several bare-CR in the request line which is explicitly invalid.
         Config.onoff.relaxed_header_parser = 0;
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(-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();
     }
 
     // space padded version
     {
         // RFC 1945 and 2616 specify version is followed by CRLF. No intermediary bytes.
         // NP: the terminal whitespace is a special case: invalid for even HTTP/0.9 with no version tag
         input.append("GET / HTTP/1.1 \n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(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();
     }
 
     // incomplete line at various positions
     {
         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.parseRequest());
+        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(!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.parseRequest());
+        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(!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.parseRequest());
+        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(!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.parseRequest());
+        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(!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;
+    Http::Http1Parser output;
     input.init();
 
     // RFC 2616 : . method
     {
         input.append(". / HTTP/1.1\n", 13);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp(". / 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(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();
     }
 
     // OPTIONS with * URL
     {
         input.append("OPTIONS * HTTP/1.1\n", 19);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("OPTIONS * 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(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();
     }
 
     // unknown method
     {
         input.append("HELLOWORLD / HTTP/1.1\n", 22);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("HELLOWORLD / 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(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();
     }
 
     // method-only
     {
         input.append("A\n", 2);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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\n", 4);
     {
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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();
     }
 
     // RELAXED space padded method (in strict mode SP is reserved so invalid as a method byte)
     {
         input.append(" GET / HTTP/1.1\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
         Config.onoff.relaxed_header_parser = 1;
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         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(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)
     {
         input.append(" GET / HTTP/1.1\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
         Config.onoff.relaxed_header_parser = 0;
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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();
     }
 
     // tab padded method (NP: tab is not SP so treated as any other binary)
     {
         input.append("\tGET / HTTP/1.1\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("\tGET / 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(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;
+    Http::Http1Parser output;
     input.init();
 
     // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
     {
         // XXX: Bug: HTTP/0.9 requires method to be "GET"
         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.parseRequest());
+        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("/ 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(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();
     }
 
     // RELAXED no method (an invalid format)
     {
         input.append(" / HTTP/1.0\n", 12);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
+        // 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.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("/ HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         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)
     {
         input.append(" / HTTP/1.0\n", 12);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
         // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
         Config.onoff.relaxed_header_parser = 0;
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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();
     }
 
     // binary code in method (strange but ...)
     {
         input.append("GET\x0B / HTTP/1.1\n", 16);
         //printf("TEST: %d-%d/%d '%.*s'\n", output.req.start, output.req.end, input.contentSize(), 16, input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\x0B / 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(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();
     }
 
     // CR in method
     {
         // RFC 2616 sec 5.1 prohibits CR other than in terminator.
         input.append("GET\r / HTTP/1.1\r\n", 16);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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();
     }
 
     // binary code NUL! in method (strange but ...)
     {
         input.append("GET\0 / HTTP/1.1\n", 16);
         //printf("TEST: %d-%d/%d '%.*s'\n", output.req.start, output.req.end, input.contentSize(), 16, input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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);
         CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\0 / 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(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();
     }
 
     // no URL (grammer otherwise correct)
     {
         input.append("GET  HTTP/1.1\n", 14);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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  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(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();
     }
 
     // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
     {
         input.append("GET HTTP/1.1\n", 13);
         //printf("TEST: '%s'\n",input.content());
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(true, output.parseRequest());
+        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 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(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();
     }
 
     // binary line
     {
         input.append("\xB\xC\xE\xF\n", 5);
         //printf("TEST: binary-line\n");
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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();
     }
 
     // mixed whitespace line
     {
         // We accept non-space binary bytes for method so first \t shows up as that
         // but remaining space and tabs are skipped searching for URI-start
         input.append("\t \t \t\n", 6);
         //printf("TEST: mixed whitespace\n");
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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("\t \t \t\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
         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();
     }
 
     // mixed whitespace line with CR middle
     {
         // CR aborts on sight, so even initial \t method is not marked as above
         // (not when parsing clean with whole line available anyway)
         input.append("\t  \r \n", 6);
         //printf("TEST: mixed whitespace with CR\n");
         output.reset(input.content(), input.contentSize());
-        CPPUNIT_ASSERT_EQUAL(-1, HttpParserParseReqLine(&output));
+        CPPUNIT_ASSERT_EQUAL(false, output.parseRequest());
+        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(!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);
+
+    Http::Http1Parser 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.parseRequest();
+
+#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,27 +1,30 @@
-#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:
     void globalSetup(); // MemPools init etc.
 
     // request-line unit tests
     void testParseRequestLineTerminators(); // terminator detection correct
     void testParseRequestLineMethods();     // methoid detection correct
     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
@@ -1,26 +1,26 @@
 #define SQUID_UNIT_TEST 1
 
 #include "squid.h"
 #include <cppunit/TestAssert.h>
 
-#include "HttpRequestMethod.h"
+#include "http/RequestMethod.h"
 #include "Mem.h"
 #include "SquidConfig.h"
 #include "testHttpRequestMethod.h"
 
 #if HAVE_SSTREAM
 #include <sstream>
 #endif
 
 CPPUNIT_TEST_SUITE_REGISTRATION( testHttpRequestMethod );
 
 /*
  * We should be able to make an HttpRequestMethod straight from a string.
  */
 void
 testHttpRequestMethod::testConstructCharStart()
 {
     /* parse an empty string -> Http::METHOD_NONE */
     CPPUNIT_ASSERT(HttpRequestMethod(NULL,NULL) == Http::METHOD_NONE);
     /* parsing a literal should work */
     CPPUNIT_ASSERT(HttpRequestMethod("GET", NULL) == Http::METHOD_GET);


