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
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;
-}
};
-/* 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;}
--- /dev/null
+#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
+
--- /dev/null
+#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 */
HttpControlMsg.h \
HttpMsg.cc \
HttpMsg.h \
+ HttpParser.cc \
+ HttpParser.h \
HttpReply.cc \
HttpReply.h \
HttpRequest.cc \
tests/testEvent \
tests/testEventLoop \
tests/test_http_range \
+ tests/testHttpParser \
tests/testHttpReply \
tests/testHttpRequest \
tests/testStore \
tests_testCacheManager_SOURCES = \
$(ACL_REGISTRATION_SOURCES) \
debug.cc \
+ HttpParser.cc \
+ HttpParser.h \
HttpRequest.cc \
HttpRequestMethod.cc \
mem.cc \
HttpHdrSc.cc \
HttpHdrScTarget.cc \
HttpMsg.cc \
+ HttpParser.cc \
+ HttpParser.h \
HttpReply.cc \
HttpRequest.cc \
HttpRequestMethod.cc \
HttpHdrSc.cc \
HttpHdrScTarget.cc \
HttpMsg.cc \
+ HttpParser.cc \
+ HttpParser.h \
HttpReply.cc \
HttpRequest.cc \
HttpRequestMethod.cc \
HttpHeader.cc \
HttpHeaderTools.cc \
HttpMsg.cc \
+ HttpParser.cc \
+ HttpParser.h \
HttpReply.cc \
HttpRequest.cc \
HttpRequestMethod.cc \
$(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 \
HttpHeader.cc \
HttpHeaderTools.cc \
HttpMsg.cc \
+ HttpParser.cc \
+ HttpParser.h \
HttpReply.cc \
HttpRequest.cc \
HttpRequestMethod.cc \
#include "eui/Eui48.h"
#include "eui/Eui64.h"
#include "HttpControlMsg.h"
+#include "HttpParser.h"
#include "RefCount.h"
#include "StoreIOBuffer.h"
class ClientHttpRequest;
class clientStreamNode;
class ChunkedCodingParser;
-class HttpParser;
class ClientSocketContext : public RefCountable
{
--- /dev/null
+#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)
--- /dev/null
+#define SQUID_UNIT_TEST 1
+#include "config.h"
+
+#include <cppunit/TestAssert.h>
+
+#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();
+}
--- /dev/null
+#ifndef SQUID_SRC_TESTS_TESTHTTPPARSER_H
+#define SQUID_SRC_TESTS_TESTHTTPPARSER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+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
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();
-}
CPPUNIT_TEST( testCreateFromUrl );
CPPUNIT_TEST( testIPv6HostColonBug );
CPPUNIT_TEST( testSanityCheckStartLine );
- CPPUNIT_TEST( testParseRequestLine );
CPPUNIT_TEST_SUITE_END();
public:
void testCreateFromUrl();
void testIPv6HostColonBug();
void testSanityCheckStartLine();
- void testParseRequestLine();
};
#endif