]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testHttp1Parser.cc
Shuffle request_header_max_size limit checks into RequestParser
[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/Http1Parser.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 void
36 testHttp1Parser::testParseRequestLineProtocols()
37 {
38 // ensure MemPools etc exist
39 globalSetup();
40
41 MemBuf input;
42 Http1::RequestParser output;
43 input.init();
44
45 // TEST: Do we comply with RFC 1945 section 5.1 ?
46 // TEST: Do we comply with RFC 2616 section 5.1 ?
47
48 // RFC 1945 : HTTP/0.9 simple-request
49 {
50 input.append("GET /\r\n", 7);
51 output.reset(input.content(), input.contentSize());
52 CPPUNIT_ASSERT_EQUAL(true, output.parse());
53 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
54 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
55 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
56 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
57 CPPUNIT_ASSERT_EQUAL(0,memcmp("GET /\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
58 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
59 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
60 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start], (output.req.m_end-output.req.m_start+1)));
61 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
62 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
63 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
64 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start], (output.req.u_end-output.req.u_start+1)));
65 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
66 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
67 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
68 input.reset();
69 }
70
71 // RFC 1945 : invalid HTTP/0.9 simple-request (only GET is valid)
72 #if 0
73 {
74 input.append("POST /\r\n", 7);
75 output.reset(input.content(), input.contentSize());
76 CPPUNIT_ASSERT_EQUAL(true, output.parse());
77 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
78 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
79 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
80 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
81 CPPUNIT_ASSERT_EQUAL(0,memcmp("POST /\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
82 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
83 CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
84 CPPUNIT_ASSERT_EQUAL(0, memcmp("POST", &output.buf[output.req.m_start], (output.req.m_end-output.req.m_start+1)));
85 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_POST), output.method_);
86 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
87 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
88 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start], (output.req.u_end-output.req.u_start+1)));
89 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
90 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
91 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
92 input.reset();
93 }
94 #endif
95
96 // RFC 1945 and 2616 : HTTP/1.0 request
97 {
98 input.append("GET / HTTP/1.0\r\n", 16);
99 output.reset(input.content(), input.contentSize());
100 CPPUNIT_ASSERT_EQUAL(false, output.parse());
101 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
102 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
103 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
104 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
105 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
106 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.0\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
107 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
108 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
109 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
110 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
111 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
112 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
113 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
114 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
115 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
116 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
117 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
118 input.reset();
119 }
120
121 // RFC 2616 : HTTP/1.1 request
122 {
123 input.append("GET / HTTP/1.1\r\n", 16);
124 output.reset(input.content(), input.contentSize());
125 CPPUNIT_ASSERT_EQUAL(false, output.parse());
126 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
127 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
128 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
129 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
130 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
131 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
132 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
133 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
134 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
135 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
136 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
137 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
138 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
139 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
140 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
141 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
142 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
143 input.reset();
144 }
145
146 // RFC 2616 : future version full-request
147 {
148 input.append("GET / HTTP/1.2\r\n", 16);
149 //printf("TEST: '%s'\n",input.content());
150 output.reset(input.content(), input.contentSize());
151 CPPUNIT_ASSERT_EQUAL(false, output.parse());
152 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
153 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
154 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
155 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
156 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
157 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.2\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
158 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
159 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
160 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
161 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
162 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
163 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
164 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
165 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
166 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
167 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.2", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
168 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,2), output.msgProtocol_);
169 input.reset();
170 }
171
172 // RFC 2616 : future version full-request
173 {
174 // IETF HTTPbis WG has made this two-digits format invalid.
175 // it gets treated same as HTTP/0.9 for now
176 input.append("GET / HTTP/10.12\r\n", 18);
177 //printf("TEST: '%s'\n",input.content());
178 output.reset(input.content(), input.contentSize());
179 CPPUNIT_ASSERT_EQUAL(true, output.parse()); // BUG: declares true
180 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
181 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
182 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
183 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
184 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/10.12\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
185 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
186 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
187 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
188 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
189 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
190 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
191 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
192 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
193 CPPUNIT_ASSERT_EQUAL(15, output.req.v_end);
194 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/10.12", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
195 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,10,12), output.msgProtocol_);
196 input.reset();
197 }
198
199 // This stage of the parser does not yet accept non-HTTP protocol names.
200 {
201 // violations mode treats them as HTTP/0.9 requests!
202 input.append("GET / FOO/1.0\n", 14);
203 //printf("TEST: '%s'\n",input.content());
204 output.reset(input.content(), input.contentSize());
205 #if USE_HTTP_VIOLATIONS
206 CPPUNIT_ASSERT_EQUAL(true, output.parse());
207 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
208 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
209 CPPUNIT_ASSERT_EQUAL(12, output.req.u_end);
210 CPPUNIT_ASSERT_EQUAL(0, memcmp("/ FOO/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
211 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
212 #else
213 CPPUNIT_ASSERT_EQUAL(false, output.parse());
214 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
215 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
216 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
217 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
218 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
219 #endif
220 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
221 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
222 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / FOO/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
223 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
224 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
225 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
226 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
227 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
228 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
229 CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
230 CPPUNIT_ASSERT_EQUAL(0, memcmp("FOO/1.0", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
231 input.reset();
232 }
233
234 // no version
235 {
236 input.append("GET / HTTP/\n", 12);
237 //printf("TEST: '%s'\n",input.content());
238 output.reset(input.content(), input.contentSize());
239 CPPUNIT_ASSERT_EQUAL(false, output.parse());
240 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
241 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
242 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
243 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
244 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
245 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
246 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
247 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
248 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
249 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
250 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
251 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
252 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
253 CPPUNIT_ASSERT_EQUAL(10, output.req.v_end);
254 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
255 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
256 input.reset();
257 }
258
259 // no major version
260 {
261 input.append("GET / HTTP/.1\n", 14);
262 //printf("TEST: '%s'\n",input.content());
263 output.reset(input.content(), input.contentSize());
264 CPPUNIT_ASSERT_EQUAL(false, output.parse());
265 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
266 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
267 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
268 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
269 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
270 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
271 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
272 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
273 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
274 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
275 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
276 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
277 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
278 CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
279 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
280 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
281 input.reset();
282 }
283
284 // no version dot
285 {
286 input.append("GET / HTTP/11\n", 14);
287 //printf("TEST: '%s'\n",input.content());
288 output.reset(input.content(), input.contentSize());
289 CPPUNIT_ASSERT_EQUAL(false, output.parse());
290 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
291 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
292 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
293 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
294 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/11\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
295 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
296 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
297 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
298 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
299 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
300 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
301 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
302 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
303 CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
304 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/11", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
305 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
306 input.reset();
307 }
308
309 // negative major version (bug 3062)
310 {
311 input.append("GET / HTTP/-999999.1\n", 21);
312 //printf("TEST: '%s'\n",input.content());
313 output.reset(input.content(), input.contentSize());
314 CPPUNIT_ASSERT_EQUAL(false, output.parse());
315 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
316 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
317 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
318 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
319 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/-999999.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
320 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
321 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
322 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
323 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
324 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
325 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
326 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
327 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
328 CPPUNIT_ASSERT_EQUAL(19, output.req.v_end);
329 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/-999999.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
330 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,0), output.msgProtocol_);
331 input.reset();
332 }
333
334 // no minor version
335 {
336 input.append("GET / HTTP/1.\n", 14);
337 //printf("TEST: '%s'\n",input.content());
338 output.reset(input.content(), input.contentSize());
339 CPPUNIT_ASSERT_EQUAL(false, output.parse());
340 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
341 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
342 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
343 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
344 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
345 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
346 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
347 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
348 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
349 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
350 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
351 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
352 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
353 CPPUNIT_ASSERT_EQUAL(12, output.req.v_end);
354 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
355 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
356 input.reset();
357 }
358
359 // negative major version (bug 3062 corollary)
360 {
361 input.append("GET / HTTP/1.-999999\n", 21);
362 //printf("TEST: '%s'\n",input.content());
363 output.reset(input.content(), input.contentSize());
364 CPPUNIT_ASSERT_EQUAL(false, output.parse());
365 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
366 CPPUNIT_ASSERT_EQUAL(Http::scHttpVersionNotSupported, output.request_parse_status);
367 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
368 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
369 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.-999999\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
370 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
371 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
372 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
373 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
374 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
375 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
376 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
377 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
378 CPPUNIT_ASSERT_EQUAL(19, output.req.v_end);
379 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.-999999", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
380 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,0), output.msgProtocol_);
381 input.reset();
382 }
383 }
384
385 void
386 testHttp1Parser::testParseRequestLineStrange()
387 {
388 // ensure MemPools etc exist
389 globalSetup();
390
391 MemBuf input;
392 Http1::RequestParser output;
393 input.init();
394
395 // space padded URL
396 {
397 input.append("GET / HTTP/1.1\r\n", 21);
398 //printf("TEST: '%s'\n",input.content());
399 output.reset(input.content(), input.contentSize());
400 CPPUNIT_ASSERT_EQUAL(false, output.parse());
401 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
402 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
403 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
404 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
405 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
406 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
407 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
408 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
409 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
410 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
411 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
412 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
413 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
414 CPPUNIT_ASSERT_EQUAL(11, output.req.v_start);
415 CPPUNIT_ASSERT_EQUAL(18, output.req.v_end);
416 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
417 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
418 input.reset();
419 }
420
421 // whitespace inside URI. (nasty but happens)
422 {
423 input.append("GET /fo o/ HTTP/1.1\n", 20);
424 //printf("TEST: '%s'\n",input.content());
425 output.reset(input.content(), input.contentSize());
426 CPPUNIT_ASSERT_EQUAL(false, output.parse());
427 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
428 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
429 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
430 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
431 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
432 CPPUNIT_ASSERT_EQUAL(0,memcmp("GET /fo o/ HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
433 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
434 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
435 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
436 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
437 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
438 CPPUNIT_ASSERT_EQUAL(9, output.req.u_end);
439 CPPUNIT_ASSERT_EQUAL(0, memcmp("/fo o/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
440 CPPUNIT_ASSERT_EQUAL(11, output.req.v_start);
441 CPPUNIT_ASSERT_EQUAL(18, output.req.v_end);
442 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
443 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
444 input.reset();
445 }
446
447 // additional data in buffer
448 {
449 input.append("GET / HTTP/1.1\nboo!", 23);
450 //printf("TEST: '%s'\n",input.content());
451 output.reset(input.content(), input.contentSize());
452 CPPUNIT_ASSERT_EQUAL(false, output.parse());
453 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
454 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
455 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
456 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
457 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-5, output.req.end);
458 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
459 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
460 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
461 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
462 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
463 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
464 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end); // strangeness generated by following RFC
465 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
466 CPPUNIT_ASSERT_EQUAL(10, output.req.v_start);
467 CPPUNIT_ASSERT_EQUAL(17, output.req.v_end);
468 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
469 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
470 input.reset();
471 }
472 }
473
474 void
475 testHttp1Parser::testParseRequestLineTerminators()
476 {
477 // ensure MemPools etc exist
478 globalSetup();
479
480 MemBuf input;
481 Http1::RequestParser output;
482 input.init();
483
484 // alternative EOL sequence: NL-only
485 {
486 input.append("GET / HTTP/1.1\n", 15);
487 //printf("TEST: '%s'\n",input.content());
488 output.reset(input.content(), input.contentSize());
489 CPPUNIT_ASSERT_EQUAL(false, output.parse());
490 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
491 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
492 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
493 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
494 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
495 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
496 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
497 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
498 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
499 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
500 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
501 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
502 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
503 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
504 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
505 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
506 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
507 input.reset();
508 }
509
510 // alternative EOL sequence: double-NL-only
511 {
512 input.append("GET / HTTP/1.1\n\n", 16);
513 //printf("TEST: '%s'\n",input.content());
514 output.reset(input.content(), input.contentSize());
515 CPPUNIT_ASSERT_EQUAL(true, output.parse());
516 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
517 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
518 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
519 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-2, output.req.end);
520 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
521 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
522 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
523 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
524 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
525 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
526 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
527 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
528 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
529 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
530 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
531 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
532 input.reset();
533 }
534
535 // RELAXED alternative EOL sequence: multi-CR-NL
536 {
537 input.append("GET / HTTP/1.1\r\r\r\n", 18);
538 //printf("TEST: '%s'\n",input.content());
539 output.reset(input.content(), input.contentSize());
540 Config.onoff.relaxed_header_parser = 1;
541 // Being tolerant we can ignore and elide these apparently benign CR
542 CPPUNIT_ASSERT_EQUAL(false, output.parse());
543 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
544 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
545 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
546 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
547 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
548 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\r\r\r\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
549 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
550 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
551 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
552 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
553 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
554 CPPUNIT_ASSERT_EQUAL(4, output.req.u_end);
555 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
556 CPPUNIT_ASSERT_EQUAL(6, output.req.v_start);
557 CPPUNIT_ASSERT_EQUAL(13, output.req.v_end);
558 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
559 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
560 input.reset();
561 Config.onoff.relaxed_header_parser = 0;
562 }
563
564 // STRICT alternative EOL sequence: multi-CR-NL
565 {
566 input.append("GET / HTTP/1.1\r\r\r\n", 18);
567 //printf("TEST: '%s'\n",input.content());
568 output.reset(input.content(), input.contentSize());
569 // strict mode treats these as several bare-CR in the request line which is explicitly invalid.
570 Config.onoff.relaxed_header_parser = 0;
571 CPPUNIT_ASSERT_EQUAL(false, output.parse());
572 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
573 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
574 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
575 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
576 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
577 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
578 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
579 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
580 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
581 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
582 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
583 input.reset();
584 }
585
586 // space padded version
587 {
588 // RFC 1945 and 2616 specify version is followed by CRLF. No intermediary bytes.
589 // NP: the terminal whitespace is a special case: invalid for even HTTP/0.9 with no version tag
590 input.append("GET / HTTP/1.1 \n", 16);
591 //printf("TEST: '%s'\n",input.content());
592 output.reset(input.content(), input.contentSize());
593 CPPUNIT_ASSERT_EQUAL(false, output.parse());
594 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
595 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
596 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
597 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
598 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1 \n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
599 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
600 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
601 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
602 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
603 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
604 CPPUNIT_ASSERT_EQUAL(13, output.req.u_end);
605 CPPUNIT_ASSERT_EQUAL(0, memcmp("/ HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
606 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
607 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
608 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
609 input.reset();
610 }
611
612 // incomplete line at various positions
613 {
614 input.append("GET", 3);
615 //printf("TEST: '%s'\n",input.content());
616 output.reset(input.content(), input.contentSize());
617 CPPUNIT_ASSERT_EQUAL(false, output.parse());
618 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
619 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
620 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
621 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
622 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
623 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
624 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
625 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
626 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
627 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
628 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
629 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
630 input.reset();
631
632 input.append("GET ", 4);
633 //printf("TEST: '%s'\n",input.content());
634 output.reset(input.content(), input.contentSize());
635 CPPUNIT_ASSERT_EQUAL(false, output.parse());
636 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
637 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
638 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
639 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
640 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
641 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
642 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
643 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
644 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
645 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
646 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
647 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
648 input.reset();
649
650 input.append("GET / HT", 8);
651 //printf("TEST: '%s'\n",input.content());
652 output.reset(input.content(), input.contentSize());
653 CPPUNIT_ASSERT_EQUAL(false, output.parse());
654 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
655 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
656 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
657 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
658 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
659 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
660 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
661 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
662 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
663 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
664 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
665 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
666 input.reset();
667
668 input.append("GET / HTTP/1.1", 14);
669 //printf("TEST: '%s'\n",input.content());
670 output.reset(input.content(), input.contentSize());
671 CPPUNIT_ASSERT_EQUAL(false, output.parse());
672 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
673 CPPUNIT_ASSERT_EQUAL(Http::scNone, output.request_parse_status);
674 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
675 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
676 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
677 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
678 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
679 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
680 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
681 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
682 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
683 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
684 input.reset();
685 }
686 }
687
688 void
689 testHttp1Parser::testParseRequestLineMethods()
690 {
691 // ensure MemPools etc exist
692 globalSetup();
693
694 MemBuf input;
695 Http1::RequestParser output;
696 input.init();
697
698 // RFC 2616 : . method
699 {
700 input.append(". / HTTP/1.1\n", 13);
701 //printf("TEST: '%s'\n",input.content());
702 output.reset(input.content(), input.contentSize());
703 CPPUNIT_ASSERT_EQUAL(false, output.parse());
704 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
705 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
706 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
707 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
708 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
709 CPPUNIT_ASSERT_EQUAL(0, memcmp(". / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
710 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
711 CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
712 CPPUNIT_ASSERT_EQUAL(0, memcmp(".", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
713 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(".", NULL), output.method_);
714 CPPUNIT_ASSERT_EQUAL(2, output.req.u_start);
715 CPPUNIT_ASSERT_EQUAL(2, output.req.u_end);
716 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
717 CPPUNIT_ASSERT_EQUAL(4, output.req.v_start);
718 CPPUNIT_ASSERT_EQUAL(11, output.req.v_end);
719 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
720 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
721 input.reset();
722 }
723
724 // OPTIONS with * URL
725 {
726 input.append("OPTIONS * HTTP/1.1\n", 19);
727 //printf("TEST: '%s'\n",input.content());
728 output.reset(input.content(), input.contentSize());
729 CPPUNIT_ASSERT_EQUAL(false, output.parse());
730 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
731 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
732 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
733 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
734 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
735 CPPUNIT_ASSERT_EQUAL(0, memcmp("OPTIONS * HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
736 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
737 CPPUNIT_ASSERT_EQUAL(6, output.req.m_end);
738 CPPUNIT_ASSERT_EQUAL(0, memcmp("OPTIONS", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
739 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_OPTIONS), output.method_);
740 CPPUNIT_ASSERT_EQUAL(8, output.req.u_start);
741 CPPUNIT_ASSERT_EQUAL(8, output.req.u_end);
742 CPPUNIT_ASSERT_EQUAL(0, memcmp("*", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
743 CPPUNIT_ASSERT_EQUAL(10, output.req.v_start);
744 CPPUNIT_ASSERT_EQUAL(17, output.req.v_end);
745 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
746 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
747 input.reset();
748 }
749
750 // unknown method
751 {
752 input.append("HELLOWORLD / HTTP/1.1\n", 22);
753 //printf("TEST: '%s'\n",input.content());
754 output.reset(input.content(), input.contentSize());
755 CPPUNIT_ASSERT_EQUAL(false, output.parse());
756 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
757 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
758 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
759 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
760 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
761 CPPUNIT_ASSERT_EQUAL(0, memcmp("HELLOWORLD / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
762 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
763 CPPUNIT_ASSERT_EQUAL(9, output.req.m_end);
764 CPPUNIT_ASSERT_EQUAL(0, memcmp("HELLOWORLD", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
765 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("HELLOWORLD",NULL), output.method_);
766 CPPUNIT_ASSERT_EQUAL(11, output.req.u_start);
767 CPPUNIT_ASSERT_EQUAL(11, output.req.u_end);
768 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
769 CPPUNIT_ASSERT_EQUAL(13, output.req.v_start);
770 CPPUNIT_ASSERT_EQUAL(20, output.req.v_end);
771 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
772 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
773 input.reset();
774 }
775
776 // method-only
777 {
778 input.append("A\n", 2);
779 //printf("TEST: '%s'\n",input.content());
780 output.reset(input.content(), input.contentSize());
781 CPPUNIT_ASSERT_EQUAL(false, output.parse());
782 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
783 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
784 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
785 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
786 CPPUNIT_ASSERT_EQUAL(0, memcmp("A\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
787 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
788 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
789 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
790 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
791 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
792 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
793 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
794 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
795 input.reset();
796 }
797
798 input.append("GET\n", 4);
799 {
800 //printf("TEST: '%s'\n",input.content());
801 output.reset(input.content(), input.contentSize());
802 CPPUNIT_ASSERT_EQUAL(false, output.parse());
803 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
804 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
805 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
806 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
807 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
808 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
809 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
810 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
811 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
812 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
813 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
814 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
815 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
816 input.reset();
817 }
818
819 // RELAXED space padded method (in strict mode SP is reserved so invalid as a method byte)
820 {
821 input.append(" GET / HTTP/1.1\n", 16);
822 //printf("TEST: '%s'\n",input.content());
823 output.reset(input.content(), input.contentSize());
824 Config.onoff.relaxed_header_parser = 1;
825 CPPUNIT_ASSERT_EQUAL(false, output.parse());
826 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
827 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
828 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
829 CPPUNIT_ASSERT_EQUAL(1, output.req.start);
830 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
831 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
832 CPPUNIT_ASSERT_EQUAL(1, output.req.m_start);
833 CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
834 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
835 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
836 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
837 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
838 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
839 CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
840 CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
841 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
842 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
843 input.reset();
844 Config.onoff.relaxed_header_parser = 0;
845 }
846
847 // STRICT space padded method (in strict mode SP is reserved so invalid as a method byte)
848 {
849 input.append(" GET / HTTP/1.1\n", 16);
850 //printf("TEST: '%s'\n",input.content());
851 output.reset(input.content(), input.contentSize());
852 Config.onoff.relaxed_header_parser = 0;
853 CPPUNIT_ASSERT_EQUAL(false, output.parse());
854 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
855 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
856 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
857 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
858 CPPUNIT_ASSERT_EQUAL(0, memcmp(" GET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
859 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
860 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
861 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
862 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
863 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
864 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
865 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
866 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
867 input.reset();
868 }
869
870 // tab padded method (NP: tab is not SP so treated as any other binary)
871 {
872 input.append("\tGET / HTTP/1.1\n", 16);
873 //printf("TEST: '%s'\n",input.content());
874 output.reset(input.content(), input.contentSize());
875 CPPUNIT_ASSERT_EQUAL(false, output.parse());
876 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
877 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
878 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
879 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
880 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
881 CPPUNIT_ASSERT_EQUAL(0, memcmp("\tGET / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
882 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
883 CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
884 CPPUNIT_ASSERT_EQUAL(0, memcmp("\tGET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
885 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(&output.buf[output.req.m_start],&output.buf[output.req.m_end+1]), output.method_);
886 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
887 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
888 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
889 CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
890 CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
891 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
892 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
893 input.reset();
894 }
895 }
896
897 void
898 testHttp1Parser::testParseRequestLineInvalid()
899 {
900 // ensure MemPools etc exist
901 globalSetup();
902
903 MemBuf input;
904 Http1::RequestParser output;
905 input.init();
906
907 // no method (but in a form which is ambiguous with HTTP/0.9 simple-request)
908 {
909 // XXX: Bug: HTTP/0.9 requires method to be "GET"
910 input.append("/ HTTP/1.0\n", 11);
911 //printf("TEST: '%s'\n",input.content());
912 output.reset(input.content(), input.contentSize());
913 CPPUNIT_ASSERT_EQUAL(true, output.parse());
914 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
915 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
916 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
917 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
918 CPPUNIT_ASSERT_EQUAL(0, memcmp("/ HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
919 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
920 CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
921 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
922 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("/",NULL), output.method_);
923 CPPUNIT_ASSERT_EQUAL(2, output.req.u_start);
924 CPPUNIT_ASSERT_EQUAL(9, output.req.u_end);
925 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
926 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
927 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
928 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
929 input.reset();
930 }
931
932 // RELAXED no method (an invalid format)
933 {
934 input.append(" / HTTP/1.0\n", 12);
935 //printf("TEST: '%s'\n",input.content());
936 output.reset(input.content(), input.contentSize());
937 // BUG: When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
938 Config.onoff.relaxed_header_parser = 1;
939 CPPUNIT_ASSERT_EQUAL(true, output.parse());
940 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
941 // CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_NEW, output.completedState_);
942 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
943 CPPUNIT_ASSERT_EQUAL(1, output.req.start);
944 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
945 CPPUNIT_ASSERT_EQUAL(0, memcmp("/ HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
946 CPPUNIT_ASSERT_EQUAL(1, output.req.m_start);
947 CPPUNIT_ASSERT_EQUAL(1, output.req.m_end);
948 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
949 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("/",NULL), output.method_);
950 CPPUNIT_ASSERT_EQUAL(3, output.req.u_start);
951 CPPUNIT_ASSERT_EQUAL(10, output.req.u_end);
952 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.0", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
953 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
954 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
955 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
956 input.reset();
957 Config.onoff.relaxed_header_parser = 0;
958 }
959
960 // STRICT no method (an invalid format)
961 {
962 input.append(" / HTTP/1.0\n", 12);
963 //printf("TEST: '%s'\n",input.content());
964 output.reset(input.content(), input.contentSize());
965 // When tolerantly ignoring SP prefix this case becomes ambiguous with HTTP/0.9 simple-request)
966 Config.onoff.relaxed_header_parser = 0;
967 CPPUNIT_ASSERT_EQUAL(false, output.parse());
968 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
969 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
970 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
971 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
972 CPPUNIT_ASSERT_EQUAL(0, memcmp(" / HTTP/1.0\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
973 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
974 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
975 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
976 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
977 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
978 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
979 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
980 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_NONE,0,0), output.msgProtocol_);
981 input.reset();
982 }
983
984 // binary code in method (strange but ...)
985 {
986 input.append("GET\x0B / HTTP/1.1\n", 16);
987 //printf("TEST: %d-%d/%d '%.*s'\n", output.req.start, output.req.end, input.contentSize(), 16, input.content());
988 output.reset(input.content(), input.contentSize());
989 CPPUNIT_ASSERT_EQUAL(false, output.parse());
990 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
991 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
992 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
993 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
994 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
995 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\x0B / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
996 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
997 CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
998 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\x0B", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
999 // CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("GET\0x0B",NULL), output.method_);
1000 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
1001 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
1002 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
1003 CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
1004 CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
1005 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
1006 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
1007 input.reset();
1008 }
1009
1010 // CR in method
1011 {
1012 // RFC 2616 sec 5.1 prohibits CR other than in terminator.
1013 input.append("GET\r / HTTP/1.1\r\n", 16);
1014 //printf("TEST: '%s'\n",input.content());
1015 output.reset(input.content(), input.contentSize());
1016 CPPUNIT_ASSERT_EQUAL(false, output.parse());
1017 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1018 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
1019 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1020 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
1021 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
1022 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
1023 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
1024 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
1025 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
1026 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1027 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1028 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
1029 input.reset();
1030 }
1031
1032 // binary code NUL! in method (strange but ...)
1033 {
1034 input.append("GET\0 / HTTP/1.1\n", 16);
1035 //printf("TEST: %d-%d/%d '%.*s'\n", output.req.start, output.req.end, input.contentSize(), 16, input.content());
1036 output.reset(input.content(), input.contentSize());
1037 CPPUNIT_ASSERT_EQUAL(false, output.parse());
1038 CPPUNIT_ASSERT_EQUAL(false, output.isDone());
1039 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, output.completedState_);
1040 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
1041 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1042 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
1043 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\0 / HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
1044 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
1045 CPPUNIT_ASSERT_EQUAL(3, output.req.m_end);
1046 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET\0", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
1047 // CPPUNIT_ASSERT_EQUAL(HttpRequestMethod("GET\0",NULL), output.method_);
1048 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
1049 CPPUNIT_ASSERT_EQUAL(5, output.req.u_end);
1050 CPPUNIT_ASSERT_EQUAL(0, memcmp("/", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
1051 CPPUNIT_ASSERT_EQUAL(7, output.req.v_start);
1052 CPPUNIT_ASSERT_EQUAL(14, output.req.v_end);
1053 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.v_start],(output.req.v_end-output.req.v_start+1)));
1054 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1), output.msgProtocol_);
1055 input.reset();
1056 }
1057
1058 // no URL (grammer otherwise correct)
1059 {
1060 input.append("GET HTTP/1.1\n", 14);
1061 //printf("TEST: '%s'\n",input.content());
1062 output.reset(input.content(), input.contentSize());
1063 CPPUNIT_ASSERT_EQUAL(true, output.parse());
1064 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1065 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
1066 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1067 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
1068 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
1069 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
1070 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
1071 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
1072 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
1073 CPPUNIT_ASSERT_EQUAL(5, output.req.u_start);
1074 CPPUNIT_ASSERT_EQUAL(12, output.req.u_end);
1075 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1076 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
1077 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1078 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
1079 input.reset();
1080 }
1081
1082 // no URL (grammer invalid, ambiguous with RFC 1945 HTTP/0.9 simple-request)
1083 {
1084 input.append("GET HTTP/1.1\n", 13);
1085 //printf("TEST: '%s'\n",input.content());
1086 output.reset(input.content(), input.contentSize());
1087 CPPUNIT_ASSERT_EQUAL(true, output.parse());
1088 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1089 CPPUNIT_ASSERT_EQUAL(Http::scOkay, output.request_parse_status);
1090 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1091 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
1092 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET HTTP/1.1\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
1093 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
1094 CPPUNIT_ASSERT_EQUAL(2, output.req.m_end);
1095 CPPUNIT_ASSERT_EQUAL(0, memcmp("GET", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
1096 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(Http::METHOD_GET), output.method_);
1097 CPPUNIT_ASSERT_EQUAL(4, output.req.u_start);
1098 CPPUNIT_ASSERT_EQUAL(11, output.req.u_end);
1099 CPPUNIT_ASSERT_EQUAL(0, memcmp("HTTP/1.1", &output.buf[output.req.u_start],(output.req.u_end-output.req.u_start+1)));
1100 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1101 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1102 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(AnyP::PROTO_HTTP,0,9), output.msgProtocol_);
1103 input.reset();
1104 }
1105
1106 // binary line
1107 {
1108 input.append("\xB\xC\xE\xF\n", 5);
1109 //printf("TEST: binary-line\n");
1110 output.reset(input.content(), input.contentSize());
1111 CPPUNIT_ASSERT_EQUAL(false, output.parse());
1112 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1113 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
1114 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1115 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
1116 CPPUNIT_ASSERT_EQUAL(0, memcmp("\xB\xC\xE\xF\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
1117 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
1118 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
1119 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
1120 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
1121 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
1122 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1123 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1124 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
1125 input.reset();
1126 }
1127
1128 // mixed whitespace line
1129 {
1130 // We accept non-space binary bytes for method so first \t shows up as that
1131 // but remaining space and tabs are skipped searching for URI-start
1132 input.append("\t \t \t\n", 6);
1133 //printf("TEST: mixed whitespace\n");
1134 output.reset(input.content(), input.contentSize());
1135 CPPUNIT_ASSERT_EQUAL(false, output.parse());
1136 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1137 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
1138 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1139 CPPUNIT_ASSERT_EQUAL((int)input.contentSize()-1, output.req.end);
1140 CPPUNIT_ASSERT_EQUAL(0, memcmp("\t \t \t\n", &output.buf[output.req.start],(output.req.end-output.req.start+1)));
1141 CPPUNIT_ASSERT_EQUAL(0, output.req.m_start);
1142 CPPUNIT_ASSERT_EQUAL(0, output.req.m_end);
1143 CPPUNIT_ASSERT_EQUAL(0, memcmp("\t", &output.buf[output.req.m_start],(output.req.m_end-output.req.m_start+1)));
1144 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(&output.buf[output.req.m_start],&output.buf[output.req.m_end+1]), output.method_);
1145 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
1146 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
1147 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1148 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1149 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
1150 input.reset();
1151 }
1152
1153 // mixed whitespace line with CR middle
1154 {
1155 // CR aborts on sight, so even initial \t method is not marked as above
1156 // (not when parsing clean with whole line available anyway)
1157 input.append("\t \r \n", 6);
1158 //printf("TEST: mixed whitespace with CR\n");
1159 output.reset(input.content(), input.contentSize());
1160 CPPUNIT_ASSERT_EQUAL(false, output.parse());
1161 CPPUNIT_ASSERT_EQUAL(true, output.isDone());
1162 CPPUNIT_ASSERT_EQUAL(Http::scBadRequest, output.request_parse_status);
1163 CPPUNIT_ASSERT_EQUAL(0, output.req.start);
1164 CPPUNIT_ASSERT_EQUAL(-1, output.req.end);
1165 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_start);
1166 CPPUNIT_ASSERT_EQUAL(-1, output.req.m_end);
1167 CPPUNIT_ASSERT_EQUAL(HttpRequestMethod(), output.method_);
1168 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_start);
1169 CPPUNIT_ASSERT_EQUAL(-1, output.req.u_end);
1170 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_start);
1171 CPPUNIT_ASSERT_EQUAL(-1, output.req.v_end);
1172 CPPUNIT_ASSERT_EQUAL(AnyP::ProtocolVersion(), output.msgProtocol_);
1173 input.reset();
1174 }
1175 }
1176
1177 void
1178 testHttp1Parser::testDripFeed()
1179 {
1180 // Simulate a client drip-feeding Squid a few bytes at a time.
1181 // extend the size of the buffer from 0 bytes to full request length
1182 // calling the parser repeatedly as visible data grows.
1183
1184 MemBuf mb;
1185 mb.init(1024, 1024);
1186 mb.append(" ", 12);
1187 int garbageEnd = mb.contentSize();
1188 mb.append("GET http://example.com/ HTTP/1.1\r\n", 34);
1189 int reqLineEnd = mb.contentSize();
1190 mb.append("Host: example.com\r\n\r\n.", 22);
1191
1192 Http1::RequestParser hp(mb.content(), 0);
1193
1194 // only relaxed parser accepts the garbage whitespace
1195 Config.onoff.relaxed_header_parser = 1;
1196
1197 for (; hp.bufsiz <= mb.contentSize(); ++hp.bufsiz) {
1198 bool parseResult = hp.parse();
1199
1200 #if WHEN_TEST_DEBUG_IS_NEEDED
1201 printf("%d/%d :: %d, %d, %d '%c'\n", hp.bufsiz, mb.contentSize(),
1202 garbageEnd, reqLineEnd, parseResult,
1203 mb.content()[hp.bufsiz]);
1204 #endif
1205
1206 // before end of garbage found its a moving offset.
1207 if (hp.bufsiz < garbageEnd) {
1208 CPPUNIT_ASSERT_EQUAL(hp.bufsiz, (int)hp.parseOffset_);
1209 CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
1210 continue;
1211 }
1212
1213 // before request line found, parse announces incomplete
1214 if (hp.bufsiz < reqLineEnd) {
1215 CPPUNIT_ASSERT_EQUAL(garbageEnd, (int)hp.parseOffset_);
1216 CPPUNIT_ASSERT_EQUAL(false, parseResult);
1217 CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
1218 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_NEW, hp.completedState_);
1219 continue;
1220 }
1221
1222 // before request headers entirely found, parse announces incomplete
1223 if (hp.bufsiz < mb.contentSize()-1) {
1224 CPPUNIT_ASSERT_EQUAL(reqLineEnd, (int)hp.parseOffset_);
1225 CPPUNIT_ASSERT_EQUAL(false, parseResult);
1226 CPPUNIT_ASSERT_EQUAL(false, hp.isDone());
1227 // TODO: add all the other usual tests for request-line details
1228 CPPUNIT_ASSERT_EQUAL((uint8_t)HTTP_PARSE_FIRST, hp.completedState_);
1229 continue;
1230 }
1231
1232 // once request line is found (AND the following \n) current parser announces success
1233 CPPUNIT_ASSERT_EQUAL(reqLineEnd, (int)hp.parseOffset_);
1234 CPPUNIT_ASSERT_EQUAL(true, parseResult);
1235 CPPUNIT_ASSERT_EQUAL(true, hp.isDone());
1236 }
1237 }