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