]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
2 * Copyright (C) 1996-2017 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
45 Http1::ParseState parserState
;
46 Http::StatusCode status
;
47 SBuf::size_type suffixSz
;
48 HttpRequestMethod method
;
50 AnyP::ProtocolVersion version
;
53 // define SQUID_DEBUG_TESTS to see exactly which test sub-cases fail and where
54 #ifdef SQUID_DEBUG_TESTS
55 // not optimized for runtime use
57 Replace(SBuf
&where
, const SBuf
&what
, const SBuf
&with
)
59 // prevent infinite loops
60 if (!what
.length() || with
.find(what
) != SBuf::npos
)
63 SBuf::size_type pos
= 0;
64 while ((pos
= where
.find(what
, pos
)) != SBuf::npos
) {
65 SBuf buf
= where
.substr(0, pos
);
67 buf
.append(where
.substr(pos
+what
.length()));
73 static SBuf
Pretty(SBuf raw
)
75 Replace(raw
, SBuf("\r"), SBuf("\\r"));
76 Replace(raw
, SBuf("\n"), SBuf("\\n"));
82 testResults(int line
, const SBuf
&input
, Http1::RequestParser
&output
, struct resultSet
&expect
)
84 #ifdef SQUID_DEBUG_TESTS
85 std::cerr
<< "TEST @" << line
<< ", in=" << Pretty(input
) << "\n";
88 const bool parsed
= output
.parse(input
);
90 #ifdef SQUID_DEBUG_TESTS
91 if (expect
.parsed
!= parsed
)
92 std::cerr
<< "\tparse-FAILED: " << expect
.parsed
<< "!=" << parsed
<< "\n";
93 else if (parsed
&& expect
.method
!= output
.method_
)
94 std::cerr
<< "\tmethod-FAILED: " << expect
.method
<< "!=" << output
.method_
<< "\n";
95 if (expect
.status
!= output
.parseStatusCode
)
96 std::cerr
<< "\tscode-FAILED: " << expect
.status
<< "!=" << output
.parseStatusCode
<< "\n";
97 if (expect
.suffixSz
!= output
.buf_
.length())
98 std::cerr
<< "\tsuffixSz-FAILED: " << expect
.suffixSz
<< "!=" << output
.buf_
.length() << "\n";
102 CPPUNIT_ASSERT_EQUAL(expect
.parsed
, parsed
);
104 // if parsing was successful, check easily visible field outputs
106 CPPUNIT_ASSERT_EQUAL(expect
.method
, output
.method_
);
107 if (expect
.uri
!= NULL
)
108 CPPUNIT_ASSERT_EQUAL(0, output
.uri_
.cmp(expect
.uri
));
109 CPPUNIT_ASSERT_EQUAL(expect
.version
, output
.msgProtocol_
);
112 CPPUNIT_ASSERT_EQUAL(expect
.status
, output
.parseStatusCode
);
114 // check more obscure states
115 CPPUNIT_ASSERT_EQUAL(expect
.needsMore
, output
.needsMoreData());
116 if (output
.needsMoreData())
117 CPPUNIT_ASSERT_EQUAL(expect
.parserState
, output
.parsingStage_
);
118 CPPUNIT_ASSERT_EQUAL(expect
.suffixSz
, output
.buf_
.length());
122 testHttp1Parser::testParserConstruct()
124 // whether the constructor works
126 Http1::RequestParser output
;
127 CPPUNIT_ASSERT_EQUAL(true, output
.needsMoreData());
128 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
.parsingStage_
);
129 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
.parseStatusCode
); // XXX: clear() not being called.
130 CPPUNIT_ASSERT(output
.buf_
.isEmpty());
131 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
.method_
);
132 CPPUNIT_ASSERT(output
.uri_
.isEmpty());
133 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
.msgProtocol_
);
136 // whether new() works
138 Http1::RequestParser
*output
= new Http1::RequestParser
;
139 CPPUNIT_ASSERT_EQUAL(true, output
->needsMoreData());
140 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
->parsingStage_
);
141 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
->parseStatusCode
);
142 CPPUNIT_ASSERT(output
->buf_
.isEmpty());
143 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
->method_
);
144 CPPUNIT_ASSERT(output
->uri_
.isEmpty());
145 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
->msgProtocol_
);
150 #if __cplusplus >= 201103L
152 testHttp1Parser::testParseRequestLineProtocols()
154 // ensure MemPools etc exist
158 Http1::RequestParser output
;
160 // TEST: Do we comply with RFC 1945 section 5.1 ?
161 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
163 // RFC 1945 : HTTP/0.9 simple-request
165 input
.append("GET /\r\n", 7);
166 struct resultSet expect
= {
169 .parserState
= Http1::HTTP_PARSE_DONE
,
170 .status
= Http::scOkay
,
172 .method
= HttpRequestMethod(Http::METHOD_GET
),
174 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,0,9)
177 testResults(__LINE__
, input
, output
, expect
);
181 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
183 input
.append("POST /\r\n", 8);
184 struct resultSet expect
= {
187 .parserState
= Http1::HTTP_PARSE_DONE
,
188 .status
= Http::scBadRequest
,
189 .suffixSz
= input
.length(),
190 .method
= HttpRequestMethod(Http::METHOD_POST
),
192 .version
= AnyP::ProtocolVersion()
195 testResults(__LINE__
, input
, output
, expect
);
199 // RFC 1945 and 7230 : HTTP/1.0 request
201 input
.append("GET / HTTP/1.0\r\n", 16);
202 struct resultSet expect
= {
205 .parserState
= Http1::HTTP_PARSE_MIME
,
206 .status
= Http::scOkay
,
208 .method
= HttpRequestMethod(Http::METHOD_GET
),
210 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,0)
213 testResults(__LINE__
, input
, output
, expect
);
217 // RFC 7230 : HTTP/1.1 request
219 input
.append("GET / HTTP/1.1\r\n", 16);
220 struct resultSet expect
= {
223 .parserState
= Http1::HTTP_PARSE_MIME
,
224 .status
= Http::scOkay
,
226 .method
= HttpRequestMethod(Http::METHOD_GET
),
228 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
231 testResults(__LINE__
, input
, output
, expect
);
235 // RFC 7230 : future 1.x version full-request
237 input
.append("GET / HTTP/1.2\r\n", 16);
238 struct resultSet expect
= {
241 .parserState
= Http1::HTTP_PARSE_MIME
,
242 .status
= Http::scOkay
,
244 .method
= HttpRequestMethod(Http::METHOD_GET
),
246 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,2)
249 testResults(__LINE__
, input
, output
, expect
);
253 // RFC 7230 : future versions do not use 1.x message syntax.
254 // However, it is still valid syntax for the single-digit forms
255 // to appear. The parser we are testing should accept them.
257 input
.append("GET / HTTP/2.0\r\n", 16);
258 struct resultSet expectA
= {
261 .parserState
= Http1::HTTP_PARSE_DONE
,
262 .status
= Http::scOkay
,
264 .method
= HttpRequestMethod(Http::METHOD_GET
),
266 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,2,0)
269 testResults(__LINE__
, input
, output
, expectA
);
272 input
.append("GET / HTTP/9.9\r\n", 16);
273 struct resultSet expectB
= {
276 .parserState
= Http1::HTTP_PARSE_DONE
,
277 .status
= Http::scOkay
,
279 .method
= HttpRequestMethod(Http::METHOD_GET
),
281 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,9,9)
284 testResults(__LINE__
, input
, output
, expectB
);
288 // RFC 7230 : future versions >= 10.0 are invalid syntax
290 input
.append("GET / HTTP/10.12\r\n", 18);
291 struct resultSet expect
= {
294 .parserState
= Http1::HTTP_PARSE_MIME
,
295 .status
= Http::scBadRequest
,
296 .suffixSz
= input
.length(),
297 .method
= HttpRequestMethod(Http::METHOD_GET
),
299 .version
= AnyP::ProtocolVersion()
302 testResults(__LINE__
, input
, output
, expect
);
306 // unknown non-HTTP protocol names
308 input
.append("GET / FOO/1.0\r\n", 15);
309 struct resultSet expect
= {
312 .parserState
= Http1::HTTP_PARSE_DONE
,
313 .status
= Http::scBadRequest
,
314 .suffixSz
= input
.length(),
315 .method
= HttpRequestMethod(Http::METHOD_GET
),
317 .version
= AnyP::ProtocolVersion()
320 testResults(__LINE__
, input
, output
, expect
);
326 input
.append("GET / HTTP/\r\n", 13);
327 struct resultSet expect
= {
330 .parserState
= Http1::HTTP_PARSE_DONE
,
331 .status
= Http::scBadRequest
,
332 .suffixSz
= input
.length(),
333 .method
= HttpRequestMethod(Http::METHOD_GET
),
335 .version
= AnyP::ProtocolVersion()
338 testResults(__LINE__
, input
, output
, expect
);
344 input
.append("GET / HTTP/.1\r\n", 15);
345 struct resultSet expect
= {
348 .parserState
= Http1::HTTP_PARSE_DONE
,
349 .status
= Http::scBadRequest
,
350 .suffixSz
= input
.length(),
351 .method
= HttpRequestMethod(Http::METHOD_GET
),
353 .version
= AnyP::ProtocolVersion()
356 testResults(__LINE__
, input
, output
, expect
);
362 input
.append("GET / HTTP/11\r\n", 15);
363 struct resultSet expect
= {
366 .parserState
= Http1::HTTP_PARSE_DONE
,
367 .status
= Http::scBadRequest
,
368 .suffixSz
= input
.length(),
369 .method
= HttpRequestMethod(Http::METHOD_GET
),
371 .version
= AnyP::ProtocolVersion()
374 testResults(__LINE__
, input
, output
, expect
);
378 // negative major version (bug 3062)
380 input
.append("GET / HTTP/-999999.1\r\n", 22);
381 struct resultSet expect
= {
384 .parserState
= Http1::HTTP_PARSE_DONE
,
385 .status
= Http::scBadRequest
,
386 .suffixSz
= input
.length(),
387 .method
= HttpRequestMethod(Http::METHOD_GET
),
389 .version
= AnyP::ProtocolVersion()
392 testResults(__LINE__
, input
, output
, expect
);
398 input
.append("GET / HTTP/1.\r\n", 15);
399 struct resultSet expect
= {
402 .parserState
= Http1::HTTP_PARSE_DONE
,
403 .status
= Http::scBadRequest
,
404 .suffixSz
= input
.length(),
405 .method
= HttpRequestMethod(Http::METHOD_GET
),
407 .version
= AnyP::ProtocolVersion()
410 testResults(__LINE__
, input
, output
, expect
);
414 // negative major version (bug 3062 corollary)
416 input
.append("GET / HTTP/1.-999999\r\n", 22);
417 struct resultSet expect
= {
420 .parserState
= Http1::HTTP_PARSE_DONE
,
421 .status
= Http::scBadRequest
,
422 .suffixSz
= input
.length(),
423 .method
= HttpRequestMethod(Http::METHOD_GET
),
425 .version
= AnyP::ProtocolVersion()
428 testResults(__LINE__
, input
, output
, expect
);
434 testHttp1Parser::testParseRequestLineStrange()
436 // ensure MemPools etc exist
440 Http1::RequestParser output
;
444 input
.append("GET / HTTP/1.1\r\n", 21);
445 // when being tolerant extra (sequential) SP delimiters are acceptable
446 Config
.onoff
.relaxed_header_parser
= 1;
447 struct resultSet expect
= {
450 .parserState
= Http1::HTTP_PARSE_MIME
,
451 .status
= Http::scOkay
,
453 .method
= HttpRequestMethod(Http::METHOD_GET
),
455 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
458 testResults(__LINE__
, input
, output
, expect
);
460 Config
.onoff
.relaxed_header_parser
= 0;
461 struct resultSet expectStrict
= {
464 .parserState
= Http1::HTTP_PARSE_DONE
,
465 .status
= Http::scBadRequest
,
466 .suffixSz
= input
.length(),
467 .method
= HttpRequestMethod(),
469 .version
= AnyP::ProtocolVersion()
472 testResults(__LINE__
, input
, output
, expectStrict
);
476 // whitespace inside URI. (nasty but happens)
478 input
.append("GET /fo o/ HTTP/1.1\r\n", 21);
479 Config
.onoff
.relaxed_header_parser
= 1;
480 struct resultSet expect
= {
483 .parserState
= Http1::HTTP_PARSE_MIME
,
484 .status
= Http::scOkay
,
486 .method
= HttpRequestMethod(Http::METHOD_GET
),
488 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
491 testResults(__LINE__
, input
, output
, expect
);
493 Config
.onoff
.relaxed_header_parser
= 0;
494 struct resultSet expectStrict
= {
497 .parserState
= Http1::HTTP_PARSE_DONE
,
498 .status
= Http::scBadRequest
,
499 .suffixSz
= input
.length(),
500 .method
= HttpRequestMethod(),
502 .version
= AnyP::ProtocolVersion()
505 testResults(__LINE__
, input
, output
, expectStrict
);
509 // additional data in buffer
511 input
.append("GET / HTTP/1.1\r\nboo!", 20);
512 struct resultSet expect
= {
515 .parserState
= Http1::HTTP_PARSE_MIME
,
516 .status
= Http::scOkay
,
517 .suffixSz
= 4, // strlen("boo!")
518 .method
= HttpRequestMethod(Http::METHOD_GET
),
520 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
523 testResults(__LINE__
, input
, output
, expect
);
525 Config
.onoff
.relaxed_header_parser
= 0;
530 testHttp1Parser::testParseRequestLineTerminators()
532 // ensure MemPools etc exist
536 Http1::RequestParser output
;
538 // alternative EOL sequence: NL-only
539 // RFC 7230 tolerance permits omitted CR
541 input
.append("GET / HTTP/1.1\n", 15);
542 Config
.onoff
.relaxed_header_parser
= 1;
543 struct resultSet expect
= {
546 .parserState
= Http1::HTTP_PARSE_MIME
,
547 .status
= Http::scOkay
,
549 .method
= HttpRequestMethod(Http::METHOD_GET
),
551 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
554 testResults(__LINE__
, input
, output
, expect
);
556 Config
.onoff
.relaxed_header_parser
= 0;
557 struct resultSet expectStrict
= {
560 .parserState
= Http1::HTTP_PARSE_DONE
,
561 .status
= Http::scBadRequest
,
562 .suffixSz
= input
.length(),
563 .method
= HttpRequestMethod(),
565 .version
= AnyP::ProtocolVersion()
568 testResults(__LINE__
, input
, output
, expectStrict
);
572 // alternative EOL sequence: double-NL-only
573 // RFC 7230 tolerance permits omitted CR
574 // NP: represents a request with no mime headers
576 input
.append("GET / HTTP/1.1\n\n", 16);
577 Config
.onoff
.relaxed_header_parser
= 1;
578 struct resultSet expect
= {
581 .parserState
= Http1::HTTP_PARSE_DONE
,
582 .status
= Http::scOkay
,
584 .method
= HttpRequestMethod(Http::METHOD_GET
),
586 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
589 testResults(__LINE__
, input
, output
, expect
);
591 Config
.onoff
.relaxed_header_parser
= 0;
592 struct resultSet expectStrict
= {
595 .parserState
= Http1::HTTP_PARSE_DONE
,
596 .status
= Http::scBadRequest
,
597 .suffixSz
= input
.length(),
598 .method
= HttpRequestMethod(),
600 .version
= AnyP::ProtocolVersion()
603 testResults(__LINE__
, input
, output
, expectStrict
);
607 // space padded version
609 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
610 input
.append("GET / HTTP/1.1 \r\n", 17);
611 struct resultSet expect
= {
614 .parserState
= Http1::HTTP_PARSE_DONE
,
615 .status
= Http::scBadRequest
,
616 .suffixSz
= input
.length(),
617 .method
= HttpRequestMethod(),
619 .version
= AnyP::ProtocolVersion()
622 testResults(__LINE__
, input
, output
, expect
);
628 testHttp1Parser::testParseRequestLineMethods()
630 // ensure MemPools etc exist
634 Http1::RequestParser output
;
636 // RFC 7230 : dot method
638 input
.append(". / HTTP/1.1\r\n", 14);
639 struct resultSet expect
= {
642 .parserState
= Http1::HTTP_PARSE_MIME
,
643 .status
= Http::scOkay
,
645 .method
= HttpRequestMethod(SBuf(".")),
647 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
650 testResults(__LINE__
, input
, output
, expect
);
654 // RFC 7230 : special TCHAR method chars
656 input
.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
657 struct resultSet expect
= {
660 .parserState
= Http1::HTTP_PARSE_MIME
,
661 .status
= Http::scOkay
,
663 .method
= HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
665 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
668 testResults(__LINE__
, input
, output
, expect
);
672 // OPTIONS with * URL
674 input
.append("OPTIONS * HTTP/1.1\r\n", 20);
675 struct resultSet expect
= {
678 .parserState
= Http1::HTTP_PARSE_MIME
,
679 .status
= Http::scOkay
,
681 .method
= HttpRequestMethod(Http::METHOD_OPTIONS
),
683 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
686 testResults(__LINE__
, input
, output
, expect
);
692 input
.append("HELLOWORLD / HTTP/1.1\r\n", 23);
693 struct resultSet expect
= {
696 .parserState
= Http1::HTTP_PARSE_MIME
,
697 .status
= Http::scOkay
,
699 .method
= HttpRequestMethod(SBuf("HELLOWORLD")),
701 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
704 testResults(__LINE__
, input
, output
, expect
);
709 // too-long method (over 16 bytes)
711 input
.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
712 struct resultSet expect
= {
715 .parserState
= Http1::HTTP_PARSE_DONE
,
716 .status
= Http::scNotImplemented
,
717 .suffixSz
= input
.length(),
718 .method
= HttpRequestMethod(),
720 .version
= AnyP::ProtocolVersion()
723 testResults(__LINE__
, input
, output
, expect
);
730 input
.append("A\n", 2);
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
);
747 input
.append("GET\n", 4);
748 struct resultSet expect
= {
751 .parserState
= Http1::HTTP_PARSE_DONE
,
752 .status
= Http::scBadRequest
,
753 .suffixSz
= input
.length(),
754 .method
= HttpRequestMethod(),
756 .version
= AnyP::ProtocolVersion()
759 testResults(__LINE__
, input
, output
, expect
);
763 // space padded method (SP is reserved so invalid as a method byte)
765 input
.append(" GET / HTTP/1.1\r\n", 17);
766 struct resultSet expect
= {
769 .parserState
= Http1::HTTP_PARSE_DONE
,
770 .status
= Http::scBadRequest
,
771 .suffixSz
= input
.length(),
772 .method
= HttpRequestMethod(),
774 .version
= AnyP::ProtocolVersion()
777 testResults(__LINE__
, input
, output
, expect
);
781 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
783 input
.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
784 Config
.onoff
.relaxed_header_parser
= 1;
785 struct resultSet expect
= {
788 .parserState
= Http1::HTTP_PARSE_MIME
,
789 .status
= Http::scOkay
,
791 .method
= HttpRequestMethod(Http::METHOD_GET
),
793 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
796 testResults(__LINE__
, input
, output
, expect
);
798 Config
.onoff
.relaxed_header_parser
= 0;
799 struct resultSet expectStrict
= {
802 .parserState
= Http1::HTTP_PARSE_DONE
,
803 .status
= Http::scBadRequest
,
804 .suffixSz
= input
.length(),
805 .method
= HttpRequestMethod(),
807 .version
= AnyP::ProtocolVersion()
810 testResults(__LINE__
, input
, output
, expectStrict
);
814 // forbidden character in method
816 input
.append("\tGET / HTTP/1.1\r\n", 17);
817 struct resultSet expect
= {
820 .parserState
= Http1::HTTP_PARSE_DONE
,
821 .status
= Http::scBadRequest
,
822 .suffixSz
= input
.length(),
823 .method
= HttpRequestMethod(),
825 .version
= AnyP::ProtocolVersion()
828 testResults(__LINE__
, input
, output
, expect
);
832 // CR in method delimiters
834 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
835 input
.append("GET\r / HTTP/1.1\r\n", 17);
836 Config
.onoff
.relaxed_header_parser
= 1;
837 struct resultSet expect
= {
840 .parserState
= Http1::HTTP_PARSE_MIME
,
841 .status
= Http::scOkay
,
843 .method
= HttpRequestMethod(Http::METHOD_GET
),
845 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
848 testResults(__LINE__
, input
, output
, expect
);
850 Config
.onoff
.relaxed_header_parser
= 0;
851 struct resultSet expectStrict
= {
854 .parserState
= Http1::HTTP_PARSE_DONE
,
855 .status
= Http::scBadRequest
,
856 .suffixSz
= input
.length(),
857 .method
= HttpRequestMethod(),
859 .version
= AnyP::ProtocolVersion()
862 testResults(__LINE__
, input
, output
, expectStrict
);
866 // tolerant parser delimiters
868 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
869 input
.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
870 Config
.onoff
.relaxed_header_parser
= 1;
871 struct resultSet expect
= {
874 .parserState
= Http1::HTTP_PARSE_MIME
,
875 .status
= Http::scOkay
,
877 .method
= HttpRequestMethod(Http::METHOD_GET
),
879 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
882 testResults(__LINE__
, input
, output
, expect
);
884 Config
.onoff
.relaxed_header_parser
= 0;
885 struct resultSet expectStrict
= {
888 .parserState
= Http1::HTTP_PARSE_DONE
,
889 .status
= Http::scBadRequest
,
890 .suffixSz
= input
.length(),
891 .method
= HttpRequestMethod(),
893 .version
= AnyP::ProtocolVersion()
896 testResults(__LINE__
, input
, output
, expectStrict
);
902 testHttp1Parser::testParseRequestLineInvalid()
904 // ensure MemPools etc exist
908 Http1::RequestParser output
;
910 // no method (or method delimiter)
912 // HTTP/0.9 requires method to be "GET"
913 input
.append("/ HTTP/1.0\n", 11);
914 struct resultSet expect
= {
917 .parserState
= Http1::HTTP_PARSE_DONE
,
918 .status
= Http::scBadRequest
,
919 .suffixSz
= input
.length(),
920 .method
= HttpRequestMethod(),
922 .version
= AnyP::ProtocolVersion()
925 testResults(__LINE__
, input
, output
, expect
);
929 // no method (with method delimiter)
931 input
.append(" / HTTP/1.0\n", 12);
932 struct resultSet expectStrict
= {
935 .parserState
= Http1::HTTP_PARSE_DONE
,
936 .status
= Http::scBadRequest
,
937 .suffixSz
= input
.length(),
938 .method
= HttpRequestMethod(),
940 .version
= AnyP::ProtocolVersion()
943 testResults(__LINE__
, input
, output
, expectStrict
);
947 // binary code after method (invalid)
949 input
.append("GET\x16 / HTTP/1.1\r\n", 17);
950 struct resultSet expect
= {
953 .parserState
= Http1::HTTP_PARSE_DONE
,
954 .status
= Http::scBadRequest
,
955 .suffixSz
= input
.length(),
956 .method
= HttpRequestMethod(),
958 .version
= AnyP::ProtocolVersion()
961 testResults(__LINE__
, input
, output
, expect
);
965 // binary code NUL! after method (always invalid)
967 input
.append("GET\0 / HTTP/1.1\r\n", 17);
968 struct resultSet expect
= {
971 .parserState
= Http1::HTTP_PARSE_DONE
,
972 .status
= Http::scBadRequest
,
973 .suffixSz
= input
.length(),
974 .method
= HttpRequestMethod(),
976 .version
= AnyP::ProtocolVersion()
979 testResults(__LINE__
, input
, output
, expect
);
983 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
984 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
986 input
.append("GET HTTP/1.1\r\n", 15);
987 Config
.onoff
.relaxed_header_parser
= 1;
988 struct resultSet expect
= {
991 .parserState
= Http1::HTTP_PARSE_DONE
,
992 .status
= Http::scBadRequest
,
993 .suffixSz
= input
.length(),
994 .method
= HttpRequestMethod(),
996 .version
= AnyP::ProtocolVersion()
999 testResults(__LINE__
, input
, output
, expect
);
1001 Config
.onoff
.relaxed_header_parser
= 0;
1002 struct resultSet expectStrict
= {
1005 .parserState
= Http1::HTTP_PARSE_DONE
,
1006 .status
= Http::scBadRequest
,
1007 .suffixSz
= input
.length(),
1008 .method
= HttpRequestMethod(),
1010 .version
= AnyP::ProtocolVersion()
1013 testResults(__LINE__
, input
, output
, expectStrict
);
1017 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
1018 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
1020 input
.append("GET HTTP/1.1\r\n", 14);
1021 struct resultSet expect
= {
1024 .parserState
= Http1::HTTP_PARSE_DONE
,
1025 .status
= Http::scBadRequest
,
1026 .suffixSz
= input
.length(),
1027 .method
= HttpRequestMethod(),
1029 .version
= AnyP::ProtocolVersion()
1032 testResults(__LINE__
, input
, output
, expect
);
1038 input
.append("\xB\xC\xE\xF\n", 5);
1039 struct resultSet expect
= {
1042 .parserState
= Http1::HTTP_PARSE_DONE
,
1043 .status
= Http::scBadRequest
,
1044 .suffixSz
= input
.length(),
1045 .method
= HttpRequestMethod(),
1047 .version
= AnyP::ProtocolVersion()
1050 testResults(__LINE__
, input
, output
, expect
);
1054 // mixed whitespace line
1056 input
.append("\t \t \t\n", 6);
1057 struct resultSet expect
= {
1060 .parserState
= Http1::HTTP_PARSE_DONE
,
1061 .status
= Http::scBadRequest
,
1062 .suffixSz
= input
.length(),
1063 .method
= HttpRequestMethod(),
1065 .version
= AnyP::ProtocolVersion()
1068 testResults(__LINE__
, input
, output
, expect
);
1072 // mixed whitespace line with CR
1074 input
.append("\r \t \n", 6);
1075 struct resultSet expect
= {
1078 .parserState
= Http1::HTTP_PARSE_DONE
,
1079 .status
= Http::scBadRequest
,
1080 .suffixSz
= input
.length(),
1081 .method
= HttpRequestMethod(),
1083 .version
= AnyP::ProtocolVersion()
1086 testResults(__LINE__
, input
, output
, expect
);
1092 testHttp1Parser::testDripFeed()
1094 // Simulate a client drip-feeding Squid a few bytes at a time.
1095 // extend the size of the buffer from 0 bytes to full request length
1096 // calling the parser repeatedly as visible data grows.
1099 data
.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
1100 SBuf::size_type garbageEnd
= data
.length();
1101 data
.append("GET ", 4);
1102 data
.append("http://example.com/ ", 20);
1103 data
.append("HTTP/1.1\r\n", 10);
1104 SBuf::size_type reqLineEnd
= data
.length() - 1;
1105 data
.append("Host: example.com\r\n\r\n", 21);
1106 SBuf::size_type mimeEnd
= data
.length() - 1;
1107 data
.append("...", 3); // trailer to catch mime EOS errors.
1110 Http1::RequestParser hp
;
1112 // start with strict and move on to relaxed
1113 Config
.onoff
.relaxed_header_parser
= 2;
1115 Config
.maxRequestHeaderSize
= 1024; // large enough to hold the test data.
1119 // state of things we expect right now
1120 struct resultSet expect
= {
1123 .parserState
= Http1::HTTP_PARSE_NONE
,
1124 .status
= Http::scNone
,
1126 .method
= HttpRequestMethod(),
1128 .version
= AnyP::ProtocolVersion()
1131 ioBuf
.clear(); // begins empty for each parser type
1134 --Config
.onoff
.relaxed_header_parser
;
1136 for (SBuf::size_type pos
= 0; pos
<= data
.length(); ++pos
) {
1138 // simulate reading one more byte
1139 ioBuf
.append(data
.substr(pos
,1));
1141 // strict does not permit the garbage prefix
1142 if (pos
< garbageEnd
&& !Config
.onoff
.relaxed_header_parser
) {
1147 // when the garbage is passed we expect to start seeing first-line bytes
1148 if (pos
== garbageEnd
)
1149 expect
.parserState
= Http1::HTTP_PARSE_FIRST
;
1151 // all points after garbage start to see accumulated bytes looking for end of current section
1152 if (pos
>= garbageEnd
)
1153 expect
.suffixSz
= ioBuf
.length();
1155 // at end of request line expect to see method, URI, version details
1156 // and switch to seeking Mime header section
1157 if (pos
== reqLineEnd
) {
1158 expect
.parserState
= Http1::HTTP_PARSE_MIME
;
1159 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1160 expect
.status
= Http::scOkay
;
1161 expect
.method
= HttpRequestMethod(Http::METHOD_GET
);
1162 expect
.uri
= "http://example.com/";
1163 expect
.version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1);
1166 // one mime header is done we are expecting a new request
1167 // parse results say true and initial data is all gone from the buffer
1168 if (pos
== mimeEnd
) {
1169 expect
.parsed
= true;
1170 expect
.needsMore
= false;
1171 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1174 testResults(__LINE__
, ioBuf
, hp
, expect
);
1176 // sync the buffers like Squid does
1177 ioBuf
= hp
.remaining();
1179 // Squid stops using the parser once it has parsed the first message.
1180 if (!hp
.needsMoreData())
1184 } while (Config
.onoff
.relaxed_header_parser
);
1187 #endif /* __cplusplus >= 201103L */