From: Amos Jeffries Date: Mon, 30 Dec 2013 18:18:03 +0000 (-0800) Subject: Shuffle request headersEnd call into Http1Parser::parseRequest actions X-Git-Tag: merge-candidate-3-v1~506^2~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f488052601d09ce46c410c5089413125d326719e;p=thirdparty%2Fsquid.git Shuffle request headersEnd call into Http1Parser::parseRequest actions Http1Parser will now respond with signals for 'incomplete parse' until the entire first line and any mime headers are present. The size and content of mime headers are guaranteed once the parser responds with a true result. HTTP/0.9, HTTP/1.* and future versions using "HTTP/" are all accounted for and handled in accordance with HTTP RFC 2616 requirements (adjusted for later HTTPbis WG clarifications). TODO: Parsing of the mime header fields. --- diff --git a/src/Makefile.am b/src/Makefile.am index dca9bd5a1b..f0544bb742 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2519,6 +2519,8 @@ tests_testHttp1Parser_SOURCES = \ MemBuf.h \ Mem.h \ tests/stub_mem.cc \ + mime_header.cc \ + mime_header.h \ String.cc \ cache_cf.h \ YesNoNone.h \ diff --git a/src/client_side.cc b/src/client_side.cc index a0052656a3..9be78b100d 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -2214,8 +2214,6 @@ prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, static ClientSocketContext * parseHttpRequest(ConnStateData *csd, const Http::Http1ParserPointer &hp) { - char *req_hdr = NULL; - char *end; size_t req_sz; ClientHttpRequest *http; ClientSocketContext *result; @@ -2245,31 +2243,14 @@ parseHttpRequest(ConnStateData *csd, const Http::Http1ParserPointer &hp) return parseHttpRequestAbort(csd, "error:invalid-request"); } - /* Request line is valid here .. */ - - /* This call scans the entire request, not just the headers */ - if (hp->messageProtocol().major > 0) { - if ((req_sz = headersEnd(hp->buf, hp->bufsiz)) == 0) { - debugs(33, 5, "Incomplete request, waiting for end of headers"); - return NULL; - } - } else { - debugs(33, 3, "parseHttpRequest: Missing HTTP identifier"); - req_sz = hp->firstLineSize(); - } - /* 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"); @@ -2298,17 +2279,13 @@ parseHttpRequest(ConnStateData *csd, const Http::Http1ParserPointer &hp) * 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; + const char *req_hdr = hp->rawHeaderBuf(); - debugs(33, 3, "parseHttpRequest: end = {" << end << "}"); + debugs(33, 3, Raw("req_hdr", req_hdr, hp->headerBlockSize())); - debugs(33, 3, "parseHttpRequest: prefix_sz = " << - hp->messageHeaderSize() << ", request-line-size=" << - hp->firstLineSize()); + 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); diff --git a/src/http/Http1Parser.cc b/src/http/Http1Parser.cc index 8b535c0212..db289f1130 100644 --- a/src/http/Http1Parser.cc +++ b/src/http/Http1Parser.cc @@ -2,6 +2,7 @@ #include "Debug.h" #include "http/Http1Parser.h" #include "http/RequestMethod.h" +#include "mime_header.h" #include "profiler/Profiler.h" #include "SquidConfig.h" @@ -20,6 +21,7 @@ Http::Http1Parser::clear() req.v_start = req.v_end = -1; msgProtocol_ = AnyP::ProtocolVersion(); method_ = NULL; + mimeHeaderBytes_ = 0; } void @@ -44,8 +46,6 @@ Http::Http1Parser::parseRequestFirstLine() // Single-pass parse: (provided we have the whole line anyways) - assert(completedState_ == HTTP_PARSE_NEW); - req.start = parseOffset_; // avoid re-parsing any portion we managed to complete if (Config.onoff.relaxed_header_parser) { if (Config.onoff.relaxed_header_parser < 0 && buf[req.start] == ' ') @@ -155,6 +155,7 @@ Http::Http1Parser::parseRequestFirstLine() 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 { @@ -254,16 +255,51 @@ Http::Http1Parser::parseRequestFirstLine() bool Http::Http1Parser::parseRequest() { - PROF_start(HttpParserParseReqLine); - int retcode = parseRequestFirstLine(); - debugs(74, 5, "Parser: retval " << retcode << ": from " << req.start << - "->" << req.end << ": method " << req.m_start << "->" << - req.m_end << "; url " << req.u_start << "->" << req.u_end << - "; proto-version " << req.v_start << "->" << req.v_end << " (" << msgProtocol_ << ")"); - PROF_stop(HttpParserParseReqLine); - - if (retcode != 0) + // stage 1: locate the request-line + // 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 << " " << Raw("field", &buf[req.u_start], req.u_end-req.u_start)); + debugs(74, 5, "request-line: proto " << req.v_start << "->" << req.v_end << " (" << msgProtocol_ << ")"); + debugs(74, 5, "Parser: parse-offset=" << parseOffset_); + PROF_stop(HttpParserParseReqLine); + if (retcode < 0) { + completedState_ = HTTP_PARSE_DONE; + return false; + } + } + + // stage 3: locate the mime header block + if (completedState_ == HTTP_PARSE_FIRST) { + + // NP: set these to same value representing 0-byte headers. + hdr_start = req.end + 1; + hdr_end = hdr_start; + + // 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) + */ + if ((mimeHeaderBytes_ = headersEnd(buf+parseOffset_, bufsiz-parseOffset_)) == 0) { + debugs(33, 5, "Incomplete request, waiting for end of headers"); + return false; + } + + hdr_start = req.end + 1; + hdr_end = parseOffset_ + mimeHeaderBytes_ - 1; + + } else + debugs(33, 3, "Missing HTTP/1.x identifier"); + + // NP: planned name for this stage is HTTP_PARSE_MIME + // but we do not do any further stages here yet so go straight to DONE completedState_ = HTTP_PARSE_DONE; + } - return (retcode > 0); + return isDone(); } diff --git a/src/http/Http1Parser.h b/src/http/Http1Parser.h index 0be9b09b33..c50685e159 100644 --- a/src/http/Http1Parser.h +++ b/src/http/Http1Parser.h @@ -12,6 +12,7 @@ namespace Http { #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. @@ -54,16 +55,17 @@ public: /// including CRLF terminator int64_t firstLineSize() const {return req.end - req.start + 1;} - /// size in bytes of the message headers including CRLF terminator + /// size in bytes of the message headers including CRLF terminator(s) /// but excluding request-line bytes - int64_t headerBlockSize() const {return hdr_end - hdr_start + 1;} + int64_t headerBlockSize() const {return mimeHeaderBytes_;} /// size in bytes of HTTP message block, includes request-line and mime headers /// excludes any body/entity/payload bytes - int64_t messageHeaderSize() const {return hdr_end - req.start + 1;} + /// excludes any garbage prefix before the request-line + int64_t messageHeaderSize() const {return firstLineSize() + headerBlockSize();} /// buffer containing HTTP mime headers - // convert to SBuf + // TODO: convert to SBuf const char *rawHeaderBuf() {return buf + hdr_start;} /** Attempt to parse a request. @@ -109,6 +111,7 @@ public: const HttpRequestMethodPointer & method() const {return method_;} // Offsets for pieces of the MiME Header segment + // \deprecated use rawHeaderBuf() and headerBlockSize() instead int hdr_start, hdr_end; // TODO: Offsets for pieces of the (HTTP reply) Status-Line as per RFC 2616 @@ -130,6 +133,9 @@ private: /// what request method has been found on the first line HttpRequestMethodPointer method_; + + /// number of bytes in the mime header block + int64_t mimeHeaderBytes_; }; } // namespace Http diff --git a/src/tests/testHttp1Parser.cc b/src/tests/testHttp1Parser.cc index 50281f4cae..a49dbf45ca 100644 --- a/src/tests/testHttp1Parser.cc +++ b/src/tests/testHttp1Parser.cc @@ -92,8 +92,9 @@ testHttp1Parser::testParseRequestLineProtocols() { input.append("GET / HTTP/1.0\r\n", 16); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -116,8 +117,9 @@ testHttp1Parser::testParseRequestLineProtocols() { input.append("GET / HTTP/1.1\r\n", 16); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -137,11 +139,13 @@ testHttp1Parser::testParseRequestLineProtocols() } // 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(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -162,11 +166,12 @@ testHttp1Parser::testParseRequestLineProtocols() // 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(true, output.parseRequest()); + 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); @@ -387,8 +392,9 @@ testHttp1Parser::testParseRequestLineStrange() input.append("GET / HTTP/1.1\r\n", 21); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -412,8 +418,9 @@ testHttp1Parser::testParseRequestLineStrange() 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(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -437,8 +444,9 @@ testHttp1Parser::testParseRequestLineStrange() input.append("GET / HTTP/1.1\nboo!", 23); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -473,8 +481,9 @@ testHttp1Parser::testParseRequestLineTerminators() input.append("GET / HTTP/1.1\n", 15); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -525,8 +534,9 @@ testHttp1Parser::testParseRequestLineTerminators() 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(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -543,6 +553,7 @@ testHttp1Parser::testParseRequestLineTerminators() 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; } // STRICT alternative EOL sequence: multi-CR-NL @@ -684,8 +695,9 @@ testHttp1Parser::testParseRequestLineMethods() input.append(". / HTTP/1.1\n", 13); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -709,8 +721,9 @@ testHttp1Parser::testParseRequestLineMethods() input.append("OPTIONS * HTTP/1.1\n", 19); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -734,8 +747,9 @@ testHttp1Parser::testParseRequestLineMethods() input.append("HELLOWORLD / HTTP/1.1\n", 22); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -803,8 +817,9 @@ testHttp1Parser::testParseRequestLineMethods() //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); Config.onoff.relaxed_header_parser = 1; - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -821,6 +836,7 @@ testHttp1Parser::testParseRequestLineMethods() 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; } // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte) @@ -844,7 +860,6 @@ testHttp1Parser::testParseRequestLineMethods() CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end); CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_); input.reset(); - Config.onoff.relaxed_header_parser = 1; } // tab padded method (NP: tab is not SP so treated as any other binary) @@ -852,8 +867,9 @@ testHttp1Parser::testParseRequestLineMethods() input.append("\tGET / HTTP/1.1\n", 16); //printf("TEST: '%s'\n",input.content()); output.reset(input.content(), input.contentSize()); - CPPUNIT_ASSERT_EQUAL(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -913,10 +929,11 @@ testHttp1Parser::testParseRequestLineInvalid() 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(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); @@ -932,6 +949,7 @@ testHttp1Parser::testParseRequestLineInvalid() 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; } // STRICT no method (an invalid format) @@ -963,8 +981,9 @@ testHttp1Parser::testParseRequestLineInvalid() 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(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -1010,8 +1029,9 @@ testHttp1Parser::testParseRequestLineInvalid() 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(true, output.parseRequest()); - CPPUNIT_ASSERT_EQUAL(true, output.isDone()); + 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); @@ -1162,14 +1182,14 @@ testHttp1Parser::testDripFeed() int garbageEnd = mb.contentSize(); mb.append("GET http://example.com/ HTTP/1.1\r\n", 34); int reqLineEnd = mb.contentSize(); - mb.append("\n", 1); + 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) { + for (; hp.bufsiz <= mb.contentSize(); ++hp.bufsiz) { bool parseResult = hp.parseRequest(); #if WHEN_TEST_DEBUG_IS_NEEDED @@ -1190,6 +1210,17 @@ testHttp1Parser::testDripFeed() 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; }