]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
11 #include <cppunit/TestAssert.h>
13 #define private public
14 #define protected public
17 #include "http/one/RequestParser.h"
18 #include "http/RequestMethod.h"
20 #include "SquidConfig.h"
21 #include "testHttp1Parser.h"
22 #include "unitTestMain.h"
24 CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser
);
27 testHttp1Parser::globalSetup()
29 static bool setup_done
= false;
36 // default to strict parser. set for loose parsing specifically where behaviour differs.
37 Config
.onoff
.relaxed_header_parser
= 0;
39 Config
.maxRequestHeaderSize
= 1024; // XXX: unit test the RequestParser handling of this limit
42 #if __cplusplus >= 201103L
47 Http1::ParseState parserState
;
48 Http::StatusCode status
;
49 SBuf::size_type suffixSz
;
50 HttpRequestMethod method
;
52 AnyP::ProtocolVersion version
;
55 // define SQUID_DEBUG_TESTS to see exactly which test sub-cases fail and where
56 #ifdef SQUID_DEBUG_TESTS
57 // not optimized for runtime use
59 Replace(SBuf
&where
, const SBuf
&what
, const SBuf
&with
)
61 // prevent infinite loops
62 if (!what
.length() || with
.find(what
) != SBuf::npos
)
65 SBuf::size_type pos
= 0;
66 while ((pos
= where
.find(what
, pos
)) != SBuf::npos
) {
67 SBuf buf
= where
.substr(0, pos
);
69 buf
.append(where
.substr(pos
+what
.length()));
75 static SBuf
Pretty(SBuf raw
)
77 Replace(raw
, SBuf("\r"), SBuf("\\r"));
78 Replace(raw
, SBuf("\n"), SBuf("\\n"));
84 testResults(int line
, const SBuf
&input
, Http1::RequestParser
&output
, struct resultSet
&expect
)
86 #ifdef SQUID_DEBUG_TESTS
87 std::cerr
<< "TEST @" << line
<< ", in=" << Pretty(input
) << "\n";
90 const bool parsed
= output
.parse(input
);
92 #ifdef SQUID_DEBUG_TESTS
93 if (expect
.parsed
!= parsed
)
94 std::cerr
<< "\tparse-FAILED: " << expect
.parsed
<< "!=" << parsed
<< "\n";
95 else if (parsed
&& expect
.method
!= output
.method_
)
96 std::cerr
<< "\tmethod-FAILED: " << expect
.method
<< "!=" << output
.method_
<< "\n";
97 if (expect
.status
!= output
.parseStatusCode
)
98 std::cerr
<< "\tscode-FAILED: " << expect
.status
<< "!=" << output
.parseStatusCode
<< "\n";
99 if (expect
.suffixSz
!= output
.buf_
.length())
100 std::cerr
<< "\tsuffixSz-FAILED: " << expect
.suffixSz
<< "!=" << output
.buf_
.length() << "\n";
104 CPPUNIT_ASSERT_EQUAL(expect
.parsed
, parsed
);
106 // if parsing was successful, check easily visible field outputs
108 CPPUNIT_ASSERT_EQUAL(expect
.method
, output
.method_
);
109 if (expect
.uri
!= NULL
)
110 CPPUNIT_ASSERT_EQUAL(0, output
.uri_
.cmp(expect
.uri
));
111 CPPUNIT_ASSERT_EQUAL(expect
.version
, output
.msgProtocol_
);
114 CPPUNIT_ASSERT_EQUAL(expect
.status
, output
.parseStatusCode
);
116 // check more obscure states
117 CPPUNIT_ASSERT_EQUAL(expect
.needsMore
, output
.needsMoreData());
118 if (output
.needsMoreData())
119 CPPUNIT_ASSERT_EQUAL(expect
.parserState
, output
.parsingStage_
);
120 CPPUNIT_ASSERT_EQUAL(expect
.suffixSz
, output
.buf_
.length());
122 #endif /* __cplusplus >= 200103L */
125 testHttp1Parser::testParserConstruct()
127 // whether the constructor works
129 Http1::RequestParser output
;
130 CPPUNIT_ASSERT_EQUAL(true, output
.needsMoreData());
131 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
.parsingStage_
);
132 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
.parseStatusCode
); // XXX: clear() not being called.
133 CPPUNIT_ASSERT(output
.buf_
.isEmpty());
134 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
.method_
);
135 CPPUNIT_ASSERT(output
.uri_
.isEmpty());
136 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
.msgProtocol_
);
139 // whether new() works
141 Http1::RequestParser
*output
= new Http1::RequestParser
;
142 CPPUNIT_ASSERT_EQUAL(true, output
->needsMoreData());
143 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
->parsingStage_
);
144 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
->parseStatusCode
);
145 CPPUNIT_ASSERT(output
->buf_
.isEmpty());
146 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
->method_
);
147 CPPUNIT_ASSERT(output
->uri_
.isEmpty());
148 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
->msgProtocol_
);
153 #if __cplusplus >= 201103L
155 testHttp1Parser::testParseRequestLineProtocols()
157 // ensure MemPools etc exist
161 Http1::RequestParser output
;
163 // TEST: Do we comply with RFC 1945 section 5.1 ?
164 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
166 // RFC 1945 : HTTP/0.9 simple-request
168 input
.append("GET /\r\n", 7);
169 struct resultSet expect
= {
172 .parserState
= Http1::HTTP_PARSE_DONE
,
173 .status
= Http::scOkay
,
175 .method
= HttpRequestMethod(Http::METHOD_GET
),
177 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,0,9)
180 testResults(__LINE__
, input
, output
, expect
);
184 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
186 input
.append("POST /\r\n", 8);
187 struct resultSet expect
= {
190 .parserState
= Http1::HTTP_PARSE_DONE
,
191 .status
= Http::scBadRequest
,
192 .suffixSz
= input
.length(),
193 .method
= HttpRequestMethod(Http::METHOD_POST
),
195 .version
= AnyP::ProtocolVersion()
198 testResults(__LINE__
, input
, output
, expect
);
202 // RFC 1945 and 7230 : HTTP/1.0 request
204 input
.append("GET / HTTP/1.0\r\n", 16);
205 struct resultSet expect
= {
208 .parserState
= Http1::HTTP_PARSE_MIME
,
209 .status
= Http::scOkay
,
211 .method
= HttpRequestMethod(Http::METHOD_GET
),
213 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,0)
216 testResults(__LINE__
, input
, output
, expect
);
220 // RFC 7230 : HTTP/1.1 request
222 input
.append("GET / HTTP/1.1\r\n", 16);
223 struct resultSet expect
= {
226 .parserState
= Http1::HTTP_PARSE_MIME
,
227 .status
= Http::scOkay
,
229 .method
= HttpRequestMethod(Http::METHOD_GET
),
231 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
234 testResults(__LINE__
, input
, output
, expect
);
238 // RFC 7230 : future version full-request
240 input
.append("GET / HTTP/1.2\r\n", 16);
241 struct resultSet expect
= {
244 .parserState
= Http1::HTTP_PARSE_MIME
,
245 .status
= Http::scOkay
,
247 .method
= HttpRequestMethod(Http::METHOD_GET
),
249 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,2)
252 testResults(__LINE__
, input
, output
, expect
);
256 // RFC 7230 : future versions do not use request-line syntax
258 input
.append("GET / HTTP/2.0\r\n", 16);
259 struct resultSet expectA
= {
262 .parserState
= Http1::HTTP_PARSE_MIME
,
263 .status
= Http::scBadRequest
,
264 .suffixSz
= input
.length(),
265 .method
= HttpRequestMethod(),
267 .version
= AnyP::ProtocolVersion()
270 testResults(__LINE__
, input
, output
, expectA
);
273 input
.append("GET / HTTP/10.12\r\n", 18);
274 struct resultSet expectB
= {
277 .parserState
= Http1::HTTP_PARSE_MIME
,
278 .status
= Http::scBadRequest
,
279 .suffixSz
= input
.length(),
280 .method
= HttpRequestMethod(Http::METHOD_GET
),
282 .version
= AnyP::ProtocolVersion()
285 testResults(__LINE__
, input
, output
, expectB
);
289 // unknown non-HTTP protocol names
291 input
.append("GET / FOO/1.0\r\n", 15);
292 struct resultSet expect
= {
295 .parserState
= Http1::HTTP_PARSE_DONE
,
296 .status
= Http::scBadRequest
,
297 .suffixSz
= input
.length(),
298 .method
= HttpRequestMethod(Http::METHOD_GET
),
300 .version
= AnyP::ProtocolVersion()
303 testResults(__LINE__
, input
, output
, expect
);
309 input
.append("GET / HTTP/\r\n", 13);
310 struct resultSet expect
= {
313 .parserState
= Http1::HTTP_PARSE_DONE
,
314 .status
= Http::scBadRequest
,
315 .suffixSz
= input
.length(),
316 .method
= HttpRequestMethod(Http::METHOD_GET
),
318 .version
= AnyP::ProtocolVersion()
321 testResults(__LINE__
, input
, output
, expect
);
327 input
.append("GET / HTTP/.1\r\n", 15);
328 struct resultSet expect
= {
331 .parserState
= Http1::HTTP_PARSE_DONE
,
332 .status
= Http::scBadRequest
,
333 .suffixSz
= input
.length(),
334 .method
= HttpRequestMethod(Http::METHOD_GET
),
336 .version
= AnyP::ProtocolVersion()
339 testResults(__LINE__
, input
, output
, expect
);
345 input
.append("GET / HTTP/11\r\n", 15);
346 struct resultSet expect
= {
349 .parserState
= Http1::HTTP_PARSE_DONE
,
350 .status
= Http::scBadRequest
,
351 .suffixSz
= input
.length(),
352 .method
= HttpRequestMethod(Http::METHOD_GET
),
354 .version
= AnyP::ProtocolVersion()
357 testResults(__LINE__
, input
, output
, expect
);
361 // negative major version (bug 3062)
363 input
.append("GET / HTTP/-999999.1\r\n", 22);
364 struct resultSet expect
= {
367 .parserState
= Http1::HTTP_PARSE_DONE
,
368 .status
= Http::scBadRequest
,
369 .suffixSz
= input
.length(),
370 .method
= HttpRequestMethod(Http::METHOD_GET
),
372 .version
= AnyP::ProtocolVersion()
375 testResults(__LINE__
, input
, output
, expect
);
381 input
.append("GET / HTTP/1.\r\n", 15);
382 struct resultSet expect
= {
385 .parserState
= Http1::HTTP_PARSE_DONE
,
386 .status
= Http::scBadRequest
,
387 .suffixSz
= input
.length(),
388 .method
= HttpRequestMethod(Http::METHOD_GET
),
390 .version
= AnyP::ProtocolVersion()
393 testResults(__LINE__
, input
, output
, expect
);
397 // negative major version (bug 3062 corollary)
399 input
.append("GET / HTTP/1.-999999\r\n", 22);
400 struct resultSet expect
= {
403 .parserState
= Http1::HTTP_PARSE_DONE
,
404 .status
= Http::scBadRequest
,
405 .suffixSz
= input
.length(),
406 .method
= HttpRequestMethod(Http::METHOD_GET
),
408 .version
= AnyP::ProtocolVersion()
411 testResults(__LINE__
, input
, output
, expect
);
417 testHttp1Parser::testParseRequestLineStrange()
419 // ensure MemPools etc exist
423 Http1::RequestParser output
;
427 input
.append("GET / HTTP/1.1\r\n", 21);
428 // when being tolerant extra (sequential) SP delimiters are acceptable
429 Config
.onoff
.relaxed_header_parser
= 1;
430 struct resultSet expect
= {
433 .parserState
= Http1::HTTP_PARSE_MIME
,
434 .status
= Http::scOkay
,
436 .method
= HttpRequestMethod(Http::METHOD_GET
),
438 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
441 testResults(__LINE__
, input
, output
, expect
);
443 Config
.onoff
.relaxed_header_parser
= 0;
444 struct resultSet expectStrict
= {
447 .parserState
= Http1::HTTP_PARSE_DONE
,
448 .status
= Http::scBadRequest
,
449 .suffixSz
= input
.length(),
450 .method
= HttpRequestMethod(),
452 .version
= AnyP::ProtocolVersion()
455 testResults(__LINE__
, input
, output
, expectStrict
);
459 // whitespace inside URI. (nasty but happens)
461 input
.append("GET /fo o/ HTTP/1.1\r\n", 21);
462 Config
.onoff
.relaxed_header_parser
= 1;
463 struct resultSet expect
= {
466 .parserState
= Http1::HTTP_PARSE_MIME
,
467 .status
= Http::scOkay
,
469 .method
= HttpRequestMethod(Http::METHOD_GET
),
471 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
474 testResults(__LINE__
, input
, output
, expect
);
476 Config
.onoff
.relaxed_header_parser
= 0;
477 struct resultSet expectStrict
= {
480 .parserState
= Http1::HTTP_PARSE_DONE
,
481 .status
= Http::scBadRequest
,
482 .suffixSz
= input
.length(),
483 .method
= HttpRequestMethod(),
485 .version
= AnyP::ProtocolVersion()
488 testResults(__LINE__
, input
, output
, expectStrict
);
492 // additional data in buffer
494 input
.append("GET / HTTP/1.1\r\nboo!", 20);
495 struct resultSet expect
= {
498 .parserState
= Http1::HTTP_PARSE_MIME
,
499 .status
= Http::scOkay
,
500 .suffixSz
= 4, // strlen("boo!")
501 .method
= HttpRequestMethod(Http::METHOD_GET
),
503 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
506 testResults(__LINE__
, input
, output
, expect
);
508 Config
.onoff
.relaxed_header_parser
= 0;
513 testHttp1Parser::testParseRequestLineTerminators()
515 // ensure MemPools etc exist
519 Http1::RequestParser output
;
521 // alternative EOL sequence: NL-only
522 // RFC 7230 tolerance permits omitted CR
524 input
.append("GET / HTTP/1.1\n", 15);
525 Config
.onoff
.relaxed_header_parser
= 1;
526 struct resultSet expect
= {
529 .parserState
= Http1::HTTP_PARSE_MIME
,
530 .status
= Http::scOkay
,
532 .method
= HttpRequestMethod(Http::METHOD_GET
),
534 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
537 testResults(__LINE__
, input
, output
, expect
);
539 Config
.onoff
.relaxed_header_parser
= 0;
540 struct resultSet expectStrict
= {
543 .parserState
= Http1::HTTP_PARSE_DONE
,
544 .status
= Http::scBadRequest
,
545 .suffixSz
= input
.length(),
546 .method
= HttpRequestMethod(),
548 .version
= AnyP::ProtocolVersion()
551 testResults(__LINE__
, input
, output
, expectStrict
);
555 // alternative EOL sequence: double-NL-only
556 // RFC 7230 tolerance permits omitted CR
557 // NP: represents a request with no mime headers
559 input
.append("GET / HTTP/1.1\n\n", 16);
560 Config
.onoff
.relaxed_header_parser
= 1;
561 struct resultSet expect
= {
564 .parserState
= Http1::HTTP_PARSE_DONE
,
565 .status
= Http::scOkay
,
567 .method
= HttpRequestMethod(Http::METHOD_GET
),
569 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
572 testResults(__LINE__
, input
, output
, expect
);
574 Config
.onoff
.relaxed_header_parser
= 0;
575 struct resultSet expectStrict
= {
578 .parserState
= Http1::HTTP_PARSE_DONE
,
579 .status
= Http::scBadRequest
,
580 .suffixSz
= input
.length(),
581 .method
= HttpRequestMethod(),
583 .version
= AnyP::ProtocolVersion()
586 testResults(__LINE__
, input
, output
, expectStrict
);
590 // space padded version
592 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
593 input
.append("GET / HTTP/1.1 \r\n", 17);
594 struct resultSet expect
= {
597 .parserState
= Http1::HTTP_PARSE_DONE
,
598 .status
= Http::scBadRequest
,
599 .suffixSz
= input
.length(),
600 .method
= HttpRequestMethod(),
602 .version
= AnyP::ProtocolVersion()
605 testResults(__LINE__
, input
, output
, expect
);
611 testHttp1Parser::testParseRequestLineMethods()
613 // ensure MemPools etc exist
617 Http1::RequestParser output
;
619 // RFC 7230 : dot method
621 input
.append(". / HTTP/1.1\r\n", 14);
622 struct resultSet expect
= {
625 .parserState
= Http1::HTTP_PARSE_MIME
,
626 .status
= Http::scOkay
,
628 .method
= HttpRequestMethod(SBuf(".")),
630 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
633 testResults(__LINE__
, input
, output
, expect
);
637 // RFC 7230 : special TCHAR method chars
639 input
.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
640 struct resultSet expect
= {
643 .parserState
= Http1::HTTP_PARSE_MIME
,
644 .status
= Http::scOkay
,
646 .method
= HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
648 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
651 testResults(__LINE__
, input
, output
, expect
);
655 // OPTIONS with * URL
657 input
.append("OPTIONS * HTTP/1.1\r\n", 20);
658 struct resultSet expect
= {
661 .parserState
= Http1::HTTP_PARSE_MIME
,
662 .status
= Http::scOkay
,
664 .method
= HttpRequestMethod(Http::METHOD_OPTIONS
),
666 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
669 testResults(__LINE__
, input
, output
, expect
);
675 input
.append("HELLOWORLD / HTTP/1.1\r\n", 23);
676 struct resultSet expect
= {
679 .parserState
= Http1::HTTP_PARSE_MIME
,
680 .status
= Http::scOkay
,
682 .method
= HttpRequestMethod(SBuf("HELLOWORLD")),
684 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
687 testResults(__LINE__
, input
, output
, expect
);
692 // too-long method (over 16 bytes)
694 input
.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
695 struct resultSet expect
= {
698 .parserState
= Http1::HTTP_PARSE_DONE
,
699 .status
= Http::scNotImplemented
,
700 .suffixSz
= input
.length(),
701 .method
= HttpRequestMethod(),
703 .version
= AnyP::ProtocolVersion()
706 testResults(__LINE__
, input
, output
, expect
);
713 input
.append("A\n", 2);
714 struct resultSet expect
= {
717 .parserState
= Http1::HTTP_PARSE_DONE
,
718 .status
= Http::scBadRequest
,
719 .suffixSz
= input
.length(),
720 .method
= HttpRequestMethod(),
722 .version
= AnyP::ProtocolVersion()
725 testResults(__LINE__
, input
, output
, expect
);
730 input
.append("GET\n", 4);
731 struct resultSet expect
= {
734 .parserState
= Http1::HTTP_PARSE_DONE
,
735 .status
= Http::scBadRequest
,
736 .suffixSz
= input
.length(),
737 .method
= HttpRequestMethod(),
739 .version
= AnyP::ProtocolVersion()
742 testResults(__LINE__
, input
, output
, expect
);
746 // space padded method (SP is reserved so invalid as a method byte)
748 input
.append(" GET / HTTP/1.1\r\n", 17);
749 struct resultSet expect
= {
752 .parserState
= Http1::HTTP_PARSE_DONE
,
753 .status
= Http::scBadRequest
,
754 .suffixSz
= input
.length(),
755 .method
= HttpRequestMethod(),
757 .version
= AnyP::ProtocolVersion()
760 testResults(__LINE__
, input
, output
, expect
);
764 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
766 input
.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
767 Config
.onoff
.relaxed_header_parser
= 1;
768 struct resultSet expect
= {
771 .parserState
= Http1::HTTP_PARSE_MIME
,
772 .status
= Http::scOkay
,
774 .method
= HttpRequestMethod(Http::METHOD_GET
),
776 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
779 testResults(__LINE__
, input
, output
, expect
);
781 Config
.onoff
.relaxed_header_parser
= 0;
782 struct resultSet expectStrict
= {
785 .parserState
= Http1::HTTP_PARSE_DONE
,
786 .status
= Http::scBadRequest
,
787 .suffixSz
= input
.length(),
788 .method
= HttpRequestMethod(),
790 .version
= AnyP::ProtocolVersion()
793 testResults(__LINE__
, input
, output
, expectStrict
);
797 // forbidden character in method
799 input
.append("\tGET / HTTP/1.1\r\n", 17);
800 struct resultSet expect
= {
803 .parserState
= Http1::HTTP_PARSE_DONE
,
804 .status
= Http::scBadRequest
,
805 .suffixSz
= input
.length(),
806 .method
= HttpRequestMethod(),
808 .version
= AnyP::ProtocolVersion()
811 testResults(__LINE__
, input
, output
, expect
);
815 // CR in method delimiters
817 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
818 input
.append("GET\r / HTTP/1.1\r\n", 17);
819 Config
.onoff
.relaxed_header_parser
= 1;
820 struct resultSet expect
= {
823 .parserState
= Http1::HTTP_PARSE_MIME
,
824 .status
= Http::scOkay
,
826 .method
= HttpRequestMethod(Http::METHOD_GET
),
828 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
831 testResults(__LINE__
, input
, output
, expect
);
833 Config
.onoff
.relaxed_header_parser
= 0;
834 struct resultSet expectStrict
= {
837 .parserState
= Http1::HTTP_PARSE_DONE
,
838 .status
= Http::scBadRequest
,
839 .suffixSz
= input
.length(),
840 .method
= HttpRequestMethod(),
842 .version
= AnyP::ProtocolVersion()
845 testResults(__LINE__
, input
, output
, expectStrict
);
849 // tolerant parser delimiters
851 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
852 input
.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
853 Config
.onoff
.relaxed_header_parser
= 1;
854 struct resultSet expect
= {
857 .parserState
= Http1::HTTP_PARSE_MIME
,
858 .status
= Http::scOkay
,
860 .method
= HttpRequestMethod(Http::METHOD_GET
),
862 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
865 testResults(__LINE__
, input
, output
, expect
);
867 Config
.onoff
.relaxed_header_parser
= 0;
868 struct resultSet expectStrict
= {
871 .parserState
= Http1::HTTP_PARSE_DONE
,
872 .status
= Http::scBadRequest
,
873 .suffixSz
= input
.length(),
874 .method
= HttpRequestMethod(),
876 .version
= AnyP::ProtocolVersion()
879 testResults(__LINE__
, input
, output
, expectStrict
);
885 testHttp1Parser::testParseRequestLineInvalid()
887 // ensure MemPools etc exist
891 Http1::RequestParser output
;
893 // no method (or method delimiter)
895 // HTTP/0.9 requires method to be "GET"
896 input
.append("/ HTTP/1.0\n", 11);
897 struct resultSet expect
= {
900 .parserState
= Http1::HTTP_PARSE_DONE
,
901 .status
= Http::scBadRequest
,
902 .suffixSz
= input
.length(),
903 .method
= HttpRequestMethod(),
905 .version
= AnyP::ProtocolVersion()
908 testResults(__LINE__
, input
, output
, expect
);
912 // no method (with method delimiter)
914 input
.append(" / HTTP/1.0\n", 12);
915 struct resultSet expectStrict
= {
918 .parserState
= Http1::HTTP_PARSE_DONE
,
919 .status
= Http::scBadRequest
,
920 .suffixSz
= input
.length(),
921 .method
= HttpRequestMethod(),
923 .version
= AnyP::ProtocolVersion()
926 testResults(__LINE__
, input
, output
, expectStrict
);
930 // binary code after method (invalid)
932 input
.append("GET\x16 / HTTP/1.1\r\n", 17);
933 struct resultSet expect
= {
936 .parserState
= Http1::HTTP_PARSE_DONE
,
937 .status
= Http::scBadRequest
,
938 .suffixSz
= input
.length(),
939 .method
= HttpRequestMethod(),
941 .version
= AnyP::ProtocolVersion()
944 testResults(__LINE__
, input
, output
, expect
);
948 // binary code NUL! after method (always invalid)
950 input
.append("GET\0 / HTTP/1.1\r\n", 17);
951 struct resultSet expect
= {
954 .parserState
= Http1::HTTP_PARSE_DONE
,
955 .status
= Http::scBadRequest
,
956 .suffixSz
= input
.length(),
957 .method
= HttpRequestMethod(),
959 .version
= AnyP::ProtocolVersion()
962 testResults(__LINE__
, input
, output
, expect
);
966 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
967 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
969 input
.append("GET HTTP/1.1\r\n", 15);
970 Config
.onoff
.relaxed_header_parser
= 1;
971 struct resultSet expect
= {
974 .parserState
= Http1::HTTP_PARSE_DONE
,
975 .status
= Http::scBadRequest
,
976 .suffixSz
= input
.length(),
977 .method
= HttpRequestMethod(),
979 .version
= AnyP::ProtocolVersion()
982 testResults(__LINE__
, input
, output
, expect
);
984 Config
.onoff
.relaxed_header_parser
= 0;
985 struct resultSet expectStrict
= {
988 .parserState
= Http1::HTTP_PARSE_DONE
,
989 .status
= Http::scBadRequest
,
990 .suffixSz
= input
.length(),
991 .method
= HttpRequestMethod(),
993 .version
= AnyP::ProtocolVersion()
996 testResults(__LINE__
, input
, output
, expectStrict
);
1000 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
1001 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
1003 input
.append("GET HTTP/1.1\r\n", 14);
1004 struct resultSet expect
= {
1007 .parserState
= Http1::HTTP_PARSE_DONE
,
1008 .status
= Http::scBadRequest
,
1009 .suffixSz
= input
.length(),
1010 .method
= HttpRequestMethod(),
1012 .version
= AnyP::ProtocolVersion()
1015 testResults(__LINE__
, input
, output
, expect
);
1021 input
.append("\xB\xC\xE\xF\n", 5);
1022 struct resultSet expect
= {
1025 .parserState
= Http1::HTTP_PARSE_DONE
,
1026 .status
= Http::scBadRequest
,
1027 .suffixSz
= input
.length(),
1028 .method
= HttpRequestMethod(),
1030 .version
= AnyP::ProtocolVersion()
1033 testResults(__LINE__
, input
, output
, expect
);
1037 // mixed whitespace line
1039 input
.append("\t \t \t\n", 6);
1040 struct resultSet expect
= {
1043 .parserState
= Http1::HTTP_PARSE_DONE
,
1044 .status
= Http::scBadRequest
,
1045 .suffixSz
= input
.length(),
1046 .method
= HttpRequestMethod(),
1048 .version
= AnyP::ProtocolVersion()
1051 testResults(__LINE__
, input
, output
, expect
);
1055 // mixed whitespace line with CR
1057 input
.append("\r \t \n", 6);
1058 struct resultSet expect
= {
1061 .parserState
= Http1::HTTP_PARSE_DONE
,
1062 .status
= Http::scBadRequest
,
1063 .suffixSz
= input
.length(),
1064 .method
= HttpRequestMethod(),
1066 .version
= AnyP::ProtocolVersion()
1069 testResults(__LINE__
, input
, output
, expect
);
1075 testHttp1Parser::testDripFeed()
1077 // Simulate a client drip-feeding Squid a few bytes at a time.
1078 // extend the size of the buffer from 0 bytes to full request length
1079 // calling the parser repeatedly as visible data grows.
1082 data
.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
1083 SBuf::size_type garbageEnd
= data
.length();
1084 data
.append("GET ", 4);
1085 data
.append("http://example.com/ ", 20);
1086 data
.append("HTTP/1.1\r\n", 10);
1087 SBuf::size_type reqLineEnd
= data
.length() - 1;
1088 data
.append("Host: example.com\r\n\r\n", 21);
1089 SBuf::size_type mimeEnd
= data
.length() - 1;
1090 data
.append("...", 3); // trailer to catch mime EOS errors.
1093 Http1::RequestParser hp
;
1095 // start with strict and move on to relaxed
1096 Config
.onoff
.relaxed_header_parser
= 2;
1098 Config
.maxRequestHeaderSize
= 1024; // large enough to hold the test data.
1102 // state of things we expect right now
1103 struct resultSet expect
= {
1106 .parserState
= Http1::HTTP_PARSE_NONE
,
1107 .status
= Http::scNone
,
1109 .method
= HttpRequestMethod(),
1111 .version
= AnyP::ProtocolVersion()
1114 ioBuf
.clear(); // begins empty for each parser type
1117 --Config
.onoff
.relaxed_header_parser
;
1119 for (SBuf::size_type pos
= 0; pos
<= data
.length(); ++pos
) {
1121 // simulate reading one more byte
1122 ioBuf
.append(data
.substr(pos
,1));
1124 // strict does not permit the garbage prefix
1125 if (pos
< garbageEnd
&& !Config
.onoff
.relaxed_header_parser
) {
1130 // when the garbage is passed we expect to start seeing first-line bytes
1131 if (pos
== garbageEnd
)
1132 expect
.parserState
= Http1::HTTP_PARSE_FIRST
;
1134 // all points after garbage start to see accumulated bytes looking for end of current section
1135 if (pos
>= garbageEnd
)
1136 expect
.suffixSz
= ioBuf
.length();
1138 // at end of request line expect to see method, URI, version details
1139 // and switch to seeking Mime header section
1140 if (pos
== reqLineEnd
) {
1141 expect
.parserState
= Http1::HTTP_PARSE_MIME
;
1142 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1143 expect
.status
= Http::scOkay
;
1144 expect
.method
= HttpRequestMethod(Http::METHOD_GET
);
1145 expect
.uri
= "http://example.com/";
1146 expect
.version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1);
1149 // one mime header is done we are expecting a new request
1150 // parse results say true and initial data is all gone from the buffer
1151 if (pos
== mimeEnd
) {
1152 expect
.parsed
= true;
1153 expect
.needsMore
= false;
1154 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1157 testResults(__LINE__
, ioBuf
, hp
, expect
);
1159 // sync the buffers like Squid does
1160 ioBuf
= hp
.remaining();
1162 // Squid stops using the parser once it has parsed the first message.
1163 if (!hp
.needsMoreData())
1167 } while (Config
.onoff
.relaxed_header_parser
);
1170 #endif /* __cplusplus >= 201103L */