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