]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tests/testHttp1Parser.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / tests / testHttp1Parser.cc
CommitLineData
48a37aee 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
48a37aee
AJ
3 *
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.
7 */
8
f7f3304a 9#include "squid.h"
4c14658e
AJ
10
11#include <cppunit/TestAssert.h>
12
b6a7fc85
AJ
13#define private public
14#define protected public
15
947ca0c6 16#include "Debug.h"
c99510dd 17#include "http/one/RequestParser.h"
274bd5ad 18#include "http/RequestMethod.h"
4c14658e 19#include "MemBuf.h"
4d5904f7 20#include "SquidConfig.h"
bb86dcd4 21#include "testHttp1Parser.h"
7f861c77 22#include "unitTestMain.h"
4c14658e 23
bb86dcd4 24CPPUNIT_TEST_SUITE_REGISTRATION( testHttp1Parser );
4c14658e
AJ
25
26void
bb86dcd4 27testHttp1Parser::globalSetup()
4c14658e
AJ
28{
29 static bool setup_done = false;
30 if (setup_done)
31 return;
26c66627 32
4c14658e
AJ
33 Mem::Init();
34 setup_done = true;
016a316b
AJ
35
36 // default to strict parser. set for loose parsing specifically where behaviour differs.
37 Config.onoff.relaxed_header_parser = 0;
38
39 Config.maxRequestHeaderSize = 1024; // XXX: unit test the RequestParser handling of this limit
4c14658e
AJ
40}
41
7a4fa6a0
AJ
42struct resultSet {
43 bool parsed;
36a9c964 44 bool needsMore;
7a4fa6a0
AJ
45 Http1::ParseState parserState;
46 Http::StatusCode status;
7a4fa6a0 47 SBuf::size_type suffixSz;
7a4fa6a0 48 HttpRequestMethod method;
7a4fa6a0 49 const char *uri;
7a4fa6a0
AJ
50 AnyP::ProtocolVersion version;
51};
52
e02f963c
AR
53// define SQUID_DEBUG_TESTS to see exactly which test sub-cases fail and where
54#ifdef SQUID_DEBUG_TESTS
55// not optimized for runtime use
56static void
57Replace(SBuf &where, const SBuf &what, const SBuf &with)
58{
59 // prevent infinite loops
60 if (!what.length() || with.find(what) != SBuf::npos)
61 return;
62
63 SBuf::size_type pos = 0;
64 while ((pos = where.find(what, pos)) != SBuf::npos) {
65 SBuf buf = where.substr(0, pos);
66 buf.append(with);
67 buf.append(where.substr(pos+what.length()));
68 where = buf;
69 pos += with.length();
70 }
71}
72
73static SBuf Pretty(SBuf raw)
74{
75 Replace(raw, SBuf("\r"), SBuf("\\r"));
76 Replace(raw, SBuf("\n"), SBuf("\\n"));
77 return raw;
78}
79#endif
80
7a4fa6a0
AJ
81static void
82testResults(int line, const SBuf &input, Http1::RequestParser &output, struct resultSet &expect)
83{
e02f963c
AR
84#ifdef SQUID_DEBUG_TESTS
85 std::cerr << "TEST @" << line << ", in=" << Pretty(input) << "\n";
86#endif
87
88 const bool parsed = output.parse(input);
89
90#ifdef SQUID_DEBUG_TESTS
91 if (expect.parsed != parsed)
92 std::cerr << "\tparse-FAILED: " << expect.parsed << "!=" << parsed << "\n";
93 else if (parsed && expect.method != output.method_)
94 std::cerr << "\tmethod-FAILED: " << expect.method << "!=" << output.method_ << "\n";
95 if (expect.status != output.parseStatusCode)
96 std::cerr << "\tscode-FAILED: " << expect.status << "!=" << output.parseStatusCode << "\n";
97 if (expect.suffixSz != output.buf_.length())
98 std::cerr << "\tsuffixSz-FAILED: " << expect.suffixSz << "!=" << output.buf_.length() << "\n";
7a4fa6a0
AJ
99#endif
100
947ca0c6 101 // runs the parse
e02f963c
AR
102 CPPUNIT_ASSERT_EQUAL(expect.parsed, parsed);
103
104 // if parsing was successful, check easily visible field outputs
105 if (parsed) {
106 CPPUNIT_ASSERT_EQUAL(expect.method, output.method_);
107 if (expect.uri != NULL)
108 CPPUNIT_ASSERT_EQUAL(0, output.uri_.cmp(expect.uri));
109 CPPUNIT_ASSERT_EQUAL(expect.version, output.msgProtocol_);
110 }
947ca0c6 111
de158bf5 112 CPPUNIT_ASSERT_EQUAL(expect.status, output.parseStatusCode);
947ca0c6
AJ
113
114 // check more obscure states
115 CPPUNIT_ASSERT_EQUAL(expect.needsMore, output.needsMoreData());
116 if (output.needsMoreData())
117 CPPUNIT_ASSERT_EQUAL(expect.parserState, output.parsingStage_);
118 CPPUNIT_ASSERT_EQUAL(expect.suffixSz, output.buf_.length());
7a4fa6a0
AJ
119}
120
10c0d360
AJ
121void
122testHttp1Parser::testParserConstruct()
123{
124 // whether the constructor works
125 {
126 Http1::RequestParser output;
127 CPPUNIT_ASSERT_EQUAL(true, output.needsMoreData());
128 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output.parsingStage_);
f1d5359e 129 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.parseStatusCode); // XXX: clear() not being called.
10c0d360 130 CPPUNIT_ASSERT(output.buf_.isEmpty());
10c0d360 131 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output.method_);
10c0d360 132 CPPUNIT_ASSERT(output.uri_.isEmpty());
10c0d360
AJ
133 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
134 }
135
136 // whether new() works
137 {
138 Http1::RequestParser *output = new Http1::RequestParser;
139 CPPUNIT_ASSERT_EQUAL(true, output->needsMoreData());
140 CPPUNIT_ASSERT_EQUAL(Http1::HTTP_PARSE_NONE, output->parsingStage_);
f1d5359e 141 CPPUNIT_ASSERT_EQUAL(Http::scNone, output->parseStatusCode);
10c0d360 142 CPPUNIT_ASSERT(output->buf_.isEmpty());
10c0d360 143 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_NONE), output->method_);
10c0d360 144 CPPUNIT_ASSERT(output->uri_.isEmpty());
10c0d360
AJ
145 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output->msgProtocol_);
146 delete output;
147 }
148}
149
4c14658e 150void
bb86dcd4 151testHttp1Parser::testParseRequestLineProtocols()
4c14658e
AJ
152{
153 // ensure MemPools etc exist
154 globalSetup();
155
7a4fa6a0 156 SBuf input;
1b51ee7b 157 Http1::RequestParser output;
4c14658e
AJ
158
159 // TEST: Do we comply with RFC 1945 section 5.1 ?
947ca0c6 160 // TEST: Do we comply with RFC 7230 sections 2.6, 3.1.1 and 3.5 ?
4c14658e
AJ
161
162 // RFC 1945 : HTTP/0.9 simple-request
4245f3b9
AJ
163 {
164 input.append("GET /\r\n", 7);
7a4fa6a0
AJ
165 struct resultSet expect = {
166 .parsed = true,
36a9c964 167 .needsMore = false,
7a4fa6a0
AJ
168 .parserState = Http1::HTTP_PARSE_DONE,
169 .status = Http::scOkay,
7a4fa6a0 170 .suffixSz = 0,
7a4fa6a0 171 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 172 .uri = "/",
7a4fa6a0
AJ
173 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9)
174 };
36a9c964 175 output.clear();
7a4fa6a0
AJ
176 testResults(__LINE__, input, output, expect);
177 input.clear();
4245f3b9 178 }
4c14658e 179
8c730cae 180 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
4245f3b9 181 {
947ca0c6 182 input.append("POST /\r\n", 8);
7a4fa6a0 183 struct resultSet expect = {
947ca0c6 184 .parsed = false,
36a9c964 185 .needsMore = false,
7a4fa6a0 186 .parserState = Http1::HTTP_PARSE_DONE,
947ca0c6 187 .status = Http::scBadRequest,
e02f963c 188 .suffixSz = input.length(),
7a4fa6a0 189 .method = HttpRequestMethod(Http::METHOD_POST),
947ca0c6 190 .uri = NULL,
7a4fa6a0
AJ
191 .version = AnyP::ProtocolVersion()
192 };
36a9c964 193 output.clear();
7a4fa6a0
AJ
194 testResults(__LINE__, input, output, expect);
195 input.clear();
4245f3b9 196 }
947ca0c6
AJ
197
198 // RFC 1945 and 7230 : HTTP/1.0 request
4245f3b9
AJ
199 {
200 input.append("GET / HTTP/1.0\r\n", 16);
7a4fa6a0
AJ
201 struct resultSet expect = {
202 .parsed = false,
36a9c964 203 .needsMore = true,
7a4fa6a0
AJ
204 .parserState = Http1::HTTP_PARSE_MIME,
205 .status = Http::scOkay,
7a4fa6a0 206 .suffixSz = 0,
7a4fa6a0 207 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 208 .uri = "/",
7a4fa6a0
AJ
209 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0)
210 };
36a9c964 211 output.clear();
7a4fa6a0
AJ
212 testResults(__LINE__, input, output, expect);
213 input.clear();
4245f3b9 214 }
4c14658e 215
947ca0c6 216 // RFC 7230 : HTTP/1.1 request
4245f3b9
AJ
217 {
218 input.append("GET / HTTP/1.1\r\n", 16);
7a4fa6a0
AJ
219 struct resultSet expect = {
220 .parsed = false,
36a9c964 221 .needsMore = true,
7a4fa6a0
AJ
222 .parserState = Http1::HTTP_PARSE_MIME,
223 .status = Http::scOkay,
7a4fa6a0 224 .suffixSz = 0,
7a4fa6a0 225 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 226 .uri = "/",
7a4fa6a0
AJ
227 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
228 };
36a9c964 229 output.clear();
7a4fa6a0
AJ
230 testResults(__LINE__, input, output, expect);
231 input.clear();
4245f3b9 232 }
4c14658e 233
f9f79936 234 // RFC 7230 : future 1.x version full-request
f4880526
AJ
235 {
236 input.append("GET / HTTP/1.2\r\n", 16);
7a4fa6a0
AJ
237 struct resultSet expect = {
238 .parsed = false,
36a9c964 239 .needsMore = true,
7a4fa6a0
AJ
240 .parserState = Http1::HTTP_PARSE_MIME,
241 .status = Http::scOkay,
7a4fa6a0 242 .suffixSz = 0,
7a4fa6a0 243 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 244 .uri = "/",
7a4fa6a0
AJ
245 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2)
246 };
36a9c964 247 output.clear();
7a4fa6a0
AJ
248 testResults(__LINE__, input, output, expect);
249 input.clear();
4245f3b9 250 }
8c730cae 251
f9f79936
AJ
252 // RFC 7230 : future versions do not use 1.x message syntax.
253 // However, it is still valid syntax for the single-digit forms
254 // to appear. The parser we are testing should accept them.
4245f3b9 255 {
947ca0c6
AJ
256 input.append("GET / HTTP/2.0\r\n", 16);
257 struct resultSet expectA = {
f9f79936 258 .parsed = true,
947ca0c6 259 .needsMore = false,
f9f79936
AJ
260 .parserState = Http1::HTTP_PARSE_DONE,
261 .status = Http::scOkay,
262 .suffixSz = 0,
263 .method = HttpRequestMethod(Http::METHOD_GET),
947ca0c6 264 .uri = "/",
f9f79936 265 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,2,0)
947ca0c6
AJ
266 };
267 output.clear();
268 testResults(__LINE__, input, output, expectA);
269 input.clear();
270
f9f79936 271 input.append("GET / HTTP/9.9\r\n", 16);
947ca0c6 272 struct resultSet expectB = {
f9f79936
AJ
273 .parsed = true,
274 .needsMore = false,
275 .parserState = Http1::HTTP_PARSE_DONE,
276 .status = Http::scOkay,
277 .suffixSz = 0,
278 .method = HttpRequestMethod(Http::METHOD_GET),
279 .uri = "/",
280 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,9,9)
281 };
282 output.clear();
283 testResults(__LINE__, input, output, expectB);
284 input.clear();
285 }
286
287 // RFC 7230 : future versions >= 10.0 are invalid syntax
288 {
289 input.append("GET / HTTP/10.12\r\n", 18);
290 struct resultSet expect = {
7a4fa6a0 291 .parsed = false,
36a9c964 292 .needsMore = false,
7a4fa6a0 293 .parserState = Http1::HTTP_PARSE_MIME,
e02f963c
AR
294 .status = Http::scBadRequest,
295 .suffixSz = input.length(),
7a4fa6a0 296 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 297 .uri = "/",
9651320a 298 .version = AnyP::ProtocolVersion()
7a4fa6a0 299 };
36a9c964 300 output.clear();
f9f79936 301 testResults(__LINE__, input, output, expect);
7a4fa6a0 302 input.clear();
4245f3b9 303 }
4c14658e 304
7a4fa6a0 305 // unknown non-HTTP protocol names
4245f3b9 306 {
947ca0c6 307 input.append("GET / FOO/1.0\r\n", 15);
7a4fa6a0
AJ
308 struct resultSet expect = {
309 .parsed = false,
36a9c964 310 .needsMore = false,
7a4fa6a0 311 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
312 .status = Http::scBadRequest,
313 .suffixSz = input.length(),
7a4fa6a0 314 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 315 .uri = "/",
7a4fa6a0
AJ
316 .version = AnyP::ProtocolVersion()
317 };
36a9c964 318 output.clear();
7a4fa6a0
AJ
319 testResults(__LINE__, input, output, expect);
320 input.clear();
4245f3b9 321 }
8c730cae 322
947ca0c6 323 // no version digits
4245f3b9 324 {
947ca0c6 325 input.append("GET / HTTP/\r\n", 13);
7a4fa6a0
AJ
326 struct resultSet expect = {
327 .parsed = false,
36a9c964 328 .needsMore = false,
7a4fa6a0 329 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
330 .status = Http::scBadRequest,
331 .suffixSz = input.length(),
7a4fa6a0 332 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 333 .uri = "/",
9651320a 334 .version = AnyP::ProtocolVersion()
7a4fa6a0 335 };
36a9c964 336 output.clear();
7a4fa6a0
AJ
337 testResults(__LINE__, input, output, expect);
338 input.clear();
4245f3b9 339 }
4c14658e 340
8c730cae 341 // no major version
4245f3b9 342 {
947ca0c6 343 input.append("GET / HTTP/.1\r\n", 15);
7a4fa6a0
AJ
344 struct resultSet expect = {
345 .parsed = false,
36a9c964 346 .needsMore = false,
7a4fa6a0 347 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
348 .status = Http::scBadRequest,
349 .suffixSz = input.length(),
7a4fa6a0 350 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 351 .uri = "/",
9651320a 352 .version = AnyP::ProtocolVersion()
7a4fa6a0 353 };
36a9c964 354 output.clear();
7a4fa6a0
AJ
355 testResults(__LINE__, input, output, expect);
356 input.clear();
4245f3b9 357 }
8c730cae
AJ
358
359 // no version dot
4245f3b9 360 {
947ca0c6 361 input.append("GET / HTTP/11\r\n", 15);
7a4fa6a0
AJ
362 struct resultSet expect = {
363 .parsed = false,
36a9c964 364 .needsMore = false,
7a4fa6a0 365 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
366 .status = Http::scBadRequest,
367 .suffixSz = input.length(),
7a4fa6a0 368 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 369 .uri = "/",
9651320a 370 .version = AnyP::ProtocolVersion()
7a4fa6a0 371 };
36a9c964 372 output.clear();
7a4fa6a0
AJ
373 testResults(__LINE__, input, output, expect);
374 input.clear();
4245f3b9 375 }
8c730cae
AJ
376
377 // negative major version (bug 3062)
4245f3b9 378 {
947ca0c6 379 input.append("GET / HTTP/-999999.1\r\n", 22);
7a4fa6a0
AJ
380 struct resultSet expect = {
381 .parsed = false,
36a9c964 382 .needsMore = false,
7a4fa6a0 383 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
384 .status = Http::scBadRequest,
385 .suffixSz = input.length(),
7a4fa6a0 386 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 387 .uri = "/",
9651320a 388 .version = AnyP::ProtocolVersion()
7a4fa6a0 389 };
36a9c964 390 output.clear();
7a4fa6a0
AJ
391 testResults(__LINE__, input, output, expect);
392 input.clear();
4245f3b9 393 }
4c14658e 394
8c730cae 395 // no minor version
4245f3b9 396 {
947ca0c6 397 input.append("GET / HTTP/1.\r\n", 15);
7a4fa6a0
AJ
398 struct resultSet expect = {
399 .parsed = false,
36a9c964 400 .needsMore = false,
7a4fa6a0 401 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
402 .status = Http::scBadRequest,
403 .suffixSz = input.length(),
7a4fa6a0 404 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 405 .uri = "/",
947ca0c6 406 .version = AnyP::ProtocolVersion()
7a4fa6a0 407 };
36a9c964 408 output.clear();
7a4fa6a0
AJ
409 testResults(__LINE__, input, output, expect);
410 input.clear();
4245f3b9 411 }
8c730cae
AJ
412
413 // negative major version (bug 3062 corollary)
4245f3b9 414 {
947ca0c6 415 input.append("GET / HTTP/1.-999999\r\n", 22);
7a4fa6a0
AJ
416 struct resultSet expect = {
417 .parsed = false,
36a9c964 418 .needsMore = false,
7a4fa6a0 419 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
420 .status = Http::scBadRequest,
421 .suffixSz = input.length(),
7a4fa6a0 422 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 423 .uri = "/",
947ca0c6 424 .version = AnyP::ProtocolVersion()
7a4fa6a0 425 };
36a9c964 426 output.clear();
7a4fa6a0
AJ
427 testResults(__LINE__, input, output, expect);
428 input.clear();
4245f3b9 429 }
8c730cae
AJ
430}
431
432void
bb86dcd4 433testHttp1Parser::testParseRequestLineStrange()
8c730cae
AJ
434{
435 // ensure MemPools etc exist
436 globalSetup();
437
7a4fa6a0 438 SBuf input;
1b51ee7b 439 Http1::RequestParser output;
8c730cae
AJ
440
441 // space padded URL
4245f3b9
AJ
442 {
443 input.append("GET / HTTP/1.1\r\n", 21);
947ca0c6
AJ
444 // when being tolerant extra (sequential) SP delimiters are acceptable
445 Config.onoff.relaxed_header_parser = 1;
7a4fa6a0
AJ
446 struct resultSet expect = {
447 .parsed = false,
36a9c964 448 .needsMore = true,
7a4fa6a0
AJ
449 .parserState = Http1::HTTP_PARSE_MIME,
450 .status = Http::scOkay,
7a4fa6a0 451 .suffixSz = 0,
7a4fa6a0 452 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 453 .uri = "/",
7a4fa6a0
AJ
454 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
455 };
36a9c964 456 output.clear();
7a4fa6a0 457 testResults(__LINE__, input, output, expect);
947ca0c6
AJ
458
459 Config.onoff.relaxed_header_parser = 0;
460 struct resultSet expectStrict = {
461 .parsed = false,
462 .needsMore = false,
463 .parserState = Http1::HTTP_PARSE_DONE,
464 .status = Http::scBadRequest,
e02f963c
AR
465 .suffixSz = input.length(),
466 .method = HttpRequestMethod(),
947ca0c6
AJ
467 .uri = NULL,
468 .version = AnyP::ProtocolVersion()
469 };
470 output.clear();
471 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 472 input.clear();
4245f3b9 473 }
8c730cae 474
4c14658e 475 // whitespace inside URI. (nasty but happens)
4245f3b9 476 {
947ca0c6
AJ
477 input.append("GET /fo o/ HTTP/1.1\r\n", 21);
478 Config.onoff.relaxed_header_parser = 1;
7a4fa6a0
AJ
479 struct resultSet expect = {
480 .parsed = false,
36a9c964 481 .needsMore = true,
7a4fa6a0
AJ
482 .parserState = Http1::HTTP_PARSE_MIME,
483 .status = Http::scOkay,
7a4fa6a0 484 .suffixSz = 0,
7a4fa6a0 485 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 486 .uri = "/fo o/",
7a4fa6a0
AJ
487 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
488 };
36a9c964 489 output.clear();
7a4fa6a0 490 testResults(__LINE__, input, output, expect);
947ca0c6
AJ
491
492 Config.onoff.relaxed_header_parser = 0;
493 struct resultSet expectStrict = {
494 .parsed = false,
495 .needsMore = false,
496 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
497 .status = Http::scBadRequest,
498 .suffixSz = input.length(),
499 .method = HttpRequestMethod(),
947ca0c6
AJ
500 .uri = NULL,
501 .version = AnyP::ProtocolVersion()
502 };
503 output.clear();
504 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 505 input.clear();
4245f3b9 506 }
4c14658e
AJ
507
508 // additional data in buffer
4245f3b9 509 {
947ca0c6 510 input.append("GET / HTTP/1.1\r\nboo!", 20);
7a4fa6a0
AJ
511 struct resultSet expect = {
512 .parsed = false,
36a9c964 513 .needsMore = true,
7a4fa6a0
AJ
514 .parserState = Http1::HTTP_PARSE_MIME,
515 .status = Http::scOkay,
7a4fa6a0 516 .suffixSz = 4, // strlen("boo!")
7a4fa6a0 517 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 518 .uri = "/",
7a4fa6a0
AJ
519 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
520 };
36a9c964 521 output.clear();
7a4fa6a0
AJ
522 testResults(__LINE__, input, output, expect);
523 input.clear();
947ca0c6 524 Config.onoff.relaxed_header_parser = 0;
4245f3b9 525 }
8c730cae
AJ
526}
527
528void
bb86dcd4 529testHttp1Parser::testParseRequestLineTerminators()
8c730cae
AJ
530{
531 // ensure MemPools etc exist
532 globalSetup();
533
7a4fa6a0 534 SBuf input;
1b51ee7b 535 Http1::RequestParser output;
4c14658e
AJ
536
537 // alternative EOL sequence: NL-only
947ca0c6 538 // RFC 7230 tolerance permits omitted CR
4245f3b9
AJ
539 {
540 input.append("GET / HTTP/1.1\n", 15);
947ca0c6 541 Config.onoff.relaxed_header_parser = 1;
7a4fa6a0
AJ
542 struct resultSet expect = {
543 .parsed = false,
36a9c964 544 .needsMore = true,
7a4fa6a0
AJ
545 .parserState = Http1::HTTP_PARSE_MIME,
546 .status = Http::scOkay,
7a4fa6a0 547 .suffixSz = 0,
7a4fa6a0 548 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 549 .uri = "/",
7a4fa6a0
AJ
550 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
551 };
36a9c964 552 output.clear();
7a4fa6a0 553 testResults(__LINE__, input, output, expect);
4c14658e 554
947ca0c6
AJ
555 Config.onoff.relaxed_header_parser = 0;
556 struct resultSet expectStrict = {
557 .parsed = false,
36a9c964 558 .needsMore = false,
7a4fa6a0 559 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
560 .status = Http::scBadRequest,
561 .suffixSz = input.length(),
562 .method = HttpRequestMethod(),
563 .uri = NULL,
947ca0c6 564 .version = AnyP::ProtocolVersion()
7a4fa6a0 565 };
36a9c964 566 output.clear();
947ca0c6 567 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 568 input.clear();
4245f3b9 569 }
4c14658e 570
947ca0c6
AJ
571 // alternative EOL sequence: double-NL-only
572 // RFC 7230 tolerance permits omitted CR
573 // NP: represents a request with no mime headers
4245f3b9 574 {
947ca0c6 575 input.append("GET / HTTP/1.1\n\n", 16);
7a4fa6a0 576 Config.onoff.relaxed_header_parser = 1;
947ca0c6
AJ
577 struct resultSet expect = {
578 .parsed = true,
579 .needsMore = false,
580 .parserState = Http1::HTTP_PARSE_DONE,
7a4fa6a0 581 .status = Http::scOkay,
7a4fa6a0 582 .suffixSz = 0,
7a4fa6a0 583 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 584 .uri = "/",
7a4fa6a0
AJ
585 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
586 };
36a9c964 587 output.clear();
947ca0c6 588 testResults(__LINE__, input, output, expect);
4c14658e 589
4245f3b9 590 Config.onoff.relaxed_header_parser = 0;
7a4fa6a0
AJ
591 struct resultSet expectStrict = {
592 .parsed = false,
36a9c964 593 .needsMore = false,
947ca0c6 594 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
595 .status = Http::scBadRequest,
596 .suffixSz = input.length(),
597 .method = HttpRequestMethod(),
598 .uri = NULL,
7a4fa6a0
AJ
599 .version = AnyP::ProtocolVersion()
600 };
36a9c964 601 output.clear();
7a4fa6a0
AJ
602 testResults(__LINE__, input, output, expectStrict);
603 input.clear();
4245f3b9 604 }
4c14658e 605
8c730cae 606 // space padded version
4245f3b9 607 {
947ca0c6
AJ
608 // RFC 7230 specifies version is followed by CRLF. No intermediary bytes.
609 input.append("GET / HTTP/1.1 \r\n", 17);
7a4fa6a0
AJ
610 struct resultSet expect = {
611 .parsed = false,
36a9c964 612 .needsMore = false,
7a4fa6a0 613 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
614 .status = Http::scBadRequest,
615 .suffixSz = input.length(),
616 .method = HttpRequestMethod(),
617 .uri = NULL,
7a4fa6a0
AJ
618 .version = AnyP::ProtocolVersion()
619 };
36a9c964 620 output.clear();
7a4fa6a0
AJ
621 testResults(__LINE__, input, output, expect);
622 input.clear();
4245f3b9 623 }
8c730cae
AJ
624}
625
626void
bb86dcd4 627testHttp1Parser::testParseRequestLineMethods()
8c730cae
AJ
628{
629 // ensure MemPools etc exist
630 globalSetup();
631
7a4fa6a0 632 SBuf input;
1b51ee7b 633 Http1::RequestParser output;
8c730cae 634
947ca0c6 635 // RFC 7230 : dot method
4245f3b9 636 {
947ca0c6 637 input.append(". / HTTP/1.1\r\n", 14);
7a4fa6a0
AJ
638 struct resultSet expect = {
639 .parsed = false,
36a9c964 640 .needsMore = true,
7a4fa6a0
AJ
641 .parserState = Http1::HTTP_PARSE_MIME,
642 .status = Http::scOkay,
7a4fa6a0 643 .suffixSz = 0,
f9688132 644 .method = HttpRequestMethod(SBuf(".")),
7a4fa6a0 645 .uri = "/",
947ca0c6
AJ
646 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
647 };
648 output.clear();
649 testResults(__LINE__, input, output, expect);
650 input.clear();
651 }
652
653 // RFC 7230 : special TCHAR method chars
654 {
655 input.append("!#$%&'*+-.^_`|~ / HTTP/1.1\r\n", 28);
656 struct resultSet expect = {
657 .parsed = false,
658 .needsMore = true,
659 .parserState = Http1::HTTP_PARSE_MIME,
660 .status = Http::scOkay,
661 .suffixSz = 0,
662 .method = HttpRequestMethod(SBuf("!#$%&'*+-.^_`|~")),
663 .uri = "/",
7a4fa6a0
AJ
664 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
665 };
36a9c964 666 output.clear();
7a4fa6a0
AJ
667 testResults(__LINE__, input, output, expect);
668 input.clear();
4245f3b9 669 }
4c14658e
AJ
670
671 // OPTIONS with * URL
4245f3b9 672 {
947ca0c6 673 input.append("OPTIONS * HTTP/1.1\r\n", 20);
7a4fa6a0
AJ
674 struct resultSet expect = {
675 .parsed = false,
36a9c964 676 .needsMore = true,
7a4fa6a0
AJ
677 .parserState = Http1::HTTP_PARSE_MIME,
678 .status = Http::scOkay,
7a4fa6a0 679 .suffixSz = 0,
7a4fa6a0 680 .method = HttpRequestMethod(Http::METHOD_OPTIONS),
7a4fa6a0 681 .uri = "*",
7a4fa6a0
AJ
682 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
683 };
36a9c964 684 output.clear();
7a4fa6a0
AJ
685 testResults(__LINE__, input, output, expect);
686 input.clear();
4245f3b9 687 }
4c14658e
AJ
688
689 // unknown method
4245f3b9 690 {
947ca0c6 691 input.append("HELLOWORLD / HTTP/1.1\r\n", 23);
7a4fa6a0
AJ
692 struct resultSet expect = {
693 .parsed = false,
36a9c964 694 .needsMore = true,
7a4fa6a0
AJ
695 .parserState = Http1::HTTP_PARSE_MIME,
696 .status = Http::scOkay,
7a4fa6a0 697 .suffixSz = 0,
f9688132 698 .method = HttpRequestMethod(SBuf("HELLOWORLD")),
7a4fa6a0 699 .uri = "/",
7a4fa6a0
AJ
700 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
701 };
36a9c964 702 output.clear();
7a4fa6a0
AJ
703 testResults(__LINE__, input, output, expect);
704 input.clear();
4245f3b9 705 }
4c14658e 706
e02f963c 707#if 0
947ca0c6
AJ
708 // too-long method (over 16 bytes)
709 {
710 input.append("HELLOSTRANGEWORLD / HTTP/1.1\r\n", 31);
711 struct resultSet expect = {
712 .parsed = false,
713 .needsMore = false,
714 .parserState = Http1::HTTP_PARSE_DONE,
715 .status = Http::scNotImplemented,
716 .suffixSz = input.length(),
717 .method = HttpRequestMethod(),
718 .uri = NULL,
719 .version = AnyP::ProtocolVersion()
720 };
721 output.clear();
722 testResults(__LINE__, input, output, expect);
723 input.clear();
724 }
e02f963c 725#endif
947ca0c6 726
8c730cae 727 // method-only
4245f3b9
AJ
728 {
729 input.append("A\n", 2);
7a4fa6a0
AJ
730 struct resultSet expect = {
731 .parsed = false,
36a9c964 732 .needsMore = false,
7a4fa6a0
AJ
733 .parserState = Http1::HTTP_PARSE_DONE,
734 .status = Http::scBadRequest,
7a4fa6a0 735 .suffixSz = input.length(),
7a4fa6a0 736 .method = HttpRequestMethod(),
7a4fa6a0 737 .uri = NULL,
7a4fa6a0
AJ
738 .version = AnyP::ProtocolVersion()
739 };
36a9c964 740 output.clear();
7a4fa6a0
AJ
741 testResults(__LINE__, input, output, expect);
742 input.clear();
4245f3b9 743 }
8c730cae 744
4245f3b9 745 {
7a4fa6a0
AJ
746 input.append("GET\n", 4);
747 struct resultSet expect = {
748 .parsed = false,
36a9c964 749 .needsMore = false,
7a4fa6a0
AJ
750 .parserState = Http1::HTTP_PARSE_DONE,
751 .status = Http::scBadRequest,
7a4fa6a0 752 .suffixSz = input.length(),
7a4fa6a0 753 .method = HttpRequestMethod(),
7a4fa6a0 754 .uri = NULL,
7a4fa6a0
AJ
755 .version = AnyP::ProtocolVersion()
756 };
36a9c964 757 output.clear();
7a4fa6a0
AJ
758 testResults(__LINE__, input, output, expect);
759 input.clear();
4245f3b9 760 }
4c14658e 761
947ca0c6 762 // space padded method (SP is reserved so invalid as a method byte)
4245f3b9 763 {
947ca0c6
AJ
764 input.append(" GET / HTTP/1.1\r\n", 17);
765 struct resultSet expect = {
766 .parsed = false,
767 .needsMore = false,
768 .parserState = Http1::HTTP_PARSE_DONE,
769 .status = Http::scBadRequest,
770 .suffixSz = input.length(),
771 .method = HttpRequestMethod(),
772 .uri = NULL,
773 .version = AnyP::ProtocolVersion()
774 };
775 output.clear();
776 testResults(__LINE__, input, output, expect);
777 input.clear();
778 }
779
780 // RFC 7230 defined tolerance: ignore empty line(s) prefix on messages
4245f3b9 781 {
947ca0c6 782 input.append("\r\n\r\n\nGET / HTTP/1.1\r\n", 21);
4245f3b9 783 Config.onoff.relaxed_header_parser = 1;
947ca0c6 784 struct resultSet expect = {
7a4fa6a0 785 .parsed = false,
36a9c964 786 .needsMore = true,
7a4fa6a0
AJ
787 .parserState = Http1::HTTP_PARSE_MIME,
788 .status = Http::scOkay,
7a4fa6a0 789 .suffixSz = 0,
7a4fa6a0 790 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 791 .uri = "/",
7a4fa6a0
AJ
792 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
793 };
36a9c964 794 output.clear();
947ca0c6 795 testResults(__LINE__, input, output, expect);
7a4fa6a0 796
f4880526 797 Config.onoff.relaxed_header_parser = 0;
7a4fa6a0
AJ
798 struct resultSet expectStrict = {
799 .parsed = false,
36a9c964 800 .needsMore = false,
7a4fa6a0
AJ
801 .parserState = Http1::HTTP_PARSE_DONE,
802 .status = Http::scBadRequest,
7a4fa6a0 803 .suffixSz = input.length(),
7a4fa6a0 804 .method = HttpRequestMethod(),
7a4fa6a0 805 .uri = NULL,
7a4fa6a0
AJ
806 .version = AnyP::ProtocolVersion()
807 };
36a9c964 808 output.clear();
7a4fa6a0
AJ
809 testResults(__LINE__, input, output, expectStrict);
810 input.clear();
4245f3b9 811 }
4c14658e 812
947ca0c6 813 // forbidden character in method
4245f3b9 814 {
947ca0c6 815 input.append("\tGET / HTTP/1.1\r\n", 17);
7a4fa6a0
AJ
816 struct resultSet expect = {
817 .parsed = false,
36a9c964 818 .needsMore = false,
947ca0c6
AJ
819 .parserState = Http1::HTTP_PARSE_DONE,
820 .status = Http::scBadRequest,
821 .suffixSz = input.length(),
822 .method = HttpRequestMethod(),
823 .uri = NULL,
824 .version = AnyP::ProtocolVersion()
825 };
826 output.clear();
827 testResults(__LINE__, input, output, expect);
828 input.clear();
829 }
830
831 // CR in method delimiters
832 {
833 // RFC 7230 section 3.5 permits CR in whitespace but only for tolerant parsers
834 input.append("GET\r / HTTP/1.1\r\n", 17);
835 Config.onoff.relaxed_header_parser = 1;
836 struct resultSet expect = {
837 .parsed = false,
838 .needsMore = true,
7a4fa6a0
AJ
839 .parserState = Http1::HTTP_PARSE_MIME,
840 .status = Http::scOkay,
947ca0c6 841 .suffixSz = 0,
7a4fa6a0 842 .method = HttpRequestMethod(Http::METHOD_GET),
7a4fa6a0 843 .uri = "/",
7a4fa6a0
AJ
844 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
845 };
36a9c964 846 output.clear();
7a4fa6a0 847 testResults(__LINE__, input, output, expect);
947ca0c6
AJ
848
849 Config.onoff.relaxed_header_parser = 0;
850 struct resultSet expectStrict = {
851 .parsed = false,
852 .needsMore = false,
853 .parserState = Http1::HTTP_PARSE_DONE,
854 .status = Http::scBadRequest,
855 .suffixSz = input.length(),
856 .method = HttpRequestMethod(),
857 .uri = NULL,
858 .version = AnyP::ProtocolVersion()
859 };
860 output.clear();
861 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 862 input.clear();
4245f3b9 863 }
4c14658e 864
947ca0c6 865 // tolerant parser delimiters
4245f3b9 866 {
947ca0c6
AJ
867 // RFC 7230 section 3.5 permits certain binary characters as whitespace delimiters
868 input.append("GET\r\t\x0B\x0C / HTTP/1.1\r\n", 20);
869 Config.onoff.relaxed_header_parser = 1;
7a4fa6a0 870 struct resultSet expect = {
947ca0c6
AJ
871 .parsed = false,
872 .needsMore = true,
873 .parserState = Http1::HTTP_PARSE_MIME,
874 .status = Http::scOkay,
875 .suffixSz = 0,
876 .method = HttpRequestMethod(Http::METHOD_GET),
877 .uri = "/",
878 .version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1)
879 };
880 output.clear();
881 testResults(__LINE__, input, output, expect);
882
883 Config.onoff.relaxed_header_parser = 0;
884 struct resultSet expectStrict = {
7a4fa6a0 885 .parsed = false,
36a9c964 886 .needsMore = false,
7a4fa6a0
AJ
887 .parserState = Http1::HTTP_PARSE_DONE,
888 .status = Http::scBadRequest,
7a4fa6a0 889 .suffixSz = input.length(),
7a4fa6a0 890 .method = HttpRequestMethod(),
7a4fa6a0 891 .uri = NULL,
7a4fa6a0
AJ
892 .version = AnyP::ProtocolVersion()
893 };
36a9c964 894 output.clear();
947ca0c6 895 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 896 input.clear();
4245f3b9 897 }
8c730cae 898}
4c14658e 899
8c730cae 900void
bb86dcd4 901testHttp1Parser::testParseRequestLineInvalid()
8c730cae
AJ
902{
903 // ensure MemPools etc exist
904 globalSetup();
4c14658e 905
7a4fa6a0 906 SBuf input;
1b51ee7b 907 Http1::RequestParser output;
4c14658e 908
947ca0c6 909 // no method (or method delimiter)
4245f3b9 910 {
947ca0c6 911 // HTTP/0.9 requires method to be "GET"
4245f3b9 912 input.append("/ HTTP/1.0\n", 11);
7a4fa6a0 913 struct resultSet expect = {
7a4fa6a0 914 .parsed = false,
36a9c964 915 .needsMore = false,
7a4fa6a0
AJ
916 .parserState = Http1::HTTP_PARSE_DONE,
917 .status = Http::scBadRequest,
7a4fa6a0 918 .suffixSz = input.length(),
7a4fa6a0 919 .method = HttpRequestMethod(),
7a4fa6a0 920 .uri = NULL,
7a4fa6a0
AJ
921 .version = AnyP::ProtocolVersion()
922 };
36a9c964 923 output.clear();
947ca0c6 924 testResults(__LINE__, input, output, expect);
7a4fa6a0 925 input.clear();
4245f3b9 926 }
4c14658e 927
947ca0c6 928 // no method (with method delimiter)
4245f3b9 929 {
947ca0c6
AJ
930 input.append(" / HTTP/1.0\n", 12);
931 struct resultSet expectStrict = {
7a4fa6a0 932 .parsed = false,
36a9c964 933 .needsMore = false,
7a4fa6a0
AJ
934 .parserState = Http1::HTTP_PARSE_DONE,
935 .status = Http::scBadRequest,
7a4fa6a0 936 .suffixSz = input.length(),
7a4fa6a0 937 .method = HttpRequestMethod(),
7a4fa6a0 938 .uri = NULL,
7a4fa6a0
AJ
939 .version = AnyP::ProtocolVersion()
940 };
36a9c964 941 output.clear();
947ca0c6 942 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 943 input.clear();
4245f3b9 944 }
4c14658e 945
e02f963c 946 // binary code after method (invalid)
4245f3b9 947 {
e02f963c 948 input.append("GET\x16 / HTTP/1.1\r\n", 17);
7a4fa6a0
AJ
949 struct resultSet expect = {
950 .parsed = false,
36a9c964 951 .needsMore = false,
7a4fa6a0
AJ
952 .parserState = Http1::HTTP_PARSE_DONE,
953 .status = Http::scBadRequest,
7a4fa6a0 954 .suffixSz = input.length(),
7a4fa6a0 955 .method = HttpRequestMethod(),
7a4fa6a0 956 .uri = NULL,
7a4fa6a0
AJ
957 .version = AnyP::ProtocolVersion()
958 };
36a9c964 959 output.clear();
7a4fa6a0
AJ
960 testResults(__LINE__, input, output, expect);
961 input.clear();
4245f3b9 962 }
4c14658e 963
e02f963c 964 // binary code NUL! after method (always invalid)
4245f3b9 965 {
947ca0c6 966 input.append("GET\0 / HTTP/1.1\r\n", 17);
7a4fa6a0
AJ
967 struct resultSet expect = {
968 .parsed = false,
36a9c964 969 .needsMore = false,
7a4fa6a0
AJ
970 .parserState = Http1::HTTP_PARSE_DONE,
971 .status = Http::scBadRequest,
7a4fa6a0 972 .suffixSz = input.length(),
7a4fa6a0 973 .method = HttpRequestMethod(),
7a4fa6a0 974 .uri = NULL,
7a4fa6a0
AJ
975 .version = AnyP::ProtocolVersion()
976 };
36a9c964 977 output.clear();
7a4fa6a0
AJ
978 testResults(__LINE__, input, output, expect);
979 input.clear();
4245f3b9 980 }
4c14658e 981
e02f963c
AR
982 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
983 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
4245f3b9 984 {
947ca0c6 985 input.append("GET HTTP/1.1\r\n", 15);
947ca0c6 986 Config.onoff.relaxed_header_parser = 1;
7a4fa6a0 987 struct resultSet expect = {
e02f963c 988 .parsed = false,
36a9c964 989 .needsMore = false,
7a4fa6a0 990 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
991 .status = Http::scBadRequest,
992 .suffixSz = input.length(),
993 .method = HttpRequestMethod(),
994 .uri = NULL,
995 .version = AnyP::ProtocolVersion()
7a4fa6a0 996 };
36a9c964 997 output.clear();
7a4fa6a0 998 testResults(__LINE__, input, output, expect);
947ca0c6
AJ
999
1000 Config.onoff.relaxed_header_parser = 0;
1001 struct resultSet expectStrict = {
1002 .parsed = false,
1003 .needsMore = false,
1004 .parserState = Http1::HTTP_PARSE_DONE,
1005 .status = Http::scBadRequest,
e02f963c
AR
1006 .suffixSz = input.length(),
1007 .method = HttpRequestMethod(),
947ca0c6
AJ
1008 .uri = NULL,
1009 .version = AnyP::ProtocolVersion()
1010 };
1011 output.clear();
1012 testResults(__LINE__, input, output, expectStrict);
7a4fa6a0 1013 input.clear();
4245f3b9 1014 }
4c14658e 1015
e02f963c
AR
1016 // Either an RFC 1945 HTTP/0.9 simple-request for an "HTTP/1.1" URI or
1017 // an invalid (no URI) HTTP/1.1 request. We treat this as latter, naturally.
4245f3b9 1018 {
947ca0c6 1019 input.append("GET HTTP/1.1\r\n", 14);
7a4fa6a0 1020 struct resultSet expect = {
e02f963c 1021 .parsed = false,
36a9c964 1022 .needsMore = false,
7a4fa6a0 1023 .parserState = Http1::HTTP_PARSE_DONE,
e02f963c
AR
1024 .status = Http::scBadRequest,
1025 .suffixSz = input.length(),
1026 .method = HttpRequestMethod(),
1027 .uri = NULL,
1028 .version = AnyP::ProtocolVersion()
7a4fa6a0 1029 };
36a9c964 1030 output.clear();
7a4fa6a0
AJ
1031 testResults(__LINE__, input, output, expect);
1032 input.clear();
4245f3b9 1033 }
4c14658e 1034
4c14658e 1035 // binary line
4245f3b9
AJ
1036 {
1037 input.append("\xB\xC\xE\xF\n", 5);
7a4fa6a0
AJ
1038 struct resultSet expect = {
1039 .parsed = false,
36a9c964 1040 .needsMore = false,
7a4fa6a0
AJ
1041 .parserState = Http1::HTTP_PARSE_DONE,
1042 .status = Http::scBadRequest,
7a4fa6a0 1043 .suffixSz = input.length(),
7a4fa6a0 1044 .method = HttpRequestMethod(),
7a4fa6a0 1045 .uri = NULL,
7a4fa6a0
AJ
1046 .version = AnyP::ProtocolVersion()
1047 };
36a9c964 1048 output.clear();
7a4fa6a0
AJ
1049 testResults(__LINE__, input, output, expect);
1050 input.clear();
4245f3b9 1051 }
4c14658e
AJ
1052
1053 // mixed whitespace line
4245f3b9 1054 {
4245f3b9 1055 input.append("\t \t \t\n", 6);
7a4fa6a0
AJ
1056 struct resultSet expect = {
1057 .parsed = false,
36a9c964 1058 .needsMore = false,
7a4fa6a0
AJ
1059 .parserState = Http1::HTTP_PARSE_DONE,
1060 .status = Http::scBadRequest,
7a4fa6a0 1061 .suffixSz = input.length(),
3248e962 1062 .method = HttpRequestMethod(),
7a4fa6a0 1063 .uri = NULL,
7a4fa6a0
AJ
1064 .version = AnyP::ProtocolVersion()
1065 };
36a9c964 1066 output.clear();
7a4fa6a0
AJ
1067 testResults(__LINE__, input, output, expect);
1068 input.clear();
4245f3b9 1069 }
4c14658e 1070
947ca0c6 1071 // mixed whitespace line with CR
4245f3b9 1072 {
947ca0c6 1073 input.append("\r \t \n", 6);
7a4fa6a0
AJ
1074 struct resultSet expect = {
1075 .parsed = false,
36a9c964 1076 .needsMore = false,
7a4fa6a0
AJ
1077 .parserState = Http1::HTTP_PARSE_DONE,
1078 .status = Http::scBadRequest,
7a4fa6a0 1079 .suffixSz = input.length(),
7a4fa6a0 1080 .method = HttpRequestMethod(),
7a4fa6a0 1081 .uri = NULL,
7a4fa6a0
AJ
1082 .version = AnyP::ProtocolVersion()
1083 };
36a9c964 1084 output.clear();
7a4fa6a0
AJ
1085 testResults(__LINE__, input, output, expect);
1086 input.clear();
4245f3b9 1087 }
4c14658e 1088}
b6a7fc85
AJ
1089
1090void
bb86dcd4 1091testHttp1Parser::testDripFeed()
b6a7fc85
AJ
1092{
1093 // Simulate a client drip-feeding Squid a few bytes at a time.
1094 // extend the size of the buffer from 0 bytes to full request length
1095 // calling the parser repeatedly as visible data grows.
1096
7a4fa6a0 1097 SBuf data;
ebbb125d 1098 data.append("\n\n\n\n\n\n\n\n\n\n\n\n", 12);
7a4fa6a0 1099 SBuf::size_type garbageEnd = data.length();
947ca0c6 1100 data.append("GET ", 4);
947ca0c6 1101 data.append("http://example.com/ ", 20);
947ca0c6 1102 data.append("HTTP/1.1\r\n", 10);
7a4fa6a0
AJ
1103 SBuf::size_type reqLineEnd = data.length() - 1;
1104 data.append("Host: example.com\r\n\r\n", 21);
1105 SBuf::size_type mimeEnd = data.length() - 1;
1106 data.append("...", 3); // trailer to catch mime EOS errors.
b6a7fc85 1107
78a63ed1 1108 SBuf ioBuf;
36a9c964 1109 Http1::RequestParser hp;
b6a7fc85 1110
78a63ed1
AJ
1111 // start with strict and move on to relaxed
1112 Config.onoff.relaxed_header_parser = 2;
7a4fa6a0
AJ
1113
1114 Config.maxRequestHeaderSize = 1024; // large enough to hold the test data.
1115
78a63ed1 1116 do {
7a4fa6a0 1117
78a63ed1
AJ
1118 // state of things we expect right now
1119 struct resultSet expect = {
1120 .parsed = false,
1121 .needsMore = true,
1122 .parserState = Http1::HTTP_PARSE_NONE,
1123 .status = Http::scNone,
1124 .suffixSz = 0,
1125 .method = HttpRequestMethod(),
1126 .uri = NULL,
1127 .version = AnyP::ProtocolVersion()
1128 };
f4880526 1129
78a63ed1
AJ
1130 ioBuf.clear(); // begins empty for each parser type
1131 hp.clear();
1132
1133 --Config.onoff.relaxed_header_parser;
1134
1135 for (SBuf::size_type pos = 0; pos <= data.length(); ++pos) {
1136
1137 // simulate reading one more byte
1138 ioBuf.append(data.substr(pos,1));
1139
1140 // strict does not permit the garbage prefix
1141 if (pos < garbageEnd && !Config.onoff.relaxed_header_parser) {
1142 ioBuf.clear();
1143 continue;
1144 }
1145
1146 // when the garbage is passed we expect to start seeing first-line bytes
1147 if (pos == garbageEnd)
1148 expect.parserState = Http1::HTTP_PARSE_FIRST;
1149
1150 // all points after garbage start to see accumulated bytes looking for end of current section
1151 if (pos >= garbageEnd)
1152 expect.suffixSz = ioBuf.length();
1153
78a63ed1
AJ
1154 // at end of request line expect to see method, URI, version details
1155 // and switch to seeking Mime header section
1156 if (pos == reqLineEnd) {
1157 expect.parserState = Http1::HTTP_PARSE_MIME;
1158 expect.suffixSz = 0; // and a checkpoint buffer reset
1159 expect.status = Http::scOkay;
1160 expect.method = HttpRequestMethod(Http::METHOD_GET);
1161 expect.uri = "http://example.com/";
1162 expect.version = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1);
1163 }
1164
1165 // one mime header is done we are expecting a new request
1166 // parse results say true and initial data is all gone from the buffer
1167 if (pos == mimeEnd) {
1168 expect.parsed = true;
1169 expect.needsMore = false;
1170 expect.suffixSz = 0; // and a checkpoint buffer reset
1171 }
1172
1173 testResults(__LINE__, ioBuf, hp, expect);
1174
1175 // sync the buffers like Squid does
1176 ioBuf = hp.remaining();
1177
1178 // Squid stops using the parser once it has parsed the first message.
1179 if (!hp.needsMoreData())
1180 break;
b6a7fc85
AJ
1181 }
1182
78a63ed1 1183 } while (Config.onoff.relaxed_header_parser);
7a4fa6a0 1184
b6a7fc85 1185}
f53969cc 1186