]>
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_
);
151 testHttp1Parser::testParseRequestLineProtocols()
153 // ensure MemPools etc exist
157 Http1::RequestParser output
;
159 // TEST: Do we comply with RFC 1945 section 5.1 ?
160 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
162 // RFC 1945 : HTTP/0.9 simple-request
164 input
.append("GET /\r\n", 7);
165 struct resultSet expect
= {
168 .parserState
= Http1::HTTP_PARSE_DONE
,
169 .status
= Http::scOkay
,
171 .method
= HttpRequestMethod(Http::METHOD_GET
),
173 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,0,9)
176 testResults(__LINE__
, input
, output
, expect
);
180 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
182 input
.append("POST /\r\n", 8);
183 struct resultSet expect
= {
186 .parserState
= Http1::HTTP_PARSE_DONE
,
187 .status
= Http::scBadRequest
,
188 .suffixSz
= input
.length(),
189 .method
= HttpRequestMethod(Http::METHOD_POST
),
191 .version
= AnyP::ProtocolVersion()
194 testResults(__LINE__
, input
, output
, expect
);
198 // RFC 1945 and 7230 : HTTP/1.0 request
200 input
.append("GET / HTTP/1.0\r\n", 16);
201 struct resultSet expect
= {
204 .parserState
= Http1::HTTP_PARSE_MIME
,
205 .status
= Http::scOkay
,
207 .method
= HttpRequestMethod(Http::METHOD_GET
),
209 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,0)
212 testResults(__LINE__
, input
, output
, expect
);
216 // RFC 7230 : HTTP/1.1 request
218 input
.append("GET / HTTP/1.1\r\n", 16);
219 struct resultSet expect
= {
222 .parserState
= Http1::HTTP_PARSE_MIME
,
223 .status
= Http::scOkay
,
225 .method
= HttpRequestMethod(Http::METHOD_GET
),
227 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
230 testResults(__LINE__
, input
, output
, expect
);
234 // RFC 7230 : future 1.x version full-request
236 input
.append("GET / HTTP/1.2\r\n", 16);
237 struct resultSet expect
= {
240 .parserState
= Http1::HTTP_PARSE_MIME
,
241 .status
= Http::scOkay
,
243 .method
= HttpRequestMethod(Http::METHOD_GET
),
245 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,2)
248 testResults(__LINE__
, input
, output
, expect
);
252 // RFC 7230 : future versions do not use 1.x message syntax.
253 // However, it is still valid syntax for the single-digit forms
254 // to appear. The parser we are testing should accept them.
256 input
.append("GET / HTTP/2.0\r\n", 16);
257 struct resultSet expectA
= {
260 .parserState
= Http1::HTTP_PARSE_DONE
,
261 .status
= Http::scOkay
,
263 .method
= HttpRequestMethod(Http::METHOD_GET
),
265 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,2,0)
268 testResults(__LINE__
, input
, output
, expectA
);
271 input
.append("GET / HTTP/9.9\r\n", 16);
272 struct resultSet expectB
= {
275 .parserState
= Http1::HTTP_PARSE_DONE
,
276 .status
= Http::scOkay
,
278 .method
= HttpRequestMethod(Http::METHOD_GET
),
280 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,9,9)
283 testResults(__LINE__
, input
, output
, expectB
);
287 // RFC 7230 : future versions >= 10.0 are invalid syntax
289 input
.append("GET / HTTP/10.12\r\n", 18);
290 struct resultSet expect
= {
293 .parserState
= Http1::HTTP_PARSE_MIME
,
294 .status
= Http::scBadRequest
,
295 .suffixSz
= input
.length(),
296 .method
= HttpRequestMethod(Http::METHOD_GET
),
298 .version
= AnyP::ProtocolVersion()
301 testResults(__LINE__
, input
, output
, expect
);
305 // unknown non-HTTP protocol names
307 input
.append("GET / FOO/1.0\r\n", 15);
308 struct resultSet expect
= {
311 .parserState
= Http1::HTTP_PARSE_DONE
,
312 .status
= Http::scBadRequest
,
313 .suffixSz
= input
.length(),
314 .method
= HttpRequestMethod(Http::METHOD_GET
),
316 .version
= AnyP::ProtocolVersion()
319 testResults(__LINE__
, input
, output
, expect
);
325 input
.append("GET / HTTP/\r\n", 13);
326 struct resultSet expect
= {
329 .parserState
= Http1::HTTP_PARSE_DONE
,
330 .status
= Http::scBadRequest
,
331 .suffixSz
= input
.length(),
332 .method
= HttpRequestMethod(Http::METHOD_GET
),
334 .version
= AnyP::ProtocolVersion()
337 testResults(__LINE__
, input
, output
, expect
);
343 input
.append("GET / HTTP/.1\r\n", 15);
344 struct resultSet expect
= {
347 .parserState
= Http1::HTTP_PARSE_DONE
,
348 .status
= Http::scBadRequest
,
349 .suffixSz
= input
.length(),
350 .method
= HttpRequestMethod(Http::METHOD_GET
),
352 .version
= AnyP::ProtocolVersion()
355 testResults(__LINE__
, input
, output
, expect
);
361 input
.append("GET / HTTP/11\r\n", 15);
362 struct resultSet expect
= {
365 .parserState
= Http1::HTTP_PARSE_DONE
,
366 .status
= Http::scBadRequest
,
367 .suffixSz
= input
.length(),
368 .method
= HttpRequestMethod(Http::METHOD_GET
),
370 .version
= AnyP::ProtocolVersion()
373 testResults(__LINE__
, input
, output
, expect
);
377 // negative major version (bug 3062)
379 input
.append("GET / HTTP/-999999.1\r\n", 22);
380 struct resultSet expect
= {
383 .parserState
= Http1::HTTP_PARSE_DONE
,
384 .status
= Http::scBadRequest
,
385 .suffixSz
= input
.length(),
386 .method
= HttpRequestMethod(Http::METHOD_GET
),
388 .version
= AnyP::ProtocolVersion()
391 testResults(__LINE__
, input
, output
, expect
);
397 input
.append("GET / HTTP/1.\r\n", 15);
398 struct resultSet expect
= {
401 .parserState
= Http1::HTTP_PARSE_DONE
,
402 .status
= Http::scBadRequest
,
403 .suffixSz
= input
.length(),
404 .method
= HttpRequestMethod(Http::METHOD_GET
),
406 .version
= AnyP::ProtocolVersion()
409 testResults(__LINE__
, input
, output
, expect
);
413 // negative major version (bug 3062 corollary)
415 input
.append("GET / HTTP/1.-999999\r\n", 22);
416 struct resultSet expect
= {
419 .parserState
= Http1::HTTP_PARSE_DONE
,
420 .status
= Http::scBadRequest
,
421 .suffixSz
= input
.length(),
422 .method
= HttpRequestMethod(Http::METHOD_GET
),
424 .version
= AnyP::ProtocolVersion()
427 testResults(__LINE__
, input
, output
, expect
);
433 testHttp1Parser::testParseRequestLineStrange()
435 // ensure MemPools etc exist
439 Http1::RequestParser output
;
443 input
.append("GET / HTTP/1.1\r\n", 21);
444 // when being tolerant extra (sequential) SP delimiters are acceptable
445 Config
.onoff
.relaxed_header_parser
= 1;
446 struct resultSet expect
= {
449 .parserState
= Http1::HTTP_PARSE_MIME
,
450 .status
= Http::scOkay
,
452 .method
= HttpRequestMethod(Http::METHOD_GET
),
454 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
457 testResults(__LINE__
, input
, output
, expect
);
459 Config
.onoff
.relaxed_header_parser
= 0;
460 struct resultSet expectStrict
= {
463 .parserState
= Http1::HTTP_PARSE_DONE
,
464 .status
= Http::scBadRequest
,
465 .suffixSz
= input
.length(),
466 .method
= HttpRequestMethod(),
468 .version
= AnyP::ProtocolVersion()
471 testResults(__LINE__
, input
, output
, expectStrict
);
475 // whitespace inside URI. (nasty but happens)
477 input
.append("GET /fo o/ HTTP/1.1\r\n", 21);
478 Config
.onoff
.relaxed_header_parser
= 1;
479 struct resultSet expect
= {
482 .parserState
= Http1::HTTP_PARSE_MIME
,
483 .status
= Http::scOkay
,
485 .method
= HttpRequestMethod(Http::METHOD_GET
),
487 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
490 testResults(__LINE__
, input
, output
, expect
);
492 Config
.onoff
.relaxed_header_parser
= 0;
493 struct resultSet expectStrict
= {
496 .parserState
= Http1::HTTP_PARSE_DONE
,
497 .status
= Http::scBadRequest
,
498 .suffixSz
= input
.length(),
499 .method
= HttpRequestMethod(),
501 .version
= AnyP::ProtocolVersion()
504 testResults(__LINE__
, input
, output
, expectStrict
);
508 // additional data in buffer
510 input
.append("GET / HTTP/1.1\r\nboo!", 20);
511 struct resultSet expect
= {
514 .parserState
= Http1::HTTP_PARSE_MIME
,
515 .status
= Http::scOkay
,
516 .suffixSz
= 4, // strlen("boo!")
517 .method
= HttpRequestMethod(Http::METHOD_GET
),
519 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
522 testResults(__LINE__
, input
, output
, expect
);
524 Config
.onoff
.relaxed_header_parser
= 0;
529 testHttp1Parser::testParseRequestLineTerminators()
531 // ensure MemPools etc exist
535 Http1::RequestParser output
;
537 // alternative EOL sequence: NL-only
538 // RFC 7230 tolerance permits omitted CR
540 input
.append("GET / HTTP/1.1\n", 15);
541 Config
.onoff
.relaxed_header_parser
= 1;
542 struct resultSet expect
= {
545 .parserState
= Http1::HTTP_PARSE_MIME
,
546 .status
= Http::scOkay
,
548 .method
= HttpRequestMethod(Http::METHOD_GET
),
550 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
553 testResults(__LINE__
, input
, output
, expect
);
555 Config
.onoff
.relaxed_header_parser
= 0;
556 struct resultSet expectStrict
= {
559 .parserState
= Http1::HTTP_PARSE_DONE
,
560 .status
= Http::scBadRequest
,
561 .suffixSz
= input
.length(),
562 .method
= HttpRequestMethod(),
564 .version
= AnyP::ProtocolVersion()
567 testResults(__LINE__
, input
, output
, expectStrict
);
571 // alternative EOL sequence: double-NL-only
572 // RFC 7230 tolerance permits omitted CR
573 // NP: represents a request with no mime headers
575 input
.append("GET / HTTP/1.1\n\n", 16);
576 Config
.onoff
.relaxed_header_parser
= 1;
577 struct resultSet expect
= {
580 .parserState
= Http1::HTTP_PARSE_DONE
,
581 .status
= Http::scOkay
,
583 .method
= HttpRequestMethod(Http::METHOD_GET
),
585 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
588 testResults(__LINE__
, input
, output
, expect
);
590 Config
.onoff
.relaxed_header_parser
= 0;
591 struct resultSet expectStrict
= {
594 .parserState
= Http1::HTTP_PARSE_DONE
,
595 .status
= Http::scBadRequest
,
596 .suffixSz
= input
.length(),
597 .method
= HttpRequestMethod(),
599 .version
= AnyP::ProtocolVersion()
602 testResults(__LINE__
, input
, output
, expectStrict
);
606 // space padded version
608 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
609 input
.append("GET / HTTP/1.1 \r\n", 17);
610 struct resultSet expect
= {
613 .parserState
= Http1::HTTP_PARSE_DONE
,
614 .status
= Http::scBadRequest
,
615 .suffixSz
= input
.length(),
616 .method
= HttpRequestMethod(),
618 .version
= AnyP::ProtocolVersion()
621 testResults(__LINE__
, input
, output
, expect
);
627 testHttp1Parser::testParseRequestLineMethods()
629 // ensure MemPools etc exist
633 Http1::RequestParser output
;
635 // RFC 7230 : dot method
637 input
.append(". / HTTP/1.1\r\n", 14);
638 struct resultSet expect
= {
641 .parserState
= Http1::HTTP_PARSE_MIME
,
642 .status
= Http::scOkay
,
644 .method
= HttpRequestMethod(SBuf(".")),
646 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
649 testResults(__LINE__
, input
, output
, expect
);
653 // RFC 7230 : special TCHAR method chars
655 input
.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
656 struct resultSet expect
= {
659 .parserState
= Http1::HTTP_PARSE_MIME
,
660 .status
= Http::scOkay
,
662 .method
= HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
664 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
667 testResults(__LINE__
, input
, output
, expect
);
671 // OPTIONS with * URL
673 input
.append("OPTIONS * HTTP/1.1\r\n", 20);
674 struct resultSet expect
= {
677 .parserState
= Http1::HTTP_PARSE_MIME
,
678 .status
= Http::scOkay
,
680 .method
= HttpRequestMethod(Http::METHOD_OPTIONS
),
682 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
685 testResults(__LINE__
, input
, output
, expect
);
691 input
.append("HELLOWORLD / HTTP/1.1\r\n", 23);
692 struct resultSet expect
= {
695 .parserState
= Http1::HTTP_PARSE_MIME
,
696 .status
= Http::scOkay
,
698 .method
= HttpRequestMethod(SBuf("HELLOWORLD")),
700 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
703 testResults(__LINE__
, input
, output
, expect
);
708 // too-long method (over 16 bytes)
710 input
.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
711 struct resultSet expect
= {
714 .parserState
= Http1::HTTP_PARSE_DONE
,
715 .status
= Http::scNotImplemented
,
716 .suffixSz
= input
.length(),
717 .method
= HttpRequestMethod(),
719 .version
= AnyP::ProtocolVersion()
722 testResults(__LINE__
, input
, output
, expect
);
729 input
.append("A\n", 2);
730 struct resultSet expect
= {
733 .parserState
= Http1::HTTP_PARSE_DONE
,
734 .status
= Http::scBadRequest
,
735 .suffixSz
= input
.length(),
736 .method
= HttpRequestMethod(),
738 .version
= AnyP::ProtocolVersion()
741 testResults(__LINE__
, input
, output
, expect
);
746 input
.append("GET\n", 4);
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 // space padded method (SP is reserved so invalid as a method byte)
764 input
.append(" GET / HTTP/1.1\r\n", 17);
765 struct resultSet expect
= {
768 .parserState
= Http1::HTTP_PARSE_DONE
,
769 .status
= Http::scBadRequest
,
770 .suffixSz
= input
.length(),
771 .method
= HttpRequestMethod(),
773 .version
= AnyP::ProtocolVersion()
776 testResults(__LINE__
, input
, output
, expect
);
780 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
782 input
.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
783 Config
.onoff
.relaxed_header_parser
= 1;
784 struct resultSet expect
= {
787 .parserState
= Http1::HTTP_PARSE_MIME
,
788 .status
= Http::scOkay
,
790 .method
= HttpRequestMethod(Http::METHOD_GET
),
792 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
795 testResults(__LINE__
, input
, output
, expect
);
797 Config
.onoff
.relaxed_header_parser
= 0;
798 struct resultSet expectStrict
= {
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
, expectStrict
);
813 // forbidden character in method
815 input
.append("\tGET / HTTP/1.1\r\n", 17);
816 struct resultSet expect
= {
819 .parserState
= Http1::HTTP_PARSE_DONE
,
820 .status
= Http::scBadRequest
,
821 .suffixSz
= input
.length(),
822 .method
= HttpRequestMethod(),
824 .version
= AnyP::ProtocolVersion()
827 testResults(__LINE__
, input
, output
, expect
);
831 // CR in method delimiters
833 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
834 input
.append("GET\r / HTTP/1.1\r\n", 17);
835 Config
.onoff
.relaxed_header_parser
= 1;
836 struct resultSet expect
= {
839 .parserState
= Http1::HTTP_PARSE_MIME
,
840 .status
= Http::scOkay
,
842 .method
= HttpRequestMethod(Http::METHOD_GET
),
844 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
847 testResults(__LINE__
, input
, output
, expect
);
849 Config
.onoff
.relaxed_header_parser
= 0;
850 struct resultSet expectStrict
= {
853 .parserState
= Http1::HTTP_PARSE_DONE
,
854 .status
= Http::scBadRequest
,
855 .suffixSz
= input
.length(),
856 .method
= HttpRequestMethod(),
858 .version
= AnyP::ProtocolVersion()
861 testResults(__LINE__
, input
, output
, expectStrict
);
865 // tolerant parser delimiters
867 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
868 input
.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
869 Config
.onoff
.relaxed_header_parser
= 1;
870 struct resultSet expect
= {
873 .parserState
= Http1::HTTP_PARSE_MIME
,
874 .status
= Http::scOkay
,
876 .method
= HttpRequestMethod(Http::METHOD_GET
),
878 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
881 testResults(__LINE__
, input
, output
, expect
);
883 Config
.onoff
.relaxed_header_parser
= 0;
884 struct resultSet expectStrict
= {
887 .parserState
= Http1::HTTP_PARSE_DONE
,
888 .status
= Http::scBadRequest
,
889 .suffixSz
= input
.length(),
890 .method
= HttpRequestMethod(),
892 .version
= AnyP::ProtocolVersion()
895 testResults(__LINE__
, input
, output
, expectStrict
);
901 testHttp1Parser::testParseRequestLineInvalid()
903 // ensure MemPools etc exist
907 Http1::RequestParser output
;
909 // no method (or method delimiter)
911 // HTTP/0.9 requires method to be "GET"
912 input
.append("/ HTTP/1.0\n", 11);
913 struct resultSet expect
= {
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
, expect
);
928 // no method (with method delimiter)
930 input
.append(" / HTTP/1.0\n", 12);
931 struct resultSet expectStrict
= {
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
, expectStrict
);
946 // binary code after method (invalid)
948 input
.append("GET\x16 / 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 // binary code NUL! after method (always invalid)
966 input
.append("GET\0 / HTTP/1.1\r\n", 17);
967 struct resultSet expect
= {
970 .parserState
= Http1::HTTP_PARSE_DONE
,
971 .status
= Http::scBadRequest
,
972 .suffixSz
= input
.length(),
973 .method
= HttpRequestMethod(),
975 .version
= AnyP::ProtocolVersion()
978 testResults(__LINE__
, input
, output
, expect
);
982 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
983 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
985 input
.append("GET HTTP/1.1\r\n", 15);
986 Config
.onoff
.relaxed_header_parser
= 1;
987 struct resultSet expect
= {
990 .parserState
= Http1::HTTP_PARSE_DONE
,
991 .status
= Http::scBadRequest
,
992 .suffixSz
= input
.length(),
993 .method
= HttpRequestMethod(),
995 .version
= AnyP::ProtocolVersion()
998 testResults(__LINE__
, input
, output
, expect
);
1000 Config
.onoff
.relaxed_header_parser
= 0;
1001 struct resultSet expectStrict
= {
1004 .parserState
= Http1::HTTP_PARSE_DONE
,
1005 .status
= Http::scBadRequest
,
1006 .suffixSz
= input
.length(),
1007 .method
= HttpRequestMethod(),
1009 .version
= AnyP::ProtocolVersion()
1012 testResults(__LINE__
, input
, output
, expectStrict
);
1016 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
1017 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
1019 input
.append("GET HTTP/1.1\r\n", 14);
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
);
1037 input
.append("\xB\xC\xE\xF\n", 5);
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
1055 input
.append("\t \t \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
);
1071 // mixed whitespace line with CR
1073 input
.append("\r \t \n", 6);
1074 struct resultSet expect
= {
1077 .parserState
= Http1::HTTP_PARSE_DONE
,
1078 .status
= Http::scBadRequest
,
1079 .suffixSz
= input
.length(),
1080 .method
= HttpRequestMethod(),
1082 .version
= AnyP::ProtocolVersion()
1085 testResults(__LINE__
, input
, output
, expect
);
1091 testHttp1Parser::testDripFeed()
1093 // Simulate a client drip-feeding Squid a few bytes at a time.
1094 // extend the size of the buffer from 0 bytes to full request length
1095 // calling the parser repeatedly as visible data grows.
1098 data
.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
1099 SBuf::size_type garbageEnd
= data
.length();
1100 data
.append("GET ", 4);
1101 data
.append("http://example.com/ ", 20);
1102 data
.append("HTTP/1.1\r\n", 10);
1103 SBuf::size_type reqLineEnd
= data
.length() - 1;
1104 data
.append("Host: example.com\r\n\r\n", 21);
1105 SBuf::size_type mimeEnd
= data
.length() - 1;
1106 data
.append("...", 3); // trailer to catch mime EOS errors.
1109 Http1::RequestParser hp
;
1111 // start with strict and move on to relaxed
1112 Config
.onoff
.relaxed_header_parser
= 2;
1114 Config
.maxRequestHeaderSize
= 1024; // large enough to hold the test data.
1118 // state of things we expect right now
1119 struct resultSet expect
= {
1122 .parserState
= Http1::HTTP_PARSE_NONE
,
1123 .status
= Http::scNone
,
1125 .method
= HttpRequestMethod(),
1127 .version
= AnyP::ProtocolVersion()
1130 ioBuf
.clear(); // begins empty for each parser type
1133 --Config
.onoff
.relaxed_header_parser
;
1135 for (SBuf::size_type pos
= 0; pos
<= data
.length(); ++pos
) {
1137 // simulate reading one more byte
1138 ioBuf
.append(data
.substr(pos
,1));
1140 // strict does not permit the garbage prefix
1141 if (pos
< garbageEnd
&& !Config
.onoff
.relaxed_header_parser
) {
1146 // when the garbage is passed we expect to start seeing first-line bytes
1147 if (pos
== garbageEnd
)
1148 expect
.parserState
= Http1::HTTP_PARSE_FIRST
;
1150 // all points after garbage start to see accumulated bytes looking for end of current section
1151 if (pos
>= garbageEnd
)
1152 expect
.suffixSz
= ioBuf
.length();
1154 // at end of request line expect to see method, URI, version details
1155 // and switch to seeking Mime header section
1156 if (pos
== reqLineEnd
) {
1157 expect
.parserState
= Http1::HTTP_PARSE_MIME
;
1158 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1159 expect
.status
= Http::scOkay
;
1160 expect
.method
= HttpRequestMethod(Http::METHOD_GET
);
1161 expect
.uri
= "http://example.com/";
1162 expect
.version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1);
1165 // one mime header is done we are expecting a new request
1166 // parse results say true and initial data is all gone from the buffer
1167 if (pos
== mimeEnd
) {
1168 expect
.parsed
= true;
1169 expect
.needsMore
= false;
1170 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1173 testResults(__LINE__
, ioBuf
, hp
, expect
);
1175 // sync the buffers like Squid does
1176 ioBuf
= hp
.remaining();
1178 // Squid stops using the parser once it has parsed the first message.
1179 if (!hp
.needsMoreData())
1183 } while (Config
.onoff
.relaxed_header_parser
);