-#define SQUID_UNIT_TEST 1
+/*
+ * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
#include "squid.h"
#include <cppunit/TestAssert.h>
#define private public
#define protected public
-#include "testHttp1Parser.h"
-#include "http/Http1Parser.h"
+#include "Debug.h"
+#include "http/one/RequestParser.h"
#include "http/RequestMethod.h"
-#include "Mem.h"
#include "MemBuf.h"
#include "SquidConfig.h"
#include "testHttp1Parser.h"
+#include "unitTestMain.h"
CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser );
Config.maxRequestHeaderSize = 1024; // XXX: unit test the RequestParser handling of this limit
}
+struct resultSet {
+ bool parsed;
+ bool needsMore;
+ Http1::ParseState parserState;
+ Http::StatusCode status;
+ SBuf::size_type suffixSz;
+ HttpRequestMethod method;
+ const char *uri;
+ AnyP::ProtocolVersion version;
+};
+
+// define SQUID_DEBUG_TESTS to see exactly which test sub-cases fail and where
+#ifdef SQUID_DEBUG_TESTS
+// not optimized for runtime use
+static void
+Replace(SBuf &where, const SBuf &what, const SBuf &with)
+{
+ // prevent infinite loops
+ if (!what.length() || with.find(what) != SBuf::npos)
+ return;
+
+ SBuf::size_type pos = 0;
+ while ((pos = where.find(what, pos)) != SBuf::npos) {
+ SBuf buf = where.substr(0, pos);
+ buf.append(with);
+ buf.append(where.substr(pos+what.length()));
+ where = buf;
+ pos += with.length();
+ }
+}
+
+static SBuf Pretty(SBuf raw)
+{
+ Replace(raw, SBuf("\r"), SBuf("\\r"));
+ Replace(raw, SBuf("\n"), SBuf("\\n"));
+ return raw;
+}
+#endif
+
+static void
+testResults(int line, const SBuf &input, Http1::RequestParser &output, struct resultSet &expect)
+{
+#ifdef SQUID_DEBUG_TESTS
+ std::cerr << "TEST @" << line << ", in=" << Pretty(input) << "\n";
+#endif
+
+ const bool parsed = output.parse(input);
+
+#ifdef SQUID_DEBUG_TESTS
+ if (expect.parsed != parsed)
+ std::cerr << "\tparse-FAILED: " << expect.parsed << "!=" << parsed << "\n";
+ else if (parsed && expect.method != output.method_)
+ std::cerr << "\tmethod-FAILED: " << expect.method << "!=" << output.method_ << "\n";
+ if (expect.status != output.parseStatusCode)
+ std::cerr << "\tscode-FAILED: " << expect.status << "!=" << output.parseStatusCode << "\n";
+ if (expect.suffixSz != output.buf_.length())
+ std::cerr << "\tsuffixSz-FAILED: " << expect.suffixSz << "!=" << output.buf_.length() << "\n";
+#endif
+
+ // runs the parse
+ CPPUNIT_ASSERT_EQUAL(expect.parsed, parsed);
+
+ // if parsing was successful, check easily visible field outputs
+ if (parsed) {
+ CPPUNIT_ASSERT_EQUAL(expect.method, output.method_);
+ if (expect.uri != NULL)
+ CPPUNIT_ASSERT_EQUAL(0, output.uri_.cmp(expect.uri));
+ CPPUNIT_ASSERT_EQUAL(expect.version, output.msgProtocol_);
+ }
+
+ CPPUNIT_ASSERT_EQUAL(expect.status, output.parseStatusCode);
+
+ // check more obscure states
+ CPPUNIT_ASSERT_EQUAL(expect.needsMore, output.needsMoreData());
+ if (output.needsMoreData())
+ CPPUNIT_ASSERT_EQUAL(expect.parserState, output.parsingStage_);
+ CPPUNIT_ASSERT_EQUAL(expect.suffixSz, output.buf_.length());
+}
+
+void
+testHttp1Parser::testParserConstruct()
+{
+ // whether the constructor works
+ {
+ Http1::RequestParser output;
+ CPPUNIT_ASSERT_EQUAL(true, output.needsMoreData());
+ CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output.parsingStage_);
+ CPPUNIT_ASSERT_EQUAL(Http::scNone, output.parseStatusCode); // XXX: clear() not being called.
+ CPPUNIT_ASSERT(output.buf_.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output.method_);
+ CPPUNIT_ASSERT(output.uri_.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
+ }
+
+ // whether new() works
+ {
+ Http1::RequestParser *output = new Http1::RequestParser;
+ CPPUNIT_ASSERT_EQUAL(true, output->needsMoreData());
+ CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output->parsingStage_);
+ CPPUNIT_ASSERT_EQUAL(Http::scNone, output->parseStatusCode);
+ CPPUNIT_ASSERT(output->buf_.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output->method_);
+ CPPUNIT_ASSERT(output->uri_.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output->msgProtocol_);
+ delete output;
+ }
+}
+
void
testHttp1Parser::testParseRequestLineProtocols()
{
// ensure MemPools etc exist
globalSetup();
- MemBuf input;
+ SBuf input;
Http1::RequestParser output;
- input.init();
// TEST: Do we comply with RFC 1945 section 5.1 ?
- // TEST: Do we comply with RFC 2616 section 5.1 ?
+ // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
// RFC 1945 : HTTP/0.9 simple-request
{
input.append("GET /\r\n", 7);
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0,memcmp("GET /\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = true,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0,memcmp("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(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(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ input.append("POST /\r\n", 8);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_POST),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
-#endif
- // RFC 1945 and 2616 : HTTP/1.0 request
+ // RFC 1945 and 7230 : HTTP/1.0 request
{
input.append("GET / HTTP/1.0\r\n", 16);
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // RFC 2616 : HTTP/1.1 request
+ // RFC 7230 : HTTP/1.1 request
{
input.append("GET / HTTP/1.1\r\n", 16);
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // RFC 2616 : future version full-request
+ // RFC 7230 : future 1.x version full-request
{
input.append("GET / HTTP/1.2\r\n", 16);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // RFC 2616 : future version full-request
+ // RFC 7230 : future versions do not use 1.x message syntax.
+ // However, it is still valid syntax for the single-digit forms
+ // to appear. The parser we are testing should accept them.
+ {
+ input.append("GET / HTTP/2.0\r\n", 16);
+ struct resultSet expectA = {
+ .parsed = true,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,2,0)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectA);
+ input.clear();
+
+ input.append("GET / HTTP/9.9\r\n", 16);
+ struct resultSet expectB = {
+ .parsed = true,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,9,9)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectB);
+ input.clear();
+ }
+
+ // RFC 7230 : future versions >= 10.0 are invalid syntax
{
- // IETF HTTPbis WG has made this two-digits format invalid.
- // it gets treated same as HTTP/0.9 for now
input.append("GET / HTTP/10.12\r\n", 18);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(true, output.parse()); // BUG: declares true
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,10,12), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // This stage of the parser does not yet accept non-HTTP protocol names.
+ // unknown 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(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(12, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("/ FOO/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
-#else
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
- CPPUNIT_ASSERT_EQUAL(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();
+ input.append("GET / FOO/1.0\r\n", 15);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // no version
+ // no version digits
{
- input.append("GET / HTTP/\n", 12);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/\r\n", 13);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/.1\r\n", 15);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/11\r\n", 15);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/-999999.1\r\n", 22);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/1.\r\n", 15);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/1.-999999\r\n", 22);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
}
// ensure MemPools etc exist
globalSetup();
- MemBuf input;
+ SBuf input;
Http1::RequestParser 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ // when being tolerant extra (sequential) SP delimiters are acceptable
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
+ Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("GET /fo o/ HTTP/1.1\r\n", 21);
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/fo o/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
+ Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-5, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("GET / HTTP/1.1\r\nboo!", 20);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 4, // strlen("boo!")
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
+ Config.onoff.relaxed_header_parser = 0;
}
}
// ensure MemPools etc exist
globalSetup();
- MemBuf input;
+ SBuf input;
Http1::RequestParser output;
- input.init();
// alternative EOL sequence: NL-only
+ // RFC 7230 tolerance permits omitted CR
{
input.append("GET / HTTP/1.1\n", 15);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
+ Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
// alternative EOL sequence: double-NL-only
+ // RFC 7230 tolerance permits omitted CR
+ // NP: represents a request with no mime headers
{
input.append("GET / HTTP/1.1\n\n", 16);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-2, output.req.end);
- 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(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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
- Config.onoff.relaxed_header_parser = 0;
- }
+ struct resultSet expect = {
+ .parsed = true,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
- // 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(-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(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1 \n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(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(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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
+ input.append("GET / HTTP/1.1 \r\n", 17);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
}
// ensure MemPools etc exist
globalSetup();
- MemBuf input;
+ SBuf input;
Http1::RequestParser output;
- input.init();
- // RFC 2616 : . method
+ // RFC 7230 : dot method
+ {
+ input.append(". / HTTP/1.1\r\n", 14);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(SBuf(".")),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
+ }
+
+ // RFC 7230 : special TCHAR method chars
{
- input.append(". / HTTP/1.1\n", 13);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("OPTIONS * HTTP/1.1\r\n", 20);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_OPTIONS),
+ .uri = "*",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("HELLOWORLD / HTTP/1.1\r\n", 23);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(SBuf("HELLOWORLD")),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
+#if 0
+ // too-long method (over 16 bytes)
+ {
+ input.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scNotImplemented,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
+ }
+#endif
+
// method-only
{
input.append("A\n", 2);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("A\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- input.append("GET\n", 4);
{
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ input.append("GET\n", 4);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
+ }
+
+ // space padded method (SP is reserved so invalid as a method byte)
+ {
+ input.append(" GET / HTTP/1.1\r\n", 17);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // RELAXED space padded method (in strict mode SP is reserved so invalid as a method byte)
+ // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
{
- input.append(" GET / HTTP/1.1\n", 16);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
+ input.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
Config.onoff.relaxed_header_parser = 1;
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(1, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
+ }
+
+ // forbidden character in method
+ {
+ input.append("\tGET / HTTP/1.1\r\n", 17);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte)
+ // CR in method delimiters
{
- input.append(" GET / HTTP/1.1\n", 16);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
+ // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
+ input.append("GET\r / HTTP/1.1\r\n", 17);
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
Config.onoff.relaxed_header_parser = 0;
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp(" GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
- input.reset();
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
- // tab padded method (NP: tab is not SP so treated as any other binary)
+ // tolerant parser delimiters
{
- input.append("\tGET / HTTP/1.1\n", 16);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
+ input.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_MIME,
+ .status = Http::scOkay,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(Http::METHOD_GET),
+ .uri = "/",
+ .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+
+ Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
}
// ensure MemPools etc exist
globalSetup();
- MemBuf input;
+ SBuf input;
Http1::RequestParser output;
- input.init();
- // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
+ // no method (or method delimiter)
{
- // XXX: Bug: HTTP/0.9 requires method to be "GET"
+ // 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(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("/ 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(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());
- // 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(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
-// CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_NEW, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(1, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
- input.reset();
- Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // STRICT no method (an invalid format)
+ // no method (with method delimiter)
{
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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp(" / HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
- input.reset();
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
- // binary code in method (strange but ...)
+ // binary code after method (invalid)
{
- 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
+ input.append("GET\x16 / HTTP/1.1\r\n", 17);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // CR in method
+ // binary code NUL! after method (always invalid)
{
- // 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ input.append("GET\0 / HTTP/1.1\r\n", 17);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // binary code NUL! in method (strange but ...)
+ // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
+ // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
{
- 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(false, output.isDone());
- CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
- input.reset();
- }
+ input.append("GET HTTP/1.1\r\n", 15);
+ Config.onoff.relaxed_header_parser = 1;
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
- // 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(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("GET 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
- input.reset();
+ Config.onoff.relaxed_header_parser = 0;
+ struct resultSet expectStrict = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expectStrict);
+ input.clear();
}
- // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
+ // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
+ // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
{
- input.append("GET HTTP/1.1\n", 13);
- //printf("TEST: '%s'\n",input.content());
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(true, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("GET 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(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
- input.reset();
+ input.append("GET HTTP/1.1\r\n", 14);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// binary line
{
input.append("\xB\xC\xE\xF\n", 5);
- //printf("TEST: binary-line\n");
- output.reset(input.content(), input.contentSize());
- CPPUNIT_ASSERT_EQUAL(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("\xB\xC\xE\xF\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
- CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
// 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(0, memcmp("\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(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
- // mixed whitespace line with CR middle
+ // mixed whitespace line with CR
{
- // 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(false, output.parse());
- CPPUNIT_ASSERT_EQUAL(true, output.isDone());
- CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
- CPPUNIT_ASSERT_EQUAL(0, output.req.start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
- CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
- CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
- CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
- input.reset();
+ input.append("\r \t \n", 6);
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = false,
+ .parserState = Http1::HTTP_PARSE_DONE,
+ .status = Http::scBadRequest,
+ .suffixSz = input.length(),
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+ output.clear();
+ testResults(__LINE__, input, output, expect);
+ input.clear();
}
}
// extend the size of the buffer from 0 bytes to full request length
// calling the parser repeatedly as visible data grows.
- MemBuf mb;
- mb.init(1024, 1024);
- mb.append(" ", 12);
- int garbageEnd = mb.contentSize();
- mb.append("GET http://example.com/ HTTP/1.1\r\n", 34);
- int reqLineEnd = mb.contentSize();
- mb.append("Host: example.com\r\n\r\n.", 22);
-
- Http1::RequestParser hp(mb.content(), 0);
-
- // only relaxed parser accepts the garbage whitespace
- Config.onoff.relaxed_header_parser = 1;
-
- for (; hp.bufsiz <= mb.contentSize(); ++hp.bufsiz) {
- bool parseResult = hp.parse();
-
-#if WHEN_TEST_DEBUG_IS_NEEDED
- printf("%d/%d :: %d, %d, %d '%c'\n", hp.bufsiz, mb.contentSize(),
- garbageEnd, reqLineEnd, parseResult,
- mb.content()[hp.bufsiz]);
-#endif
-
- // before end of garbage found its a moving offset.
- if (hp.bufsiz < garbageEnd) {
- CPPUNIT_ASSERT_EQUAL(hp.bufsiz, (int)hp.parseOffset_);
- CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
- continue;
+ SBuf data;
+ data.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
+ SBuf::size_type garbageEnd = data.length();
+ data.append("GET ", 4);
+ data.append("http://example.com/ ", 20);
+ data.append("HTTP/1.1\r\n", 10);
+ SBuf::size_type reqLineEnd = data.length() - 1;
+ data.append("Host: example.com\r\n\r\n", 21);
+ SBuf::size_type mimeEnd = data.length() - 1;
+ data.append("...", 3); // trailer to catch mime EOS errors.
+
+ SBuf ioBuf;
+ Http1::RequestParser hp;
+
+ // start with strict and move on to relaxed
+ Config.onoff.relaxed_header_parser = 2;
+
+ Config.maxRequestHeaderSize = 1024; // large enough to hold the test data.
+
+ do {
+
+ // state of things we expect right now
+ struct resultSet expect = {
+ .parsed = false,
+ .needsMore = true,
+ .parserState = Http1::HTTP_PARSE_NONE,
+ .status = Http::scNone,
+ .suffixSz = 0,
+ .method = HttpRequestMethod(),
+ .uri = NULL,
+ .version = AnyP::ProtocolVersion()
+ };
+
+ ioBuf.clear(); // begins empty for each parser type
+ hp.clear();
+
+ --Config.onoff.relaxed_header_parser;
+
+ for (SBuf::size_type pos = 0; pos <= data.length(); ++pos) {
+
+ // simulate reading one more byte
+ ioBuf.append(data.substr(pos,1));
+
+ // strict does not permit the garbage prefix
+ if (pos < garbageEnd && !Config.onoff.relaxed_header_parser) {
+ ioBuf.clear();
+ continue;
+ }
+
+ // when the garbage is passed we expect to start seeing first-line bytes
+ if (pos == garbageEnd)
+ expect.parserState = Http1::HTTP_PARSE_FIRST;
+
+ // all points after garbage start to see accumulated bytes looking for end of current section
+ if (pos >= garbageEnd)
+ expect.suffixSz = ioBuf.length();
+
+ // at end of request line expect to see method, URI, version details
+ // and switch to seeking Mime header section
+ if (pos == reqLineEnd) {
+ expect.parserState = Http1::HTTP_PARSE_MIME;
+ expect.suffixSz = 0; // and a checkpoint buffer reset
+ expect.status = Http::scOkay;
+ expect.method = HttpRequestMethod(Http::METHOD_GET);
+ expect.uri = "http://example.com/";
+ expect.version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1);
+ }
+
+ // one mime header is done we are expecting a new request
+ // parse results say true and initial data is all gone from the buffer
+ if (pos == mimeEnd) {
+ expect.parsed = true;
+ expect.needsMore = false;
+ expect.suffixSz = 0; // and a checkpoint buffer reset
+ }
+
+ testResults(__LINE__, ioBuf, hp, expect);
+
+ // sync the buffers like Squid does
+ ioBuf = hp.remaining();
+
+ // Squid stops using the parser once it has parsed the first message.
+ if (!hp.needsMoreData())
+ break;
}
- // 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;
- }
+ } while (Config.onoff.relaxed_header_parser);
- // 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());
- }
}
+