]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
Merged from trunk rev.13445
[thirdparty/squid.git] / src / tests / testHttp1Parser.cc
1 #define SQUID_UNIT_TEST 1
2 #include "squid.h"
3
4 #include <cppunit/TestAssert.h>
5
6 #define private public
7 #define protected public
8
9 #include "testHttp1Parser.h"
10 #include "http/one/RequestParser.h"
11 #include "http/RequestMethod.h"
12 #include "Mem.h"
13 #include "MemBuf.h"
14 #include "SquidConfig.h"
15 #include "testHttp1Parser.h"
16
17 CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser );
18
19 void
20 testHttp1Parser::globalSetup()
21 {
22 static bool setup_done = false;
23 if (setup_done)
24 return;
25
26 Mem::Init();
27 setup_done = true;
28
29 // default to strict parser. set for loose parsing specifically where behaviour differs.
30 Config.onoff.relaxed_header_parser = 0;
31
32 Config.maxRequestHeaderSize = 1024; // XXX: unit test the RequestParser handling of this limit
33 }
34
35 struct resultSet {
36 bool parsed;
37 bool needsMore;
38 Http1::ParseState parserState;
39 Http::StatusCode status;
40 int msgStart;
41 int msgEnd;
42 SBuf::size_type suffixSz;
43 int methodStart;
44 int methodEnd;
45 HttpRequestMethod method;
46 int uriStart;
47 int uriEnd;
48 const char *uri;
49 int versionStart;
50 int versionEnd;
51 AnyP::ProtocolVersion version;
52 };
53
54 static void
55 testResults(int line, const SBuf &input, Http1::RequestParser &output, struct resultSet &expect)
56 {
57 #if WHEN_TEST_DEBUG_IS_NEEDED
58 printf("TEST @%d, in=%u: " SQUIDSBUFPH "\n", line, input.length(), SQUIDSBUFPRINT(input));
59 #endif
60
61 CPPUNIT_ASSERT_EQUAL(expect.parsed, output.parse(input));
62 CPPUNIT_ASSERT_EQUAL(expect.needsMore, output.needsMoreData());
63 if (output.needsMoreData())
64 CPPUNIT_ASSERT_EQUAL(expect.parserState, output.parsingStage_);
65 CPPUNIT_ASSERT_EQUAL(expect.status, output.request_parse_status);
66 CPPUNIT_ASSERT_EQUAL(expect.msgStart, output.req.start);
67 CPPUNIT_ASSERT_EQUAL(expect.msgEnd, output.req.end);
68 CPPUNIT_ASSERT_EQUAL(expect.suffixSz, output.buf_.length());
69 CPPUNIT_ASSERT_EQUAL(expect.methodStart, output.req.m_start);
70 CPPUNIT_ASSERT_EQUAL(expect.methodEnd, output.req.m_end);
71 CPPUNIT_ASSERT_EQUAL(expect.method, output.method_);
72 CPPUNIT_ASSERT_EQUAL(expect.uriStart, output.req.u_start);
73 CPPUNIT_ASSERT_EQUAL(expect.uriEnd, output.req.u_end);
74 if (expect.uri != NULL)
75 CPPUNIT_ASSERT_EQUAL(0, output.uri_.cmp(expect.uri));
76 CPPUNIT_ASSERT_EQUAL(expect.versionStart, output.req.v_start);
77 CPPUNIT_ASSERT_EQUAL(expect.versionEnd, output.req.v_end);
78 CPPUNIT_ASSERT_EQUAL(expect.version, output.msgProtocol_);
79 }
80
81 void
82 testHttp1Parser::testParserConstruct()
83 {
84 // whether the constructor works
85 {
86 Http1::RequestParser output;
87 CPPUNIT_ASSERT_EQUAL(true, output.needsMoreData());
88 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output.parsingStage_);
89 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status); // XXX: clear() not being called.
90 CPPUNIT_ASSERT_EQUAL(-1, output.req.start);
91 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
92 CPPUNIT_ASSERT(output.buf_.isEmpty());
93 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
94 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
95 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output.method_);
96 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
97 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
98 CPPUNIT_ASSERT(output.uri_.isEmpty());
99 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
100 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
101 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
102 }
103
104 // whether new() works
105 {
106 Http1::RequestParser *output = new Http1::RequestParser;
107 CPPUNIT_ASSERT_EQUAL(true, output->needsMoreData());
108 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output->parsingStage_);
109 CPPUNIT_ASSERT_EQUAL(Http::scNone, output->request_parse_status);
110 CPPUNIT_ASSERT_EQUAL(-1, output->req.start);
111 CPPUNIT_ASSERT_EQUAL(-1, output->req.end);
112 CPPUNIT_ASSERT(output->buf_.isEmpty());
113 CPPUNIT_ASSERT_EQUAL(-1, output->req.m_start);
114 CPPUNIT_ASSERT_EQUAL(-1, output->req.m_end);
115 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output->method_);
116 CPPUNIT_ASSERT_EQUAL(-1, output->req.u_start);
117 CPPUNIT_ASSERT_EQUAL(-1, output->req.u_end);
118 CPPUNIT_ASSERT(output->uri_.isEmpty());
119 CPPUNIT_ASSERT_EQUAL(-1, output->req.v_start);
120 CPPUNIT_ASSERT_EQUAL(-1, output->req.v_end);
121 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output->msgProtocol_);
122 delete output;
123 }
124 }
125
126 void
127 testHttp1Parser::testParseRequestLineProtocols()
128 {
129 // ensure MemPools etc exist
130 globalSetup();
131
132 SBuf input;
133 Http1::RequestParser output;
134
135 // TEST: Do we comply with RFC 1945 section 5.1 ?
136 // TEST: Do we comply with RFC 2616 section 5.1 ?
137
138 // RFC 1945 : HTTP/0.9 simple-request
139 {
140 input.append("GET /\r\n", 7);
141 struct resultSet expect = {
142 .parsed = true,
143 .needsMore = false,
144 .parserState = Http1::HTTP_PARSE_DONE,
145 .status = Http::scOkay,
146 .msgStart = 0,
147 .msgEnd = (int)input.length()-1,
148 .suffixSz = 0,
149 .methodStart = 0,
150 .methodEnd = 2,
151 .method = HttpRequestMethod(Http::METHOD_GET),
152 .uriStart = 4,
153 .uriEnd = 4,
154 .uri = "/",
155 .versionStart = -1,
156 .versionEnd = -1,
157 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
158 };
159 output.clear();
160 testResults(__LINE__, input, output, expect);
161 input.clear();
162 }
163
164 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
165 #if WHEN_RFC_COMPLIANT
166 {
167 input.append("POST /\r\n", 7);
168 struct resultSet expect = {
169 .parsed = true,
170 .needsMore = false,
171 .parserState = Http1::HTTP_PARSE_DONE,
172 .status = Http::scOkay,
173 .msgStart = 0,
174 .msgEnd = (int)input.length()-1,
175 .suffixSz = 0,
176 .methodStart = 0,
177 .methodEnd = 3,
178 .method = HttpRequestMethod(Http::METHOD_POST),
179 .uriStart = 5,
180 .uriEnd = 5,
181 .uri = "/",
182 .versionStart = -1,
183 .versionEnd = -1,
184 .version = AnyP::ProtocolVersion()
185 };
186 output.clear();
187 testResults(__LINE__, input, output, expect);
188 input.clear();
189 }
190 #endif
191 // RFC 1945 and 2616 : HTTP/1.0 request
192 {
193 input.append("GET / HTTP/1.0\r\n", 16);
194 struct resultSet expect = {
195 .parsed = false,
196 .needsMore = true,
197 .parserState = Http1::HTTP_PARSE_MIME,
198 .status = Http::scOkay,
199 .msgStart = 0,
200 .msgEnd = (int)input.length()-1,
201 .suffixSz = 0,
202 .methodStart = 0,
203 .methodEnd = 2,
204 .method = HttpRequestMethod(Http::METHOD_GET),
205 .uriStart = 4,
206 .uriEnd = 4,
207 .uri = "/",
208 .versionStart = 6,
209 .versionEnd = 13,
210 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0)
211 };
212 output.clear();
213 testResults(__LINE__, input, output, expect);
214 input.clear();
215 }
216
217 // RFC 2616 : HTTP/1.1 request
218 {
219 input.append("GET / HTTP/1.1\r\n", 16);
220 struct resultSet expect = {
221 .parsed = false,
222 .needsMore = true,
223 .parserState = Http1::HTTP_PARSE_MIME,
224 .status = Http::scOkay,
225 .msgStart = 0,
226 .msgEnd = (int)input.length()-1,
227 .suffixSz = 0,
228 .methodStart = 0,
229 .methodEnd = 2,
230 .method = HttpRequestMethod(Http::METHOD_GET),
231 .uriStart = 4,
232 .uriEnd = 4,
233 .uri = "/",
234 .versionStart = 6,
235 .versionEnd = 13,
236 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
237 };
238 output.clear();
239 testResults(__LINE__, input, output, expect);
240 input.clear();
241 }
242
243 // RFC 2616 : future version full-request
244 {
245 input.append("GET / HTTP/1.2\r\n", 16);
246 struct resultSet expect = {
247 .parsed = false,
248 .needsMore = true,
249 .parserState = Http1::HTTP_PARSE_MIME,
250 .status = Http::scOkay,
251 .msgStart = 0,
252 .msgEnd = (int)input.length()-1,
253 .suffixSz = 0,
254 .methodStart = 0,
255 .methodEnd = 2,
256 .method = HttpRequestMethod(Http::METHOD_GET),
257 .uriStart = 4,
258 .uriEnd = 4,
259 .uri = "/",
260 .versionStart = 6,
261 .versionEnd = 13,
262 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2)
263 };
264 output.clear();
265 testResults(__LINE__, input, output, expect);
266 input.clear();
267 }
268
269 // RFC 7230 : future versions do not use request-line syntax
270 {
271 input.append("GET / HTTP/10.12\r\n", 18);
272 struct resultSet expect = {
273 .parsed = false,
274 .needsMore = false,
275 .parserState = Http1::HTTP_PARSE_MIME,
276 .status = Http::scHttpVersionNotSupported,
277 .msgStart = 0,
278 .msgEnd = (int)input.length()-1,
279 .suffixSz = input.length(),
280 .methodStart = 0,
281 .methodEnd = 2,
282 .method = HttpRequestMethod(Http::METHOD_GET),
283 .uriStart = 4,
284 .uriEnd = 4,
285 .uri = "/",
286 .versionStart = 6,
287 .versionEnd = 15,
288 .version = AnyP::ProtocolVersion()
289 };
290 output.clear();
291 testResults(__LINE__, input, output, expect);
292 input.clear();
293 }
294
295 // unknown non-HTTP protocol names
296 {
297 input.append("GET / FOO/1.0\n", 14);
298 struct resultSet expect = {
299 .parsed = false,
300 .needsMore = false,
301 .parserState = Http1::HTTP_PARSE_DONE,
302 .status = Http::scHttpVersionNotSupported,
303 .msgStart = 0,
304 .msgEnd = (int)input.length()-1,
305 .suffixSz = input.length(),
306 .methodStart = 0,
307 .methodEnd = 2,
308 .method = HttpRequestMethod(Http::METHOD_GET),
309 .uriStart = 4,
310 .uriEnd = 4,
311 .uri = "/",
312 .versionStart = 6,
313 .versionEnd = 12,
314 .version = AnyP::ProtocolVersion()
315 };
316 output.clear();
317 testResults(__LINE__, input, output, expect);
318 input.clear();
319 }
320
321 // no version
322 {
323 input.append("GET / HTTP/\n", 12);
324 struct resultSet expect = {
325 .parsed = false,
326 .needsMore = false,
327 .parserState = Http1::HTTP_PARSE_DONE,
328 .status = Http::scHttpVersionNotSupported,
329 .msgStart = 0,
330 .msgEnd = (int)input.length()-1,
331 .suffixSz = input.length(),
332 .methodStart = 0,
333 .methodEnd = 2,
334 .method = HttpRequestMethod(Http::METHOD_GET),
335 .uriStart = 4,
336 .uriEnd = 4,
337 .uri = "/",
338 .versionStart = 6,
339 .versionEnd = 10,
340 .version = AnyP::ProtocolVersion()
341 };
342 output.clear();
343 testResults(__LINE__, input, output, expect);
344 input.clear();
345 }
346
347 // no major version
348 {
349 input.append("GET / HTTP/.1\n", 14);
350 struct resultSet expect = {
351 .parsed = false,
352 .needsMore = false,
353 .parserState = Http1::HTTP_PARSE_DONE,
354 .status = Http::scHttpVersionNotSupported,
355 .msgStart = 0,
356 .msgEnd = (int)input.length()-1,
357 .suffixSz = input.length(),
358 .methodStart = 0,
359 .methodEnd = 2,
360 .method = HttpRequestMethod(Http::METHOD_GET),
361 .uriStart = 4,
362 .uriEnd = 4,
363 .uri = "/",
364 .versionStart = 6,
365 .versionEnd = 12,
366 .version = AnyP::ProtocolVersion()
367 };
368 output.clear();
369 testResults(__LINE__, input, output, expect);
370 input.clear();
371 }
372
373 // no version dot
374 {
375 input.append("GET / HTTP/11\n", 14);
376 struct resultSet expect = {
377 .parsed = false,
378 .needsMore = false,
379 .parserState = Http1::HTTP_PARSE_DONE,
380 .status = Http::scHttpVersionNotSupported,
381 .msgStart = 0,
382 .msgEnd = (int)input.length()-1,
383 .suffixSz = input.length(),
384 .methodStart = 0,
385 .methodEnd = 2,
386 .method = HttpRequestMethod(Http::METHOD_GET),
387 .uriStart = 4,
388 .uriEnd = 4,
389 .uri = "/",
390 .versionStart = 6,
391 .versionEnd = 12,
392 .version = AnyP::ProtocolVersion()
393 };
394 output.clear();
395 testResults(__LINE__, input, output, expect);
396 input.clear();
397 }
398
399 // negative major version (bug 3062)
400 {
401 input.append("GET / HTTP/-999999.1\n", 21);
402 struct resultSet expect = {
403 .parsed = false,
404 .needsMore = false,
405 .parserState = Http1::HTTP_PARSE_DONE,
406 .status = Http::scHttpVersionNotSupported,
407 .msgStart = 0,
408 .msgEnd = (int)input.length()-1,
409 .suffixSz = input.length(),
410 .methodStart = 0,
411 .methodEnd = 2,
412 .method = HttpRequestMethod(Http::METHOD_GET),
413 .uriStart = 4,
414 .uriEnd = 4,
415 .uri = "/",
416 .versionStart = 6,
417 .versionEnd = 19,
418 .version = AnyP::ProtocolVersion()
419 };
420 output.clear();
421 testResults(__LINE__, input, output, expect);
422 input.clear();
423 }
424
425 // no minor version
426 {
427 input.append("GET / HTTP/1.\n", 14);
428 struct resultSet expect = {
429 .parsed = false,
430 .needsMore = false,
431 .parserState = Http1::HTTP_PARSE_DONE,
432 .status = Http::scHttpVersionNotSupported,
433 .msgStart = 0,
434 .msgEnd = (int)input.length()-1,
435 .suffixSz = input.length(),
436 .methodStart = 0,
437 .methodEnd = 2,
438 .method = HttpRequestMethod(Http::METHOD_GET),
439 .uriStart = 4,
440 .uriEnd = 4,
441 .uri = "/",
442 .versionStart = 6,
443 .versionEnd = 12,
444 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0)
445 };
446 output.clear();
447 testResults(__LINE__, input, output, expect);
448 input.clear();
449 }
450
451 // negative major version (bug 3062 corollary)
452 {
453 input.append("GET / HTTP/1.-999999\n", 21);
454 struct resultSet expect = {
455 .parsed = false,
456 .needsMore = false,
457 .parserState = Http1::HTTP_PARSE_DONE,
458 .status = Http::scHttpVersionNotSupported,
459 .msgStart = 0,
460 .msgEnd = (int)input.length()-1,
461 .suffixSz = input.length(),
462 .methodStart = 0,
463 .methodEnd = 2,
464 .method = HttpRequestMethod(Http::METHOD_GET),
465 .uriStart = 4,
466 .uriEnd = 4,
467 .uri = "/",
468 .versionStart = 6,
469 .versionEnd = 19,
470 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0)
471 };
472 output.clear();
473 testResults(__LINE__, input, output, expect);
474 input.clear();
475 }
476 }
477
478 void
479 testHttp1Parser::testParseRequestLineStrange()
480 {
481 // ensure MemPools etc exist
482 globalSetup();
483
484 SBuf input;
485 Http1::RequestParser output;
486
487 // space padded URL
488 {
489 input.append("GET / HTTP/1.1\r\n", 21);
490 struct resultSet expect = {
491 .parsed = false,
492 .needsMore = true,
493 .parserState = Http1::HTTP_PARSE_MIME,
494 .status = Http::scOkay,
495 .msgStart = 0,
496 .msgEnd = (int)input.length()-1,
497 .suffixSz = 0,
498 .methodStart = 0,
499 .methodEnd = 2,
500 .method = HttpRequestMethod(Http::METHOD_GET),
501 .uriStart = 5,
502 .uriEnd = 5,
503 .uri = "/",
504 .versionStart = 11,
505 .versionEnd = 18,
506 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
507 };
508 output.clear();
509 testResults(__LINE__, input, output, expect);
510 input.clear();
511 }
512
513 // whitespace inside URI. (nasty but happens)
514 // XXX: depends on tolerant parser...
515 {
516 input.append("GET /fo o/ HTTP/1.1\n", 20);
517 struct resultSet expect = {
518 .parsed = false,
519 .needsMore = true,
520 .parserState = Http1::HTTP_PARSE_MIME,
521 .status = Http::scOkay,
522 .msgStart = 0,
523 .msgEnd = (int)input.length()-1,
524 .suffixSz = 0,
525 .methodStart = 0,
526 .methodEnd = 2,
527 .method = HttpRequestMethod(Http::METHOD_GET),
528 .uriStart = 4,
529 .uriEnd = 9,
530 .uri = "/fo o/",
531 .versionStart = 11,
532 .versionEnd = 18,
533 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
534 };
535 output.clear();
536 testResults(__LINE__, input, output, expect);
537 input.clear();
538 }
539
540 // additional data in buffer
541 {
542 input.append("GET / HTTP/1.1\nboo!", 23);
543 struct resultSet expect = {
544 .parsed = false,
545 .needsMore = true,
546 .parserState = Http1::HTTP_PARSE_MIME,
547 .status = Http::scOkay,
548 .msgStart = 0,
549 .msgEnd = (int)input.length()-5,
550 .suffixSz = 4, // strlen("boo!")
551 .methodStart = 0,
552 .methodEnd = 2,
553 .method = HttpRequestMethod(Http::METHOD_GET),
554 .uriStart = 4,
555 .uriEnd = 4,
556 .uri = "/",
557 .versionStart = 10,
558 .versionEnd = 17,
559 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
560 };
561 output.clear();
562 testResults(__LINE__, input, output, expect);
563 input.clear();
564 }
565 }
566
567 void
568 testHttp1Parser::testParseRequestLineTerminators()
569 {
570 // ensure MemPools etc exist
571 globalSetup();
572
573 SBuf input;
574 Http1::RequestParser output;
575
576 // alternative EOL sequence: NL-only
577 {
578 input.append("GET / HTTP/1.1\n", 15);
579 struct resultSet expect = {
580 .parsed = false,
581 .needsMore = true,
582 .parserState = Http1::HTTP_PARSE_MIME,
583 .status = Http::scOkay,
584 .msgStart = 0,
585 .msgEnd = (int)input.length()-1,
586 .suffixSz = 0,
587 .methodStart = 0,
588 .methodEnd = 2,
589 .method = HttpRequestMethod(Http::METHOD_GET),
590 .uriStart = 4,
591 .uriEnd = 4,
592 .uri = "/",
593 .versionStart = 6,
594 .versionEnd = 13,
595 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
596 };
597 output.clear();
598 testResults(__LINE__, input, output, expect);
599 input.clear();
600 }
601
602 // alternative EOL sequence: double-NL-only
603 {
604 input.append("GET / HTTP/1.1\n\n", 16);
605 struct resultSet expect = {
606 .parsed = true,
607 .needsMore = false,
608 .parserState = Http1::HTTP_PARSE_DONE,
609 .status = Http::scOkay,
610 .msgStart = 0,
611 .msgEnd = (int)input.length()-2,
612 .suffixSz = 0,
613 .methodStart = 0,
614 .methodEnd = 2,
615 .method = HttpRequestMethod(Http::METHOD_GET),
616 .uriStart = 4,
617 .uriEnd = 4,
618 .uri = "/",
619 .versionStart = 6,
620 .versionEnd = 13,
621 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
622 };
623 output.clear();
624 testResults(__LINE__, input, output, expect);
625 input.clear();
626 }
627
628 // alternative EOL sequence: multi-CR-NL
629 {
630 input.append("GET / HTTP/1.1\r\r\r\n", 18);
631 // Being tolerant we can ignore and elide these apparently benign CR
632 Config.onoff.relaxed_header_parser = 1;
633 struct resultSet expectRelaxed = {
634 .parsed = false,
635 .needsMore = true,
636 .parserState = Http1::HTTP_PARSE_MIME,
637 .status = Http::scOkay,
638 .msgStart = 0,
639 .msgEnd = (int)input.length()-1,
640 .suffixSz = 0,
641 .methodStart = 0,
642 .methodEnd = 2,
643 .method = HttpRequestMethod(Http::METHOD_GET),
644 .uriStart = 4,
645 .uriEnd = 4,
646 .uri = "/",
647 .versionStart = 6,
648 .versionEnd = 13,
649 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
650 };
651 output.clear();
652 testResults(__LINE__, input, output, expectRelaxed);
653
654 // strict mode treats these as several bare-CR in the request line which is explicitly invalid.
655 Config.onoff.relaxed_header_parser = 0;
656 struct resultSet expectStrict = {
657 .parsed = false,
658 .needsMore = false,
659 .parserState = Http1::HTTP_PARSE_MIME,
660 .status = Http::scBadRequest,
661 .msgStart = 0,
662 .msgEnd = -1,
663 .suffixSz = input.length(),
664 .methodStart =-1,
665 .methodEnd = -1,
666 .method = HttpRequestMethod(),
667 .uriStart = -1,
668 .uriEnd = -1,
669 .uri = NULL,
670 .versionStart = -1,
671 .versionEnd = -1,
672 .version = AnyP::ProtocolVersion()
673 };
674 output.clear();
675 testResults(__LINE__, input, output, expectStrict);
676 input.clear();
677 }
678
679 // space padded version
680 {
681 // RFC 1945 and 2616 specify version is followed by CRLF. No intermediary bytes.
682 // NP: the terminal whitespace is a special case: invalid for even HTTP/0.9 with no version tag
683 input.append("GET / HTTP/1.1 \n", 16);
684 struct resultSet expect = {
685 .parsed = false,
686 .needsMore = false,
687 .parserState = Http1::HTTP_PARSE_DONE,
688 .status = Http::scBadRequest,
689 .msgStart = 0,
690 .msgEnd = (int)input.length()-1,
691 .suffixSz = input.length(),
692 .methodStart = 0,
693 .methodEnd = 2,
694 .method = HttpRequestMethod(Http::METHOD_GET),
695 .uriStart = 4,
696 .uriEnd = 13,
697 .uri = "/ HTTP/1.1",
698 .versionStart = -1,
699 .versionEnd = -1,
700 .version = AnyP::ProtocolVersion()
701 };
702 output.clear();
703 testResults(__LINE__, input, output, expect);
704 input.clear();
705 }
706 }
707
708 void
709 testHttp1Parser::testParseRequestLineMethods()
710 {
711 // ensure MemPools etc exist
712 globalSetup();
713
714 SBuf input;
715 Http1::RequestParser output;
716
717 // RFC 2616 : . method
718 {
719 input.append(". / HTTP/1.1\n", 13);
720 struct resultSet expect = {
721 .parsed = false,
722 .needsMore = true,
723 .parserState = Http1::HTTP_PARSE_MIME,
724 .status = Http::scOkay,
725 .msgStart = 0,
726 .msgEnd = (int)input.length()-1,
727 .suffixSz = 0,
728 .methodStart = 0,
729 .methodEnd = 0,
730 .method = HttpRequestMethod("."),
731 .uriStart = 2,
732 .uriEnd = 2,
733 .uri = "/",
734 .versionStart = 4,
735 .versionEnd = 11,
736 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
737 };
738 output.clear();
739 testResults(__LINE__, input, output, expect);
740 input.clear();
741 }
742
743 // OPTIONS with * URL
744 {
745 input.append("OPTIONS * HTTP/1.1\n", 19);
746 struct resultSet expect = {
747 .parsed = false,
748 .needsMore = true,
749 .parserState = Http1::HTTP_PARSE_MIME,
750 .status = Http::scOkay,
751 .msgStart = 0,
752 .msgEnd = (int)input.length()-1,
753 .suffixSz = 0,
754 .methodStart = 0,
755 .methodEnd = 6,
756 .method = HttpRequestMethod(Http::METHOD_OPTIONS),
757 .uriStart = 8,
758 .uriEnd = 8,
759 .uri = "*",
760 .versionStart = 10,
761 .versionEnd = 17,
762 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
763 };
764 output.clear();
765 testResults(__LINE__, input, output, expect);
766 input.clear();
767 }
768
769 // unknown method
770 {
771 input.append("HELLOWORLD / HTTP/1.1\n", 22);
772 struct resultSet expect = {
773 .parsed = false,
774 .needsMore = true,
775 .parserState = Http1::HTTP_PARSE_MIME,
776 .status = Http::scOkay,
777 .msgStart = 0,
778 .msgEnd = (int)input.length()-1,
779 .suffixSz = 0,
780 .methodStart = 0,
781 .methodEnd = 9,
782 .method = HttpRequestMethod("HELLOWORLD"),
783 .uriStart = 11,
784 .uriEnd = 11,
785 .uri = "/",
786 .versionStart = 13,
787 .versionEnd = 20,
788 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
789 };
790 output.clear();
791 testResults(__LINE__, input, output, expect);
792 input.clear();
793 }
794
795 // method-only
796 {
797 input.append("A\n", 2);
798 struct resultSet expect = {
799 .parsed = false,
800 .needsMore = false,
801 .parserState = Http1::HTTP_PARSE_DONE,
802 .status = Http::scBadRequest,
803 .msgStart = 0,
804 .msgEnd = (int)input.length()-1,
805 .suffixSz = input.length(),
806 .methodStart = 0,
807 .methodEnd = -1,
808 .method = HttpRequestMethod(),
809 .uriStart = -1,
810 .uriEnd = -1,
811 .uri = NULL,
812 .versionStart = -1,
813 .versionEnd = -1,
814 .version = AnyP::ProtocolVersion()
815 };
816 output.clear();
817 testResults(__LINE__, input, output, expect);
818 input.clear();
819 }
820
821 {
822 input.append("GET\n", 4);
823 struct resultSet expect = {
824 .parsed = false,
825 .needsMore = false,
826 .parserState = Http1::HTTP_PARSE_DONE,
827 .status = Http::scBadRequest,
828 .msgStart = 0,
829 .msgEnd = (int)input.length()-1,
830 .suffixSz = input.length(),
831 .methodStart = 0,
832 .methodEnd = -1,
833 .method = HttpRequestMethod(),
834 .uriStart = -1,
835 .uriEnd = -1,
836 .uri = NULL,
837 .versionStart = -1,
838 .versionEnd = -1,
839 .version = AnyP::ProtocolVersion()
840 };
841 output.clear();
842 testResults(__LINE__, input, output, expect);
843 input.clear();
844 }
845
846 // space padded method (in strict mode SP is reserved so invalid as a method byte)
847 {
848 input.append(" GET / HTTP/1.1\n", 16);
849 // RELAXED mode Squid custom tolerance ignores SP
850 #if USE_HTTP_VIOLATIONS
851 Config.onoff.relaxed_header_parser = 1;
852 struct resultSet expectRelaxed = {
853 .parsed = false,
854 .needsMore = true,
855 .parserState = Http1::HTTP_PARSE_MIME,
856 .status = Http::scOkay,
857 .msgStart = 0, // garbage collection consumes the SP
858 .msgEnd = (int)input.length()-2,
859 .suffixSz = 0,
860 .methodStart = 0,
861 .methodEnd = 2,
862 .method = HttpRequestMethod(Http::METHOD_GET),
863 .uriStart = 4,
864 .uriEnd = 4,
865 .uri = "/",
866 .versionStart = 6,
867 .versionEnd = 13,
868 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
869 };
870 output.clear();
871 testResults(__LINE__, input, output, expectRelaxed);
872 #endif
873
874 // STRICT mode obeys RFC syntax
875 Config.onoff.relaxed_header_parser = 0;
876 struct resultSet expectStrict = {
877 .parsed = false,
878 .needsMore = false,
879 .parserState = Http1::HTTP_PARSE_DONE,
880 .status = Http::scBadRequest,
881 .msgStart = 0,
882 .msgEnd = (int)input.length()-1,
883 .suffixSz = input.length(),
884 .methodStart = 0,
885 .methodEnd = -1,
886 .method = HttpRequestMethod(),
887 .uriStart = -1,
888 .uriEnd = -1,
889 .uri = NULL,
890 .versionStart = -1,
891 .versionEnd = -1,
892 .version = AnyP::ProtocolVersion()
893 };
894 output.clear();
895 testResults(__LINE__, input, output, expectStrict);
896 input.clear();
897 }
898
899 // RFC 2616 defined tolerance: ignore empty line(s) prefix on messages
900 #if WHEN_RFC_COMPLIANT
901 {
902 input.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
903 struct resultSet expect = {
904 .parsed = false,
905 .needsMore = false,
906 .parserState = Http1::HTTP_PARSE_MIME,
907 .status = Http::scOkay,
908 .msgStart = 5,
909 .msgEnd = (int)input.length()-1,
910 .suffixSz = 5,
911 .methodStart = 0,
912 .methodEnd = 2,
913 .method = HttpRequestMethod(Http::METHOD_GET),
914 .uriStart = 4,
915 .uriEnd = 4,
916 .uri = "/",
917 .versionStart = 6,
918 .versionEnd = 13,
919 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
920 };
921 output.clear();
922 testResults(__LINE__, input, output, expect);
923 input.clear();
924 }
925 #endif
926
927 // tab padded method (NP: tab is not SP so treated as any other binary)
928 {
929 input.append("\tGET / HTTP/1.1\n", 16);
930 #if WHEN_RFC_COMPLIANT
931 struct resultSet expect = {
932 .parsed = false,
933 .needsMore = false,
934 .parserState = Http1::HTTP_PARSE_DONE,
935 .status = Http::scBadRequest,
936 .msgStart = 0,
937 .msgEnd = (int)input.length()-1,
938 .suffixSz = input.length(),
939 .methodStart = -1,
940 .methodEnd = -1,
941 .method = HttpRequestMethod(),
942 .uriStart = -1,
943 .uriEnd = -1,
944 .uri = NULL,
945 .versionStart = -1,
946 .versionEnd = -1,
947 .version = AnyP::ProtocolVersion()
948 };
949 #else // XXX: currently broken
950 struct resultSet expect = {
951 .parsed = false,
952 .needsMore = true,
953 .parserState = Http1::HTTP_PARSE_MIME,
954 .status = Http::scOkay,
955 .msgStart = 0, // garbage collection consumes the SP
956 .msgEnd = (int)input.length()-1,
957 .suffixSz = 0,
958 .methodStart = 0,
959 .methodEnd = 3,
960 .method = HttpRequestMethod(SBuf("\tGET")),
961 .uriStart = 5,
962 .uriEnd = 5,
963 .uri = "/",
964 .versionStart = 7,
965 .versionEnd = 14,
966 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
967 };
968 #endif
969 output.clear();
970 testResults(__LINE__, input, output, expect);
971 input.clear();
972 }
973 }
974
975 void
976 testHttp1Parser::testParseRequestLineInvalid()
977 {
978 // ensure MemPools etc exist
979 globalSetup();
980
981 SBuf input;
982 Http1::RequestParser output;
983
984 // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
985 {
986 // XXX: HTTP/0.9 requires method to be "GET"
987 input.append("/ HTTP/1.0\n", 11);
988 struct resultSet expect = {
989 .parsed = true,
990 .needsMore = false,
991 .parserState = Http1::HTTP_PARSE_MIME,
992 .status = Http::scOkay,
993 .msgStart = 0,
994 .msgEnd = (int)input.length()-1,
995 .suffixSz = 0,
996 .methodStart = 0,
997 .methodEnd = 0,
998 .method = HttpRequestMethod("/"),
999 .uriStart = 2,
1000 .uriEnd = 9,
1001 .uri = "HTTP/1.0",
1002 .versionStart = -1,
1003 .versionEnd = -1,
1004 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
1005 };
1006 output.clear();
1007 testResults(__LINE__, input, output, expect);
1008 input.clear();
1009 }
1010
1011 // no method (an invalid format)
1012 {
1013 input.append(" / HTTP/1.0\n", 12);
1014
1015 // XXX: squid custom tolerance consumes initial SP.
1016 Config.onoff.relaxed_header_parser = 1;
1017 struct resultSet expectRelaxed = {
1018 .parsed = true,
1019 .needsMore = false,
1020 .parserState = Http1::HTTP_PARSE_MIME,
1021 .status = Http::scOkay,
1022 .msgStart = 0,
1023 .msgEnd = (int)input.length()-2,
1024 .suffixSz = 0,
1025 .methodStart = 0,
1026 .methodEnd = 0,
1027 .method = HttpRequestMethod("/"),
1028 .uriStart = 2,
1029 .uriEnd = 9,
1030 .uri = "HTTP/1.0",
1031 .versionStart = -1,
1032 .versionEnd = -1,
1033 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
1034 };
1035 output.clear();
1036 testResults(__LINE__, input, output, expectRelaxed);
1037
1038 // STRICT detect as invalid
1039 Config.onoff.relaxed_header_parser = 0;
1040 #if WHEN_RFC_COMPLIANT
1041 // XXX: except Squid does not
1042 struct resultSet expectStrict = {
1043 .parsed = false,
1044 .needsMore = false,
1045 .parserState = Http1::HTTP_PARSE_DONE,
1046 .status = Http::scBadRequest,
1047 .msgStart = 0,
1048 .msgEnd = (int)input.length()-1,
1049 .suffixSz = 0,
1050 .methodStart = 0,
1051 .methodEnd = -1,
1052 .method = HttpRequestMethod(),
1053 .uriStart = -1,
1054 .uriEnd = -1,
1055 .uri = NULL,
1056 .versionStart = -1,
1057 .versionEnd = -1,
1058 .version = AnyP::ProtocolVersion()
1059 };
1060 #else
1061 struct resultSet expectStrict = {
1062 .parsed = false,
1063 .needsMore = false,
1064 .parserState = Http1::HTTP_PARSE_DONE,
1065 .status = Http::scBadRequest,
1066 .msgStart = 0,
1067 .msgEnd = (int)input.length()-1,
1068 .suffixSz = input.length(),
1069 .methodStart = 0,
1070 .methodEnd = -1,
1071 .method = HttpRequestMethod(),
1072 .uriStart = -1,
1073 .uriEnd = -1,
1074 .uri = NULL,
1075 .versionStart = -1,
1076 .versionEnd = -1,
1077 .version = AnyP::ProtocolVersion()
1078 };
1079 #endif
1080 output.clear();
1081 testResults(__LINE__, input, output, expectStrict);
1082 input.clear();
1083 }
1084
1085 // binary code in method (invalid)
1086 {
1087 input.append("GET\x0B / HTTP/1.1\n", 16);
1088 #if WHEN_RFC_COMPLIANT
1089 struct resultSet expect = {
1090 .parsed = false,
1091 .needsMore = false,
1092 .parserState = Http1::HTTP_PARSE_DONE,
1093 .status = Http::scBadRequest,
1094 .msgStart = 0,
1095 .msgEnd = (int)input.length()-1,
1096 .suffixSz = input.length(),
1097 .methodStart = -1,
1098 .methodEnd = -1,
1099 .method = HttpRequestMethod(),
1100 .uriStart = -1,
1101 .uriEnd = -1,
1102 .uri = NULL,
1103 .versionStart = -1,
1104 .versionEnd = -1,
1105 .version = AnyP::ProtocolVersion()
1106 };
1107 #else
1108 struct resultSet expect = {
1109 .parsed = false,
1110 .needsMore = true,
1111 .parserState = Http1::HTTP_PARSE_MIME,
1112 .status = Http::scOkay,
1113 .msgStart = 0, // garbage collection consumes the SP
1114 .msgEnd = (int)input.length()-1,
1115 .suffixSz = 0,
1116 .methodStart = 0,
1117 .methodEnd = 3,
1118 .method = HttpRequestMethod(SBuf("GET\x0B")),
1119 .uriStart = 5,
1120 .uriEnd = 5,
1121 .uri = "/",
1122 .versionStart = 7,
1123 .versionEnd = 14,
1124 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
1125 };
1126 #endif
1127 output.clear();
1128 testResults(__LINE__, input, output, expect);
1129 input.clear();
1130 }
1131
1132 // CR in method
1133 {
1134 // RFC 2616 sec 5.1 prohibits CR other than in terminator.
1135 input.append("GET\r / HTTP/1.1\r\n", 16);
1136 struct resultSet expect = {
1137 .parsed = false,
1138 .needsMore = false,
1139 .parserState = Http1::HTTP_PARSE_DONE,
1140 .status = Http::scBadRequest,
1141 .msgStart = 0,
1142 .msgEnd = -1, // halt at the first \r
1143 .suffixSz = input.length(),
1144 .methodStart = -1,
1145 .methodEnd = -1,
1146 .method = HttpRequestMethod(),
1147 .uriStart = -1,
1148 .uriEnd = -1,
1149 .uri = NULL,
1150 .versionStart = -1,
1151 .versionEnd = -1,
1152 .version = AnyP::ProtocolVersion()
1153 };
1154 output.clear();
1155 testResults(__LINE__, input, output, expect);
1156 input.clear();
1157 }
1158
1159 // binary code NUL! in method (strange but ...)
1160 {
1161 input.append("GET\0 / HTTP/1.1\n", 16);
1162 #if WHEN_RFC_COMPLIANT
1163 struct resultSet expect = {
1164 .parsed = false,
1165 .needsMore = false,
1166 .parserState = Http1::HTTP_PARSE_DONE,
1167 .status = Http::scBadRequest,
1168 .msgStart = 0,
1169 .msgEnd = -1, // halt at the \0
1170 .suffixSz = input.length(),
1171 .methodStart = -1,
1172 .methodEnd = -1,
1173 .method = HttpRequestMethod(),
1174 .uriStart = -1,
1175 .uriEnd = -1,
1176 .uri = NULL,
1177 .versionStart = -1,
1178 .versionEnd = -1,
1179 .version = AnyP::ProtocolVersion()
1180 };
1181 #else
1182 struct resultSet expect = {
1183 .parsed = false,
1184 .needsMore = true,
1185 .parserState = Http1::HTTP_PARSE_MIME,
1186 .status = Http::scOkay,
1187 .msgStart = 0,
1188 .msgEnd = (int)input.length()-1,
1189 .suffixSz = 0,
1190 .methodStart = 0,
1191 .methodEnd = 3,
1192 .method = HttpRequestMethod(SBuf("GET\0",4)),
1193 .uriStart = 5,
1194 .uriEnd = 5,
1195 .uri = "/",
1196 .versionStart = 7,
1197 .versionEnd = 14,
1198 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
1199 };
1200 #endif
1201 output.clear();
1202 testResults(__LINE__, input, output, expect);
1203 input.clear();
1204 }
1205
1206 // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
1207 {
1208 input.append("GET HTTP/1.1\n", 14);
1209 struct resultSet expect = {
1210 .parsed = true,
1211 .needsMore = false,
1212 .parserState = Http1::HTTP_PARSE_DONE,
1213 .status = Http::scOkay,
1214 .msgStart = 0,
1215 .msgEnd = (int)input.length()-1,
1216 .suffixSz = 0,
1217 .methodStart = 0,
1218 .methodEnd = 2,
1219 .method = HttpRequestMethod(Http::METHOD_GET),
1220 .uriStart = 5,
1221 .uriEnd = 12,
1222 .uri = "HTTP/1.1",
1223 .versionStart = -1,
1224 .versionEnd = -1,
1225 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
1226 };
1227 output.clear();
1228 testResults(__LINE__, input, output, expect);
1229 input.clear();
1230 }
1231
1232 // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
1233 {
1234 input.append("GET HTTP/1.1\n", 13);
1235 struct resultSet expect = {
1236 .parsed = true,
1237 .needsMore = false,
1238 .parserState = Http1::HTTP_PARSE_DONE,
1239 .status = Http::scOkay,
1240 .msgStart = 0,
1241 .msgEnd = (int)input.length()-1,
1242 .suffixSz = 0,
1243 .methodStart = 0,
1244 .methodEnd = 2,
1245 .method = HttpRequestMethod(Http::METHOD_GET),
1246 .uriStart = 4,
1247 .uriEnd = 11,
1248 .uri = "HTTP/1.1",
1249 .versionStart = -1,
1250 .versionEnd = -1,
1251 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
1252 };
1253 output.clear();
1254 testResults(__LINE__, input, output, expect);
1255 input.clear();
1256 }
1257
1258 // binary line
1259 {
1260 input.append("\xB\xC\xE\xF\n", 5);
1261 struct resultSet expect = {
1262 .parsed = false,
1263 .needsMore = false,
1264 .parserState = Http1::HTTP_PARSE_DONE,
1265 .status = Http::scBadRequest,
1266 .msgStart = 0,
1267 .msgEnd = (int)input.length()-1,
1268 .suffixSz = input.length(),
1269 .methodStart = 0,
1270 .methodEnd = -1,
1271 .method = HttpRequestMethod(),
1272 .uriStart = -1,
1273 .uriEnd = -1,
1274 .uri = NULL,
1275 .versionStart = -1,
1276 .versionEnd = -1,
1277 .version = AnyP::ProtocolVersion()
1278 };
1279 output.clear();
1280 testResults(__LINE__, input, output, expect);
1281 input.clear();
1282 }
1283
1284 // mixed whitespace line
1285 {
1286 // We accept non-space binary bytes for method so first \t shows up as that
1287 // but remaining space and tabs are skipped searching for URI-start
1288 input.append("\t \t \t\n", 6);
1289 struct resultSet expect = {
1290 .parsed = false,
1291 .needsMore = false,
1292 .parserState = Http1::HTTP_PARSE_DONE,
1293 .status = Http::scBadRequest,
1294 .msgStart = 0,
1295 .msgEnd = (int)input.length()-1,
1296 .suffixSz = input.length(),
1297 .methodStart = 0,
1298 .methodEnd = 0,
1299 .method = HttpRequestMethod(SBuf("\t")),
1300 .uriStart = -1,
1301 .uriEnd = -1,
1302 .uri = NULL,
1303 .versionStart = -1,
1304 .versionEnd = -1,
1305 .version = AnyP::ProtocolVersion()
1306 };
1307 output.clear();
1308 testResults(__LINE__, input, output, expect);
1309 input.clear();
1310 }
1311
1312 // mixed whitespace line with CR middle
1313 {
1314 // CR aborts on sight, so even initial \t method is not marked as above
1315 // (not when parsing clean with whole line available anyway)
1316 input.append("\t \r \n", 6);
1317 struct resultSet expect = {
1318 .parsed = false,
1319 .needsMore = false,
1320 .parserState = Http1::HTTP_PARSE_DONE,
1321 .status = Http::scBadRequest,
1322 .msgStart = 0,
1323 .msgEnd = -1, // halt on the \r
1324 .suffixSz = input.length(),
1325 .methodStart = -1,
1326 .methodEnd = -1,
1327 .method = HttpRequestMethod(),
1328 .uriStart = -1,
1329 .uriEnd = -1,
1330 .uri = NULL,
1331 .versionStart = -1,
1332 .versionEnd = -1,
1333 .version = AnyP::ProtocolVersion()
1334 };
1335 output.clear();
1336 testResults(__LINE__, input, output, expect);
1337 input.clear();
1338 }
1339 }
1340
1341 void
1342 testHttp1Parser::testDripFeed()
1343 {
1344 // Simulate a client drip-feeding Squid a few bytes at a time.
1345 // extend the size of the buffer from 0 bytes to full request length
1346 // calling the parser repeatedly as visible data grows.
1347
1348 SBuf data;
1349 data.append(" ", 12);
1350 SBuf::size_type garbageEnd = data.length();
1351 data.append("GET http://example.com/ HTTP/1.1\r\n", 34);
1352 SBuf::size_type reqLineEnd = data.length() - 1;
1353 data.append("Host: example.com\r\n\r\n", 21);
1354 SBuf::size_type mimeEnd = data.length() - 1;
1355 data.append("...", 3); // trailer to catch mime EOS errors.
1356
1357 SBuf ioBuf; // begins empty
1358 Http1::RequestParser hp;
1359
1360 // only relaxed parser accepts the garbage whitespace
1361 Config.onoff.relaxed_header_parser = 1;
1362
1363 // state of things we expect right now
1364 struct resultSet expect = {
1365 .parsed = false,
1366 .needsMore = true,
1367 .parserState = Http1::HTTP_PARSE_NONE,
1368 .status = Http::scNone,
1369 .msgStart = -1,
1370 .msgEnd = -1,
1371 .suffixSz = 0,
1372 .methodStart = -1,
1373 .methodEnd = -1,
1374 .method = HttpRequestMethod(),
1375 .uriStart = -1,
1376 .uriEnd = -1,
1377 .uri = NULL,
1378 .versionStart = -1,
1379 .versionEnd = -1,
1380 .version = AnyP::ProtocolVersion()
1381 };
1382
1383 Config.maxRequestHeaderSize = 1024; // large enough to hold the test data.
1384
1385 for (SBuf::size_type pos = 0; pos <= data.length(); ++pos) {
1386
1387 // simulate reading one more byte
1388 ioBuf.append(data.substr(pos,1));
1389
1390 // when the garbage is passed we expect to start seeing first-line bytes
1391 if (pos == garbageEnd) {
1392 expect.parserState = Http1::HTTP_PARSE_FIRST;
1393 expect.msgStart = 0;
1394 }
1395
1396 // all points after garbage start to see accumulated bytes looking for end of current section
1397 if (pos >= garbageEnd)
1398 expect.suffixSz = ioBuf.length();
1399
1400 // at end of request line expect to see method, URI, version details
1401 // and switch to seeking Mime header section
1402 if (pos == reqLineEnd) {
1403 expect.parserState = Http1::HTTP_PARSE_MIME;
1404 expect.suffixSz = 0;
1405 expect.msgEnd = reqLineEnd-garbageEnd;
1406 expect.status = Http::scOkay;
1407 expect.methodStart = 0;
1408 expect.methodEnd = 2;
1409 expect.method = HttpRequestMethod(Http::METHOD_GET);
1410 expect.uriStart = 4;
1411 expect.uriEnd = 22;
1412 expect.uri = "http://example.com/";
1413 expect.versionStart = 24;
1414 expect.versionEnd = 31;
1415 expect.version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1);
1416 }
1417
1418 // one mime header is done we are expectign a new request
1419 // parse results say true and initial data is all gone from the buffer
1420 if (pos == mimeEnd) {
1421 expect.parsed = true;
1422 expect.needsMore = false;
1423 expect.suffixSz = 0;
1424 }
1425
1426 testResults(__LINE__, ioBuf, hp, expect);
1427
1428 // sync the buffers like Squid does
1429 ioBuf = hp.remaining();
1430
1431 // Squid stops using the parser once it has parsed the first message.
1432 if (!hp.needsMoreData())
1433 break;
1434 }
1435 }