]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
2 * Copyright (C) 1996-2015 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 "testHttp1Parser.h"
23 #include "unitTestMain.h"
25 CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser
);
28 testHttp1Parser::globalSetup()
30 static bool setup_done
= false;
37 // default to strict parser. set for loose parsing specifically where behaviour differs.
38 Config
.onoff
.relaxed_header_parser
= 0;
40 Config
.maxRequestHeaderSize
= 1024; // XXX: unit test the RequestParser handling of this limit
43 #if __cplusplus >= 201103L
48 Http1::ParseState parserState
;
49 Http::StatusCode status
;
50 SBuf::size_type suffixSz
;
51 HttpRequestMethod method
;
53 AnyP::ProtocolVersion version
;
56 // define SQUID_DEBUG_TESTS to see exactly which test sub-cases fail and where
57 #ifdef SQUID_DEBUG_TESTS
58 // not optimized for runtime use
60 Replace(SBuf
&where
, const SBuf
&what
, const SBuf
&with
)
62 // prevent infinite loops
63 if (!what
.length() || with
.find(what
) != SBuf::npos
)
66 SBuf::size_type pos
= 0;
67 while ((pos
= where
.find(what
, pos
)) != SBuf::npos
) {
68 SBuf buf
= where
.substr(0, pos
);
70 buf
.append(where
.substr(pos
+what
.length()));
76 static SBuf
Pretty(SBuf raw
)
78 Replace(raw
, SBuf("\r"), SBuf("\\r"));
79 Replace(raw
, SBuf("\n"), SBuf("\\n"));
85 testResults(int line
, const SBuf
&input
, Http1::RequestParser
&output
, struct resultSet
&expect
)
87 #ifdef SQUID_DEBUG_TESTS
88 std::cerr
<< "TEST @" << line
<< ", in=" << Pretty(input
) << "\n";
91 const bool parsed
= output
.parse(input
);
93 #ifdef SQUID_DEBUG_TESTS
94 if (expect
.parsed
!= parsed
)
95 std::cerr
<< "\tparse-FAILED: " << expect
.parsed
<< "!=" << parsed
<< "\n";
96 else if (parsed
&& expect
.method
!= output
.method_
)
97 std::cerr
<< "\tmethod-FAILED: " << expect
.method
<< "!=" << output
.method_
<< "\n";
98 if (expect
.status
!= output
.parseStatusCode
)
99 std::cerr
<< "\tscode-FAILED: " << expect
.status
<< "!=" << output
.parseStatusCode
<< "\n";
100 if (expect
.suffixSz
!= output
.buf_
.length())
101 std::cerr
<< "\tsuffixSz-FAILED: " << expect
.suffixSz
<< "!=" << output
.buf_
.length() << "\n";
105 CPPUNIT_ASSERT_EQUAL(expect
.parsed
, parsed
);
107 // if parsing was successful, check easily visible field outputs
109 CPPUNIT_ASSERT_EQUAL(expect
.method
, output
.method_
);
110 if (expect
.uri
!= NULL
)
111 CPPUNIT_ASSERT_EQUAL(0, output
.uri_
.cmp(expect
.uri
));
112 CPPUNIT_ASSERT_EQUAL(expect
.version
, output
.msgProtocol_
);
115 CPPUNIT_ASSERT_EQUAL(expect
.status
, output
.parseStatusCode
);
117 // check more obscure states
118 CPPUNIT_ASSERT_EQUAL(expect
.needsMore
, output
.needsMoreData());
119 if (output
.needsMoreData())
120 CPPUNIT_ASSERT_EQUAL(expect
.parserState
, output
.parsingStage_
);
121 CPPUNIT_ASSERT_EQUAL(expect
.suffixSz
, output
.buf_
.length());
123 #endif /* __cplusplus >= 200103L */
126 testHttp1Parser::testParserConstruct()
128 // whether the constructor works
130 Http1::RequestParser output
;
131 CPPUNIT_ASSERT_EQUAL(true, output
.needsMoreData());
132 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
.parsingStage_
);
133 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
.parseStatusCode
); // XXX: clear() not being called.
134 CPPUNIT_ASSERT(output
.buf_
.isEmpty());
135 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
.method_
);
136 CPPUNIT_ASSERT(output
.uri_
.isEmpty());
137 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
.msgProtocol_
);
140 // whether new() works
142 Http1::RequestParser
*output
= new Http1::RequestParser
;
143 CPPUNIT_ASSERT_EQUAL(true, output
->needsMoreData());
144 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE
, output
->parsingStage_
);
145 CPPUNIT_ASSERT_EQUAL(Http::scNone
, output
->parseStatusCode
);
146 CPPUNIT_ASSERT(output
->buf_
.isEmpty());
147 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE
), output
->method_
);
148 CPPUNIT_ASSERT(output
->uri_
.isEmpty());
149 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output
->msgProtocol_
);
154 #if __cplusplus >= 201103L
156 testHttp1Parser::testParseRequestLineProtocols()
158 // ensure MemPools etc exist
162 Http1::RequestParser output
;
164 // TEST: Do we comply with RFC 1945 section 5.1 ?
165 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
167 // RFC 1945 : HTTP/0.9 simple-request
169 input
.append("GET /\r\n", 7);
170 struct resultSet expect
= {
173 .parserState
= Http1::HTTP_PARSE_DONE
,
174 .status
= Http::scOkay
,
176 .method
= HttpRequestMethod(Http::METHOD_GET
),
178 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,0,9)
181 testResults(__LINE__
, input
, output
, expect
);
185 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
187 input
.append("POST /\r\n", 8);
188 struct resultSet expect
= {
191 .parserState
= Http1::HTTP_PARSE_DONE
,
192 .status
= Http::scBadRequest
,
193 .suffixSz
= input
.length(),
194 .method
= HttpRequestMethod(Http::METHOD_POST
),
196 .version
= AnyP::ProtocolVersion()
199 testResults(__LINE__
, input
, output
, expect
);
203 // RFC 1945 and 7230 : HTTP/1.0 request
205 input
.append("GET / HTTP/1.0\r\n", 16);
206 struct resultSet expect
= {
209 .parserState
= Http1::HTTP_PARSE_MIME
,
210 .status
= Http::scOkay
,
212 .method
= HttpRequestMethod(Http::METHOD_GET
),
214 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,0)
217 testResults(__LINE__
, input
, output
, expect
);
221 // RFC 7230 : HTTP/1.1 request
223 input
.append("GET / HTTP/1.1\r\n", 16);
224 struct resultSet expect
= {
227 .parserState
= Http1::HTTP_PARSE_MIME
,
228 .status
= Http::scOkay
,
230 .method
= HttpRequestMethod(Http::METHOD_GET
),
232 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
235 testResults(__LINE__
, input
, output
, expect
);
239 // RFC 7230 : future version full-request
241 input
.append("GET / HTTP/1.2\r\n", 16);
242 struct resultSet expect
= {
245 .parserState
= Http1::HTTP_PARSE_MIME
,
246 .status
= Http::scOkay
,
248 .method
= HttpRequestMethod(Http::METHOD_GET
),
250 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,2)
253 testResults(__LINE__
, input
, output
, expect
);
257 // RFC 7230 : future versions do not use request-line syntax
259 input
.append("GET / HTTP/2.0\r\n", 16);
260 struct resultSet expectA
= {
263 .parserState
= Http1::HTTP_PARSE_MIME
,
264 .status
= Http::scBadRequest
,
265 .suffixSz
= input
.length(),
266 .method
= HttpRequestMethod(),
268 .version
= AnyP::ProtocolVersion()
271 testResults(__LINE__
, input
, output
, expectA
);
274 input
.append("GET / HTTP/10.12\r\n", 18);
275 struct resultSet expectB
= {
278 .parserState
= Http1::HTTP_PARSE_MIME
,
279 .status
= Http::scBadRequest
,
280 .suffixSz
= input
.length(),
281 .method
= HttpRequestMethod(Http::METHOD_GET
),
283 .version
= AnyP::ProtocolVersion()
286 testResults(__LINE__
, input
, output
, expectB
);
290 // unknown non-HTTP protocol names
292 input
.append("GET / FOO/1.0\r\n", 15);
293 struct resultSet expect
= {
296 .parserState
= Http1::HTTP_PARSE_DONE
,
297 .status
= Http::scBadRequest
,
298 .suffixSz
= input
.length(),
299 .method
= HttpRequestMethod(Http::METHOD_GET
),
301 .version
= AnyP::ProtocolVersion()
304 testResults(__LINE__
, input
, output
, expect
);
310 input
.append("GET / HTTP/\r\n", 13);
311 struct resultSet expect
= {
314 .parserState
= Http1::HTTP_PARSE_DONE
,
315 .status
= Http::scBadRequest
,
316 .suffixSz
= input
.length(),
317 .method
= HttpRequestMethod(Http::METHOD_GET
),
319 .version
= AnyP::ProtocolVersion()
322 testResults(__LINE__
, input
, output
, expect
);
328 input
.append("GET / HTTP/.1\r\n", 15);
329 struct resultSet expect
= {
332 .parserState
= Http1::HTTP_PARSE_DONE
,
333 .status
= Http::scBadRequest
,
334 .suffixSz
= input
.length(),
335 .method
= HttpRequestMethod(Http::METHOD_GET
),
337 .version
= AnyP::ProtocolVersion()
340 testResults(__LINE__
, input
, output
, expect
);
346 input
.append("GET / HTTP/11\r\n", 15);
347 struct resultSet expect
= {
350 .parserState
= Http1::HTTP_PARSE_DONE
,
351 .status
= Http::scBadRequest
,
352 .suffixSz
= input
.length(),
353 .method
= HttpRequestMethod(Http::METHOD_GET
),
355 .version
= AnyP::ProtocolVersion()
358 testResults(__LINE__
, input
, output
, expect
);
362 // negative major version (bug 3062)
364 input
.append("GET / HTTP/-999999.1\r\n", 22);
365 struct resultSet expect
= {
368 .parserState
= Http1::HTTP_PARSE_DONE
,
369 .status
= Http::scBadRequest
,
370 .suffixSz
= input
.length(),
371 .method
= HttpRequestMethod(Http::METHOD_GET
),
373 .version
= AnyP::ProtocolVersion()
376 testResults(__LINE__
, input
, output
, expect
);
382 input
.append("GET / HTTP/1.\r\n", 15);
383 struct resultSet expect
= {
386 .parserState
= Http1::HTTP_PARSE_DONE
,
387 .status
= Http::scBadRequest
,
388 .suffixSz
= input
.length(),
389 .method
= HttpRequestMethod(Http::METHOD_GET
),
391 .version
= AnyP::ProtocolVersion()
394 testResults(__LINE__
, input
, output
, expect
);
398 // negative major version (bug 3062 corollary)
400 input
.append("GET / HTTP/1.-999999\r\n", 22);
401 struct resultSet expect
= {
404 .parserState
= Http1::HTTP_PARSE_DONE
,
405 .status
= Http::scBadRequest
,
406 .suffixSz
= input
.length(),
407 .method
= HttpRequestMethod(Http::METHOD_GET
),
409 .version
= AnyP::ProtocolVersion()
412 testResults(__LINE__
, input
, output
, expect
);
418 testHttp1Parser::testParseRequestLineStrange()
420 // ensure MemPools etc exist
424 Http1::RequestParser output
;
428 input
.append("GET / HTTP/1.1\r\n", 21);
429 // when being tolerant extra (sequential) SP delimiters are acceptable
430 Config
.onoff
.relaxed_header_parser
= 1;
431 struct resultSet expect
= {
434 .parserState
= Http1::HTTP_PARSE_MIME
,
435 .status
= Http::scOkay
,
437 .method
= HttpRequestMethod(Http::METHOD_GET
),
439 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
442 testResults(__LINE__
, input
, output
, expect
);
444 Config
.onoff
.relaxed_header_parser
= 0;
445 struct resultSet expectStrict
= {
448 .parserState
= Http1::HTTP_PARSE_DONE
,
449 .status
= Http::scBadRequest
,
450 .suffixSz
= input
.length(),
451 .method
= HttpRequestMethod(),
453 .version
= AnyP::ProtocolVersion()
456 testResults(__LINE__
, input
, output
, expectStrict
);
460 // whitespace inside URI. (nasty but happens)
462 input
.append("GET /fo o/ HTTP/1.1\r\n", 21);
463 Config
.onoff
.relaxed_header_parser
= 1;
464 struct resultSet expect
= {
467 .parserState
= Http1::HTTP_PARSE_MIME
,
468 .status
= Http::scOkay
,
470 .method
= HttpRequestMethod(Http::METHOD_GET
),
472 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
475 testResults(__LINE__
, input
, output
, expect
);
477 Config
.onoff
.relaxed_header_parser
= 0;
478 struct resultSet expectStrict
= {
481 .parserState
= Http1::HTTP_PARSE_DONE
,
482 .status
= Http::scBadRequest
,
483 .suffixSz
= input
.length(),
484 .method
= HttpRequestMethod(),
486 .version
= AnyP::ProtocolVersion()
489 testResults(__LINE__
, input
, output
, expectStrict
);
493 // additional data in buffer
495 input
.append("GET / HTTP/1.1\r\nboo!", 20);
496 struct resultSet expect
= {
499 .parserState
= Http1::HTTP_PARSE_MIME
,
500 .status
= Http::scOkay
,
501 .suffixSz
= 4, // strlen("boo!")
502 .method
= HttpRequestMethod(Http::METHOD_GET
),
504 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
507 testResults(__LINE__
, input
, output
, expect
);
509 Config
.onoff
.relaxed_header_parser
= 0;
514 testHttp1Parser::testParseRequestLineTerminators()
516 // ensure MemPools etc exist
520 Http1::RequestParser output
;
522 // alternative EOL sequence: NL-only
523 // RFC 7230 tolerance permits omitted CR
525 input
.append("GET / HTTP/1.1\n", 15);
526 Config
.onoff
.relaxed_header_parser
= 1;
527 struct resultSet expect
= {
530 .parserState
= Http1::HTTP_PARSE_MIME
,
531 .status
= Http::scOkay
,
533 .method
= HttpRequestMethod(Http::METHOD_GET
),
535 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
538 testResults(__LINE__
, input
, output
, expect
);
540 Config
.onoff
.relaxed_header_parser
= 0;
541 struct resultSet expectStrict
= {
544 .parserState
= Http1::HTTP_PARSE_DONE
,
545 .status
= Http::scBadRequest
,
546 .suffixSz
= input
.length(),
547 .method
= HttpRequestMethod(),
549 .version
= AnyP::ProtocolVersion()
552 testResults(__LINE__
, input
, output
, expectStrict
);
556 // alternative EOL sequence: double-NL-only
557 // RFC 7230 tolerance permits omitted CR
558 // NP: represents a request with no mime headers
560 input
.append("GET / HTTP/1.1\n\n", 16);
561 Config
.onoff
.relaxed_header_parser
= 1;
562 struct resultSet expect
= {
565 .parserState
= Http1::HTTP_PARSE_DONE
,
566 .status
= Http::scOkay
,
568 .method
= HttpRequestMethod(Http::METHOD_GET
),
570 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
573 testResults(__LINE__
, input
, output
, expect
);
575 Config
.onoff
.relaxed_header_parser
= 0;
576 struct resultSet expectStrict
= {
579 .parserState
= Http1::HTTP_PARSE_DONE
,
580 .status
= Http::scBadRequest
,
581 .suffixSz
= input
.length(),
582 .method
= HttpRequestMethod(),
584 .version
= AnyP::ProtocolVersion()
587 testResults(__LINE__
, input
, output
, expectStrict
);
591 // space padded version
593 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
594 input
.append("GET / HTTP/1.1 \r\n", 17);
595 struct resultSet expect
= {
598 .parserState
= Http1::HTTP_PARSE_DONE
,
599 .status
= Http::scBadRequest
,
600 .suffixSz
= input
.length(),
601 .method
= HttpRequestMethod(),
603 .version
= AnyP::ProtocolVersion()
606 testResults(__LINE__
, input
, output
, expect
);
612 testHttp1Parser::testParseRequestLineMethods()
614 // ensure MemPools etc exist
618 Http1::RequestParser output
;
620 // RFC 7230 : dot method
622 input
.append(". / HTTP/1.1\r\n", 14);
623 struct resultSet expect
= {
626 .parserState
= Http1::HTTP_PARSE_MIME
,
627 .status
= Http::scOkay
,
629 .method
= HttpRequestMethod(SBuf(".")),
631 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
634 testResults(__LINE__
, input
, output
, expect
);
638 // RFC 7230 : special TCHAR method chars
640 input
.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
641 struct resultSet expect
= {
644 .parserState
= Http1::HTTP_PARSE_MIME
,
645 .status
= Http::scOkay
,
647 .method
= HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
649 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
652 testResults(__LINE__
, input
, output
, expect
);
656 // OPTIONS with * URL
658 input
.append("OPTIONS * HTTP/1.1\r\n", 20);
659 struct resultSet expect
= {
662 .parserState
= Http1::HTTP_PARSE_MIME
,
663 .status
= Http::scOkay
,
665 .method
= HttpRequestMethod(Http::METHOD_OPTIONS
),
667 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
670 testResults(__LINE__
, input
, output
, expect
);
676 input
.append("HELLOWORLD / HTTP/1.1\r\n", 23);
677 struct resultSet expect
= {
680 .parserState
= Http1::HTTP_PARSE_MIME
,
681 .status
= Http::scOkay
,
683 .method
= HttpRequestMethod(SBuf("HELLOWORLD")),
685 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
688 testResults(__LINE__
, input
, output
, expect
);
693 // too-long method (over 16 bytes)
695 input
.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
696 struct resultSet expect
= {
699 .parserState
= Http1::HTTP_PARSE_DONE
,
700 .status
= Http::scNotImplemented
,
701 .suffixSz
= input
.length(),
702 .method
= HttpRequestMethod(),
704 .version
= AnyP::ProtocolVersion()
707 testResults(__LINE__
, input
, output
, expect
);
714 input
.append("A\n", 2);
715 struct resultSet expect
= {
718 .parserState
= Http1::HTTP_PARSE_DONE
,
719 .status
= Http::scBadRequest
,
720 .suffixSz
= input
.length(),
721 .method
= HttpRequestMethod(),
723 .version
= AnyP::ProtocolVersion()
726 testResults(__LINE__
, input
, output
, expect
);
731 input
.append("GET\n", 4);
732 struct resultSet expect
= {
735 .parserState
= Http1::HTTP_PARSE_DONE
,
736 .status
= Http::scBadRequest
,
737 .suffixSz
= input
.length(),
738 .method
= HttpRequestMethod(),
740 .version
= AnyP::ProtocolVersion()
743 testResults(__LINE__
, input
, output
, expect
);
747 // space padded method (SP is reserved so invalid as a method byte)
749 input
.append(" GET / HTTP/1.1\r\n", 17);
750 struct resultSet expect
= {
753 .parserState
= Http1::HTTP_PARSE_DONE
,
754 .status
= Http::scBadRequest
,
755 .suffixSz
= input
.length(),
756 .method
= HttpRequestMethod(),
758 .version
= AnyP::ProtocolVersion()
761 testResults(__LINE__
, input
, output
, expect
);
765 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
767 input
.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
768 Config
.onoff
.relaxed_header_parser
= 1;
769 struct resultSet expect
= {
772 .parserState
= Http1::HTTP_PARSE_MIME
,
773 .status
= Http::scOkay
,
775 .method
= HttpRequestMethod(Http::METHOD_GET
),
777 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
780 testResults(__LINE__
, input
, output
, expect
);
782 Config
.onoff
.relaxed_header_parser
= 0;
783 struct resultSet expectStrict
= {
786 .parserState
= Http1::HTTP_PARSE_DONE
,
787 .status
= Http::scBadRequest
,
788 .suffixSz
= input
.length(),
789 .method
= HttpRequestMethod(),
791 .version
= AnyP::ProtocolVersion()
794 testResults(__LINE__
, input
, output
, expectStrict
);
798 // forbidden character in method
800 input
.append("\tGET / HTTP/1.1\r\n", 17);
801 struct resultSet expect
= {
804 .parserState
= Http1::HTTP_PARSE_DONE
,
805 .status
= Http::scBadRequest
,
806 .suffixSz
= input
.length(),
807 .method
= HttpRequestMethod(),
809 .version
= AnyP::ProtocolVersion()
812 testResults(__LINE__
, input
, output
, expect
);
816 // CR in method delimiters
818 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
819 input
.append("GET\r / HTTP/1.1\r\n", 17);
820 Config
.onoff
.relaxed_header_parser
= 1;
821 struct resultSet expect
= {
824 .parserState
= Http1::HTTP_PARSE_MIME
,
825 .status
= Http::scOkay
,
827 .method
= HttpRequestMethod(Http::METHOD_GET
),
829 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
832 testResults(__LINE__
, input
, output
, expect
);
834 Config
.onoff
.relaxed_header_parser
= 0;
835 struct resultSet expectStrict
= {
838 .parserState
= Http1::HTTP_PARSE_DONE
,
839 .status
= Http::scBadRequest
,
840 .suffixSz
= input
.length(),
841 .method
= HttpRequestMethod(),
843 .version
= AnyP::ProtocolVersion()
846 testResults(__LINE__
, input
, output
, expectStrict
);
850 // tolerant parser delimiters
852 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
853 input
.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
854 Config
.onoff
.relaxed_header_parser
= 1;
855 struct resultSet expect
= {
858 .parserState
= Http1::HTTP_PARSE_MIME
,
859 .status
= Http::scOkay
,
861 .method
= HttpRequestMethod(Http::METHOD_GET
),
863 .version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1)
866 testResults(__LINE__
, input
, output
, expect
);
868 Config
.onoff
.relaxed_header_parser
= 0;
869 struct resultSet expectStrict
= {
872 .parserState
= Http1::HTTP_PARSE_DONE
,
873 .status
= Http::scBadRequest
,
874 .suffixSz
= input
.length(),
875 .method
= HttpRequestMethod(),
877 .version
= AnyP::ProtocolVersion()
880 testResults(__LINE__
, input
, output
, expectStrict
);
886 testHttp1Parser::testParseRequestLineInvalid()
888 // ensure MemPools etc exist
892 Http1::RequestParser output
;
894 // no method (or method delimiter)
896 // HTTP/0.9 requires method to be "GET"
897 input
.append("/ HTTP/1.0\n", 11);
898 struct resultSet expect
= {
901 .parserState
= Http1::HTTP_PARSE_DONE
,
902 .status
= Http::scBadRequest
,
903 .suffixSz
= input
.length(),
904 .method
= HttpRequestMethod(),
906 .version
= AnyP::ProtocolVersion()
909 testResults(__LINE__
, input
, output
, expect
);
913 // no method (with method delimiter)
915 input
.append(" / HTTP/1.0\n", 12);
916 struct resultSet expectStrict
= {
919 .parserState
= Http1::HTTP_PARSE_DONE
,
920 .status
= Http::scBadRequest
,
921 .suffixSz
= input
.length(),
922 .method
= HttpRequestMethod(),
924 .version
= AnyP::ProtocolVersion()
927 testResults(__LINE__
, input
, output
, expectStrict
);
931 // binary code after method (invalid)
933 input
.append("GET\x16 / HTTP/1.1\r\n", 17);
934 struct resultSet expect
= {
937 .parserState
= Http1::HTTP_PARSE_DONE
,
938 .status
= Http::scBadRequest
,
939 .suffixSz
= input
.length(),
940 .method
= HttpRequestMethod(),
942 .version
= AnyP::ProtocolVersion()
945 testResults(__LINE__
, input
, output
, expect
);
949 // binary code NUL! after method (always invalid)
951 input
.append("GET\0 / HTTP/1.1\r\n", 17);
952 struct resultSet expect
= {
955 .parserState
= Http1::HTTP_PARSE_DONE
,
956 .status
= Http::scBadRequest
,
957 .suffixSz
= input
.length(),
958 .method
= HttpRequestMethod(),
960 .version
= AnyP::ProtocolVersion()
963 testResults(__LINE__
, input
, output
, expect
);
967 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
968 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
970 input
.append("GET HTTP/1.1\r\n", 15);
971 Config
.onoff
.relaxed_header_parser
= 1;
972 struct resultSet expect
= {
975 .parserState
= Http1::HTTP_PARSE_DONE
,
976 .status
= Http::scBadRequest
,
977 .suffixSz
= input
.length(),
978 .method
= HttpRequestMethod(),
980 .version
= AnyP::ProtocolVersion()
983 testResults(__LINE__
, input
, output
, expect
);
985 Config
.onoff
.relaxed_header_parser
= 0;
986 struct resultSet expectStrict
= {
989 .parserState
= Http1::HTTP_PARSE_DONE
,
990 .status
= Http::scBadRequest
,
991 .suffixSz
= input
.length(),
992 .method
= HttpRequestMethod(),
994 .version
= AnyP::ProtocolVersion()
997 testResults(__LINE__
, input
, output
, expectStrict
);
1001 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
1002 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
1004 input
.append("GET HTTP/1.1\r\n", 14);
1005 struct resultSet expect
= {
1008 .parserState
= Http1::HTTP_PARSE_DONE
,
1009 .status
= Http::scBadRequest
,
1010 .suffixSz
= input
.length(),
1011 .method
= HttpRequestMethod(),
1013 .version
= AnyP::ProtocolVersion()
1016 testResults(__LINE__
, input
, output
, expect
);
1022 input
.append("\xB\xC\xE\xF\n", 5);
1023 struct resultSet expect
= {
1026 .parserState
= Http1::HTTP_PARSE_DONE
,
1027 .status
= Http::scBadRequest
,
1028 .suffixSz
= input
.length(),
1029 .method
= HttpRequestMethod(),
1031 .version
= AnyP::ProtocolVersion()
1034 testResults(__LINE__
, input
, output
, expect
);
1038 // mixed whitespace line
1040 input
.append("\t \t \t\n", 6);
1041 struct resultSet expect
= {
1044 .parserState
= Http1::HTTP_PARSE_DONE
,
1045 .status
= Http::scBadRequest
,
1046 .suffixSz
= input
.length(),
1047 .method
= HttpRequestMethod(),
1049 .version
= AnyP::ProtocolVersion()
1052 testResults(__LINE__
, input
, output
, expect
);
1056 // mixed whitespace line with CR
1058 input
.append("\r \t \n", 6);
1059 struct resultSet expect
= {
1062 .parserState
= Http1::HTTP_PARSE_DONE
,
1063 .status
= Http::scBadRequest
,
1064 .suffixSz
= input
.length(),
1065 .method
= HttpRequestMethod(),
1067 .version
= AnyP::ProtocolVersion()
1070 testResults(__LINE__
, input
, output
, expect
);
1076 testHttp1Parser::testDripFeed()
1078 // Simulate a client drip-feeding Squid a few bytes at a time.
1079 // extend the size of the buffer from 0 bytes to full request length
1080 // calling the parser repeatedly as visible data grows.
1083 data
.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
1084 SBuf::size_type garbageEnd
= data
.length();
1085 data
.append("GET ", 4);
1086 data
.append("http://example.com/ ", 20);
1087 data
.append("HTTP/1.1\r\n", 10);
1088 SBuf::size_type reqLineEnd
= data
.length() - 1;
1089 data
.append("Host: example.com\r\n\r\n", 21);
1090 SBuf::size_type mimeEnd
= data
.length() - 1;
1091 data
.append("...", 3); // trailer to catch mime EOS errors.
1094 Http1::RequestParser hp
;
1096 // start with strict and move on to relaxed
1097 Config
.onoff
.relaxed_header_parser
= 2;
1099 Config
.maxRequestHeaderSize
= 1024; // large enough to hold the test data.
1103 // state of things we expect right now
1104 struct resultSet expect
= {
1107 .parserState
= Http1::HTTP_PARSE_NONE
,
1108 .status
= Http::scNone
,
1110 .method
= HttpRequestMethod(),
1112 .version
= AnyP::ProtocolVersion()
1115 ioBuf
.clear(); // begins empty for each parser type
1118 --Config
.onoff
.relaxed_header_parser
;
1120 for (SBuf::size_type pos
= 0; pos
<= data
.length(); ++pos
) {
1122 // simulate reading one more byte
1123 ioBuf
.append(data
.substr(pos
,1));
1125 // strict does not permit the garbage prefix
1126 if (pos
< garbageEnd
&& !Config
.onoff
.relaxed_header_parser
) {
1131 // when the garbage is passed we expect to start seeing first-line bytes
1132 if (pos
== garbageEnd
)
1133 expect
.parserState
= Http1::HTTP_PARSE_FIRST
;
1135 // all points after garbage start to see accumulated bytes looking for end of current section
1136 if (pos
>= garbageEnd
)
1137 expect
.suffixSz
= ioBuf
.length();
1139 // at end of request line expect to see method, URI, version details
1140 // and switch to seeking Mime header section
1141 if (pos
== reqLineEnd
) {
1142 expect
.parserState
= Http1::HTTP_PARSE_MIME
;
1143 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1144 expect
.status
= Http::scOkay
;
1145 expect
.method
= HttpRequestMethod(Http::METHOD_GET
);
1146 expect
.uri
= "http://example.com/";
1147 expect
.version
= AnyP::ProtocolVersion(AnyP::PROTO_HTTP
,1,1);
1150 // one mime header is done we are expecting a new request
1151 // parse results say true and initial data is all gone from the buffer
1152 if (pos
== mimeEnd
) {
1153 expect
.parsed
= true;
1154 expect
.needsMore
= false;
1155 expect
.suffixSz
= 0; // and a checkpoint buffer reset
1158 testResults(__LINE__
, ioBuf
, hp
, expect
);
1160 // sync the buffers like Squid does
1161 ioBuf
= hp
.remaining();
1163 // Squid stops using the parser once it has parsed the first message.
1164 if (!hp
.needsMoreData())
1168 } while (Config
.onoff
.relaxed_header_parser
);
1171 #endif /* __cplusplus >= 201103L */