]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
2 * Copyright (C) 1996-2022 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
16 #include "debug/Stream.h"
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";
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
!= nullptr)
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());
124 testHttp1Parser::testParserConstruct()
126 // whether the constructor works
128 Http1::RequestParser output
;
129 CPPUNIT_ASSERT_EQUAL(true, output
.needsMoreData());
130 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
.parsingStage_
);
131 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
.parseStatusCode
); // XXX: clear() not being called.
132 CPPUNIT_ASSERT(output
.buf_
.isEmpty());
133 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
.method_
);
134 CPPUNIT_ASSERT(output
.uri_
.isEmpty());
135 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
.msgProtocol_
);
138 // whether new() works
140 Http1::RequestParser
*output
= new Http1::RequestParser
;
141 CPPUNIT_ASSERT_EQUAL(true, output
->needsMoreData());
142 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
->parsingStage_
);
143 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
->parseStatusCode
);
144 CPPUNIT_ASSERT(output
->buf_
.isEmpty());
145 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
->method_
);
146 CPPUNIT_ASSERT(output
->uri_
.isEmpty());
147 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
->msgProtocol_
);
153 testHttp1Parser::testParseRequestLineProtocols()
155 // ensure MemPools etc exist
159 Http1::RequestParser output
;
161 // TEST: Do we comply with RFC 1945 section 5.1 ?
162 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
164 // RFC 1945 : HTTP/0.9 simple-request
166 input
.append("GET /\r\n", 7);
167 struct resultSet expect
= {
170 .parserState
= Http1::HTTP_PARSE_DONE
,
171 .status
= Http::scOkay
,
173 .method
= HttpRequestMethod(Http::METHOD_GET
),
175 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,0,9)
178 testResults(__LINE__
, input
, output
, expect
);
182 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
184 input
.append("POST /\r\n", 8);
185 struct resultSet expect
= {
188 .parserState
= Http1::HTTP_PARSE_DONE
,
189 .status
= Http::scBadRequest
,
190 .suffixSz
= input
.length(),
191 .method
= HttpRequestMethod(Http::METHOD_POST
),
193 .version
= AnyP::ProtocolVersion()
196 testResults(__LINE__
, input
, output
, expect
);
200 // RFC 1945 and 7230 : HTTP/1.0 request
202 input
.append("GET / HTTP/1.0\r\n", 16);
203 struct resultSet expect
= {
206 .parserState
= Http1::HTTP_PARSE_MIME
,
207 .status
= Http::scOkay
,
209 .method
= HttpRequestMethod(Http::METHOD_GET
),
211 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,0)
214 testResults(__LINE__
, input
, output
, expect
);
218 // RFC 7230 : HTTP/1.1 request
220 input
.append("GET / HTTP/1.1\r\n", 16);
221 struct resultSet expect
= {
224 .parserState
= Http1::HTTP_PARSE_MIME
,
225 .status
= Http::scOkay
,
227 .method
= HttpRequestMethod(Http::METHOD_GET
),
229 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
232 testResults(__LINE__
, input
, output
, expect
);
236 // RFC 7230 : future 1.x version full-request
238 input
.append("GET / HTTP/1.2\r\n", 16);
239 struct resultSet expect
= {
242 .parserState
= Http1::HTTP_PARSE_MIME
,
243 .status
= Http::scOkay
,
245 .method
= HttpRequestMethod(Http::METHOD_GET
),
247 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,2)
250 testResults(__LINE__
, input
, output
, expect
);
254 // RFC 7230 : future versions do not use 1.x message syntax.
255 // However, it is still valid syntax for the single-digit forms
256 // to appear. The parser we are testing should accept them.
258 input
.append("GET / HTTP/2.0\r\n", 16);
259 struct resultSet expectA
= {
262 .parserState
= Http1::HTTP_PARSE_DONE
,
263 .status
= Http::scOkay
,
265 .method
= HttpRequestMethod(Http::METHOD_GET
),
267 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,2,0)
270 testResults(__LINE__
, input
, output
, expectA
);
273 input
.append("GET / HTTP/9.9\r\n", 16);
274 struct resultSet expectB
= {
277 .parserState
= Http1::HTTP_PARSE_DONE
,
278 .status
= Http::scOkay
,
280 .method
= HttpRequestMethod(Http::METHOD_GET
),
282 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,9,9)
285 testResults(__LINE__
, input
, output
, expectB
);
289 // RFC 7230 : future versions >= 10.0 are invalid syntax
291 input
.append("GET / HTTP/10.12\r\n", 18);
292 struct resultSet expect
= {
295 .parserState
= Http1::HTTP_PARSE_MIME
,
296 .status
= Http::scBadRequest
,
297 .suffixSz
= input
.length(),
298 .method
= HttpRequestMethod(Http::METHOD_GET
),
300 .version
= AnyP::ProtocolVersion()
303 testResults(__LINE__
, input
, output
, expect
);
307 // unknown non-HTTP protocol names
309 input
.append("GET / FOO/1.0\r\n", 15);
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/\r\n", 13);
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/.1\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
);
363 input
.append("GET / HTTP/11\r\n", 15);
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
);
379 // negative major version (bug 3062)
381 input
.append("GET / HTTP/-999999.1\r\n", 22);
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
);
399 input
.append("GET / HTTP/1.\r\n", 15);
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
);
415 // negative major version (bug 3062 corollary)
417 input
.append("GET / HTTP/1.-999999\r\n", 22);
418 struct resultSet expect
= {
421 .parserState
= Http1::HTTP_PARSE_DONE
,
422 .status
= Http::scBadRequest
,
423 .suffixSz
= input
.length(),
424 .method
= HttpRequestMethod(Http::METHOD_GET
),
426 .version
= AnyP::ProtocolVersion()
429 testResults(__LINE__
, input
, output
, expect
);
435 testHttp1Parser::testParseRequestLineStrange()
437 // ensure MemPools etc exist
441 Http1::RequestParser output
;
445 input
.append("GET / HTTP/1.1\r\n", 21);
446 // when being tolerant extra (sequential) SP delimiters are acceptable
447 Config
.onoff
.relaxed_header_parser
= 1;
448 struct resultSet expect
= {
451 .parserState
= Http1::HTTP_PARSE_MIME
,
452 .status
= Http::scOkay
,
454 .method
= HttpRequestMethod(Http::METHOD_GET
),
456 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
459 testResults(__LINE__
, input
, output
, expect
);
461 Config
.onoff
.relaxed_header_parser
= 0;
462 struct resultSet expectStrict
= {
465 .parserState
= Http1::HTTP_PARSE_DONE
,
466 .status
= Http::scBadRequest
,
467 .suffixSz
= input
.length(),
468 .method
= HttpRequestMethod(),
470 .version
= AnyP::ProtocolVersion()
473 testResults(__LINE__
, input
, output
, expectStrict
);
477 // whitespace inside URI. (nasty but happens)
479 input
.append("GET /fo o/ HTTP/1.1\r\n", 21);
480 Config
.onoff
.relaxed_header_parser
= 1;
481 struct resultSet expect
= {
484 .parserState
= Http1::HTTP_PARSE_MIME
,
485 .status
= Http::scOkay
,
487 .method
= HttpRequestMethod(Http::METHOD_GET
),
489 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
492 testResults(__LINE__
, input
, output
, expect
);
494 Config
.onoff
.relaxed_header_parser
= 0;
495 struct resultSet expectStrict
= {
498 .parserState
= Http1::HTTP_PARSE_DONE
,
499 .status
= Http::scBadRequest
,
500 .suffixSz
= input
.length(),
501 .method
= HttpRequestMethod(),
503 .version
= AnyP::ProtocolVersion()
506 testResults(__LINE__
, input
, output
, expectStrict
);
510 // additional data in buffer
512 input
.append("GET / HTTP/1.1\r\nboo!", 20);
513 struct resultSet expect
= {
516 .parserState
= Http1::HTTP_PARSE_MIME
,
517 .status
= Http::scOkay
,
518 .suffixSz
= 4, // strlen("boo!")
519 .method
= HttpRequestMethod(Http::METHOD_GET
),
521 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
524 testResults(__LINE__
, input
, output
, expect
);
526 Config
.onoff
.relaxed_header_parser
= 0;
531 testHttp1Parser::testParseRequestLineTerminators()
533 // ensure MemPools etc exist
537 Http1::RequestParser output
;
539 // alternative EOL sequence: NL-only
540 // RFC 7230 tolerance permits omitted CR
542 input
.append("GET / HTTP/1.1\n", 15);
543 Config
.onoff
.relaxed_header_parser
= 1;
544 struct resultSet expect
= {
547 .parserState
= Http1::HTTP_PARSE_MIME
,
548 .status
= Http::scOkay
,
550 .method
= HttpRequestMethod(Http::METHOD_GET
),
552 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
555 testResults(__LINE__
, input
, output
, expect
);
557 Config
.onoff
.relaxed_header_parser
= 0;
558 struct resultSet expectStrict
= {
561 .parserState
= Http1::HTTP_PARSE_DONE
,
562 .status
= Http::scBadRequest
,
563 .suffixSz
= input
.length(),
564 .method
= HttpRequestMethod(),
566 .version
= AnyP::ProtocolVersion()
569 testResults(__LINE__
, input
, output
, expectStrict
);
573 // alternative EOL sequence: double-NL-only
574 // RFC 7230 tolerance permits omitted CR
575 // NP: represents a request with no mime headers
577 input
.append("GET / HTTP/1.1\n\n", 16);
578 Config
.onoff
.relaxed_header_parser
= 1;
579 struct resultSet expect
= {
582 .parserState
= Http1::HTTP_PARSE_DONE
,
583 .status
= Http::scOkay
,
585 .method
= HttpRequestMethod(Http::METHOD_GET
),
587 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
590 testResults(__LINE__
, input
, output
, expect
);
592 Config
.onoff
.relaxed_header_parser
= 0;
593 struct resultSet expectStrict
= {
596 .parserState
= Http1::HTTP_PARSE_DONE
,
597 .status
= Http::scBadRequest
,
598 .suffixSz
= input
.length(),
599 .method
= HttpRequestMethod(),
601 .version
= AnyP::ProtocolVersion()
604 testResults(__LINE__
, input
, output
, expectStrict
);
608 // space padded version
610 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
611 input
.append("GET / HTTP/1.1 \r\n", 17);
612 struct resultSet expect
= {
615 .parserState
= Http1::HTTP_PARSE_DONE
,
616 .status
= Http::scBadRequest
,
617 .suffixSz
= input
.length(),
618 .method
= HttpRequestMethod(),
620 .version
= AnyP::ProtocolVersion()
623 testResults(__LINE__
, input
, output
, expect
);
629 testHttp1Parser::testParseRequestLineMethods()
631 // ensure MemPools etc exist
635 Http1::RequestParser output
;
637 // RFC 7230 : dot method
639 input
.append(". / HTTP/1.1\r\n", 14);
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 // RFC 7230 : special TCHAR method chars
657 input
.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
658 struct resultSet expect
= {
661 .parserState
= Http1::HTTP_PARSE_MIME
,
662 .status
= Http::scOkay
,
664 .method
= HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
666 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
669 testResults(__LINE__
, input
, output
, expect
);
673 // OPTIONS with * URL
675 input
.append("OPTIONS * HTTP/1.1\r\n", 20);
676 struct resultSet expect
= {
679 .parserState
= Http1::HTTP_PARSE_MIME
,
680 .status
= Http::scOkay
,
682 .method
= HttpRequestMethod(Http::METHOD_OPTIONS
),
684 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
687 testResults(__LINE__
, input
, output
, expect
);
693 input
.append("HELLOWORLD / HTTP/1.1\r\n", 23);
694 struct resultSet expect
= {
697 .parserState
= Http1::HTTP_PARSE_MIME
,
698 .status
= Http::scOkay
,
700 .method
= HttpRequestMethod(SBuf("HELLOWORLD")),
702 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
705 testResults(__LINE__
, input
, output
, expect
);
711 input
.append("A\n", 2);
712 struct resultSet expect
= {
715 .parserState
= Http1::HTTP_PARSE_DONE
,
716 .status
= Http::scBadRequest
,
717 .suffixSz
= input
.length(),
718 .method
= HttpRequestMethod(),
720 .version
= AnyP::ProtocolVersion()
723 testResults(__LINE__
, input
, output
, expect
);
728 input
.append("GET\n", 4);
729 struct resultSet expect
= {
732 .parserState
= Http1::HTTP_PARSE_DONE
,
733 .status
= Http::scBadRequest
,
734 .suffixSz
= input
.length(),
735 .method
= HttpRequestMethod(),
737 .version
= AnyP::ProtocolVersion()
740 testResults(__LINE__
, input
, output
, expect
);
744 // space padded method (SP is reserved so invalid as a method byte)
746 input
.append(" GET / HTTP/1.1\r\n", 17);
747 struct resultSet expect
= {
750 .parserState
= Http1::HTTP_PARSE_DONE
,
751 .status
= Http::scBadRequest
,
752 .suffixSz
= input
.length(),
753 .method
= HttpRequestMethod(),
755 .version
= AnyP::ProtocolVersion()
758 testResults(__LINE__
, input
, output
, expect
);
762 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
764 input
.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
765 Config
.onoff
.relaxed_header_parser
= 1;
766 struct resultSet expect
= {
769 .parserState
= Http1::HTTP_PARSE_MIME
,
770 .status
= Http::scOkay
,
772 .method
= HttpRequestMethod(Http::METHOD_GET
),
774 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
777 testResults(__LINE__
, input
, output
, expect
);
779 Config
.onoff
.relaxed_header_parser
= 0;
780 struct resultSet expectStrict
= {
783 .parserState
= Http1::HTTP_PARSE_DONE
,
784 .status
= Http::scBadRequest
,
785 .suffixSz
= input
.length(),
786 .method
= HttpRequestMethod(),
788 .version
= AnyP::ProtocolVersion()
791 testResults(__LINE__
, input
, output
, expectStrict
);
795 // forbidden character in method
797 input
.append("\tGET / HTTP/1.1\r\n", 17);
798 struct resultSet expect
= {
801 .parserState
= Http1::HTTP_PARSE_DONE
,
802 .status
= Http::scBadRequest
,
803 .suffixSz
= input
.length(),
804 .method
= HttpRequestMethod(),
806 .version
= AnyP::ProtocolVersion()
809 testResults(__LINE__
, input
, output
, expect
);
813 // CR in method delimiters
815 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
816 input
.append("GET\r / HTTP/1.1\r\n", 17);
817 Config
.onoff
.relaxed_header_parser
= 1;
818 struct resultSet expect
= {
821 .parserState
= Http1::HTTP_PARSE_MIME
,
822 .status
= Http::scOkay
,
824 .method
= HttpRequestMethod(Http::METHOD_GET
),
826 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
829 testResults(__LINE__
, input
, output
, expect
);
831 Config
.onoff
.relaxed_header_parser
= 0;
832 struct resultSet expectStrict
= {
835 .parserState
= Http1::HTTP_PARSE_DONE
,
836 .status
= Http::scBadRequest
,
837 .suffixSz
= input
.length(),
838 .method
= HttpRequestMethod(),
840 .version
= AnyP::ProtocolVersion()
843 testResults(__LINE__
, input
, output
, expectStrict
);
847 // tolerant parser delimiters
849 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
850 input
.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
851 Config
.onoff
.relaxed_header_parser
= 1;
852 struct resultSet expect
= {
855 .parserState
= Http1::HTTP_PARSE_MIME
,
856 .status
= Http::scOkay
,
858 .method
= HttpRequestMethod(Http::METHOD_GET
),
860 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
863 testResults(__LINE__
, input
, output
, expect
);
865 Config
.onoff
.relaxed_header_parser
= 0;
866 struct resultSet expectStrict
= {
869 .parserState
= Http1::HTTP_PARSE_DONE
,
870 .status
= Http::scBadRequest
,
871 .suffixSz
= input
.length(),
872 .method
= HttpRequestMethod(),
874 .version
= AnyP::ProtocolVersion()
877 testResults(__LINE__
, input
, output
, expectStrict
);
883 testHttp1Parser::testParseRequestLineInvalid()
885 // ensure MemPools etc exist
889 Http1::RequestParser output
;
891 // no method (or method delimiter)
893 // HTTP/0.9 requires method to be "GET"
894 input
.append("/ HTTP/1.0\n", 11);
895 struct resultSet expect
= {
898 .parserState
= Http1::HTTP_PARSE_DONE
,
899 .status
= Http::scBadRequest
,
900 .suffixSz
= input
.length(),
901 .method
= HttpRequestMethod(),
903 .version
= AnyP::ProtocolVersion()
906 testResults(__LINE__
, input
, output
, expect
);
910 // no method (with method delimiter)
912 input
.append(" / HTTP/1.0\n", 12);
913 struct resultSet expectStrict
= {
916 .parserState
= Http1::HTTP_PARSE_DONE
,
917 .status
= Http::scBadRequest
,
918 .suffixSz
= input
.length(),
919 .method
= HttpRequestMethod(),
921 .version
= AnyP::ProtocolVersion()
924 testResults(__LINE__
, input
, output
, expectStrict
);
928 // binary code after method (invalid)
930 input
.append("GET\x16 / HTTP/1.1\r\n", 17);
931 struct resultSet expect
= {
934 .parserState
= Http1::HTTP_PARSE_DONE
,
935 .status
= Http::scBadRequest
,
936 .suffixSz
= input
.length(),
937 .method
= HttpRequestMethod(),
939 .version
= AnyP::ProtocolVersion()
942 testResults(__LINE__
, input
, output
, expect
);
946 // binary code NUL! after method (always invalid)
948 input
.append("GET\0 / HTTP/1.1\r\n", 17);
949 struct resultSet expect
= {
952 .parserState
= Http1::HTTP_PARSE_DONE
,
953 .status
= Http::scBadRequest
,
954 .suffixSz
= input
.length(),
955 .method
= HttpRequestMethod(),
957 .version
= AnyP::ProtocolVersion()
960 testResults(__LINE__
, input
, output
, expect
);
964 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
965 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
967 input
.append("GET HTTP/1.1\r\n", 15);
968 Config
.onoff
.relaxed_header_parser
= 1;
969 struct resultSet expect
= {
972 .parserState
= Http1::HTTP_PARSE_DONE
,
973 .status
= Http::scBadRequest
,
974 .suffixSz
= input
.length(),
975 .method
= HttpRequestMethod(),
977 .version
= AnyP::ProtocolVersion()
980 testResults(__LINE__
, input
, output
, expect
);
982 Config
.onoff
.relaxed_header_parser
= 0;
983 struct resultSet expectStrict
= {
986 .parserState
= Http1::HTTP_PARSE_DONE
,
987 .status
= Http::scBadRequest
,
988 .suffixSz
= input
.length(),
989 .method
= HttpRequestMethod(),
991 .version
= AnyP::ProtocolVersion()
994 testResults(__LINE__
, input
, output
, expectStrict
);
998 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
999 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
1001 input
.append("GET HTTP/1.1\r\n", 14);
1002 struct resultSet expect
= {
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
, expect
);
1019 input
.append("\xB\xC\xE\xF\n", 5);
1020 struct resultSet expect
= {
1023 .parserState
= Http1::HTTP_PARSE_DONE
,
1024 .status
= Http::scBadRequest
,
1025 .suffixSz
= input
.length(),
1026 .method
= HttpRequestMethod(),
1028 .version
= AnyP::ProtocolVersion()
1031 testResults(__LINE__
, input
, output
, expect
);
1035 // mixed whitespace line
1037 input
.append("\t \t \t\n", 6);
1038 struct resultSet expect
= {
1041 .parserState
= Http1::HTTP_PARSE_DONE
,
1042 .status
= Http::scBadRequest
,
1043 .suffixSz
= input
.length(),
1044 .method
= HttpRequestMethod(),
1046 .version
= AnyP::ProtocolVersion()
1049 testResults(__LINE__
, input
, output
, expect
);
1053 // mixed whitespace line with CR
1055 input
.append("\r \t \n", 6);
1056 struct resultSet expect
= {
1059 .parserState
= Http1::HTTP_PARSE_DONE
,
1060 .status
= Http::scBadRequest
,
1061 .suffixSz
= input
.length(),
1062 .method
= HttpRequestMethod(),
1064 .version
= AnyP::ProtocolVersion()
1067 testResults(__LINE__
, input
, output
, expect
);
1073 testHttp1Parser::testDripFeed()
1075 // Simulate a client drip-feeding Squid a few bytes at a time.
1076 // extend the size of the buffer from 0 bytes to full request length
1077 // calling the parser repeatedly as visible data grows.
1080 data
.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
1081 SBuf::size_type garbageEnd
= data
.length();
1082 data
.append("GET ", 4);
1083 data
.append("http://example.com/ ", 20);
1084 data
.append("HTTP/1.1\r\n", 10);
1085 SBuf::size_type reqLineEnd
= data
.length() - 1;
1086 data
.append("Host: example.com\r\n\r\n", 21);
1087 SBuf::size_type mimeEnd
= data
.length() - 1;
1088 data
.append("...", 3); // trailer to catch mime EOS errors.
1091 Http1::RequestParser hp
;
1093 // start with strict and move on to relaxed
1094 Config
.onoff
.relaxed_header_parser
= 2;
1096 Config
.maxRequestHeaderSize
= 1024; // large enough to hold the test data.
1100 // state of things we expect right now
1101 struct resultSet expect
= {
1104 .parserState
= Http1::HTTP_PARSE_NONE
,
1105 .status
= Http::scNone
,
1107 .method
= HttpRequestMethod(),
1109 .version
= AnyP::ProtocolVersion()
1112 ioBuf
.clear(); // begins empty for each parser type
1115 --Config
.onoff
.relaxed_header_parser
;
1117 for (SBuf::size_type pos
= 0; pos
<= data
.length(); ++pos
) {
1119 // simulate reading one more byte
1120 ioBuf
.append(data
.substr(pos
,1));
1122 // strict does not permit the garbage prefix
1123 if (pos
< garbageEnd
&& !Config
.onoff
.relaxed_header_parser
) {
1128 // when the garbage is passed we expect to start seeing first-line bytes
1129 if (pos
== garbageEnd
)
1130 expect
.parserState
= Http1::HTTP_PARSE_FIRST
;
1132 // all points after garbage start to see accumulated bytes looking for end of current section
1133 if (pos
>= garbageEnd
)
1134 expect
.suffixSz
= ioBuf
.length();
1136 // at end of request line expect to see method, URI, version details
1137 // and switch to seeking Mime header section
1138 if (pos
== reqLineEnd
) {
1139 expect
.parserState
= Http1::HTTP_PARSE_MIME
;
1140 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1141 expect
.status
= Http::scOkay
;
1142 expect
.method
= HttpRequestMethod(Http::METHOD_GET
);
1143 expect
.uri
= "http://example.com/";
1144 expect
.version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1);
1147 // one mime header is done we are expecting a new request
1148 // parse results say true and initial data is all gone from the buffer
1149 if (pos
== mimeEnd
) {
1150 expect
.parsed
= true;
1151 expect
.needsMore
= false;
1152 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1155 testResults(__LINE__
, ioBuf
, hp
, expect
);
1157 // sync the buffers like Squid does
1158 ioBuf
= hp
.remaining();
1160 // Squid stops using the parser once it has parsed the first message.
1161 if (!hp
.needsMoreData())
1165 } while (Config
.onoff
.relaxed_header_parser
);