1
2 /*
3 * Copyright (C) NGINX, Inc.
4 * Copyright (C) Valentin V. Bartenev
5 */
6
7 #include <nxt_main.h>
8 #include "nxt_tests.h"
9
10
11 typedef struct {
12 nxt_str_t method;
13 nxt_str_t target;
14 nxt_str_t args;
15 u_char version[8];
16
17 /* target with "/." */
18 unsigned complex_target:1;
19 /* target with "%" */
20 unsigned quoted_target:1;
21 /* target with " " */
22 unsigned space_in_target:1;
23 } nxt_http_parse_test_request_line_t;
24
25
26 typedef struct {
27 nxt_int_t result;
28 unsigned discard_unsafe_fields:1;
29 } nxt_http_parse_test_fields_t;
30
31
32 typedef union {
33 void *pointer;
34 nxt_http_parse_test_fields_t fields;
35 nxt_http_parse_test_request_line_t request_line;
36 } nxt_http_parse_test_data_t;
37
38
39 typedef struct {
40 nxt_str_t request;
41 nxt_int_t result;
42 nxt_int_t (*handler)(nxt_http_request_parse_t *rp,
43 nxt_http_parse_test_data_t *data,
44 nxt_str_t *request, nxt_log_t *log);
45
46 nxt_http_parse_test_data_t data;
47 } nxt_http_parse_test_case_t;
48
49
50 static nxt_int_t nxt_http_parse_test_run(nxt_http_request_parse_t *rp,
51 nxt_str_t *request);
52 static nxt_int_t nxt_http_parse_test_bench(nxt_thread_t *thr,
53 nxt_str_t *request, nxt_lvlhsh_t *hash, const char *name, nxt_uint_t n);
54 static nxt_int_t nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp,
55 nxt_http_parse_test_data_t *data,
56 nxt_str_t *request, nxt_log_t *log);
57 static nxt_int_t nxt_http_parse_test_fields(nxt_http_request_parse_t *rp,
58 nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log);
59
60
61 static nxt_int_t nxt_http_test_header_return(void *ctx, nxt_http_field_t *field,
62 uintptr_t data);
63
64
65 static nxt_http_parse_test_case_t nxt_http_test_cases[] = {
66 {
67 nxt_string("GET / HTTP/1.0\r\n\r\n"),
68 NXT_DONE,
69 &nxt_http_parse_test_request_line,
70 { .request_line = {
71 nxt_string("GET"),
72 nxt_string("/"),
73 nxt_null_string,
74 "HTTP/1.0",
75 0, 0, 0
76 }}
77 },
78 {
79 nxt_string("XXX-METHOD /d.ir/fi+le.ext?key=val HTTP/1.2\n\n"),
80 NXT_DONE,
81 &nxt_http_parse_test_request_line,
82 { .request_line = {
83 nxt_string("XXX-METHOD"),
84 nxt_string("/d.ir/fi+le.ext?key=val"),
85 nxt_string("key=val"),
86 "HTTP/1.2",
87 0, 0, 0
88 }}
89 },
90 {
91 nxt_string("GET /di.r/? HTTP/1.0\r\n\r\n"),
92 NXT_DONE,
93 &nxt_http_parse_test_request_line,
94 { .request_line = {
95 nxt_string("GET"),
96 nxt_string("/di.r/?"),
97 nxt_string(""),
98 "HTTP/1.0",
99 0, 0, 0
100 }}
101 },
102 {
103 nxt_string("GEt / HTTP/1.0\r\n\r\n"),
104 NXT_HTTP_PARSE_INVALID,
105 NULL, { NULL }
106 },
107 {
108 nxt_string("GET /\0 HTTP/1.0\r\n\r\n"),
109 NXT_HTTP_PARSE_INVALID,
110 NULL, { NULL }
111 },
112 {
113 nxt_string("GET /\r HTTP/1.0\r\n\r\n"),
114 NXT_HTTP_PARSE_INVALID,
115 NULL, { NULL }
116 },
117 {
118 nxt_string("GET /\n HTTP/1.0\r\n\r\n"),
119 NXT_HTTP_PARSE_INVALID,
120 NULL, { NULL }
121 },
122 {
123 nxt_string("GET / HTTP/1.0\r\r\n"),
124 NXT_HTTP_PARSE_INVALID,
125 NULL, { NULL }
126 },
127 {
128 nxt_string("GET / HTTP/2.0\r\n"),
129 NXT_HTTP_PARSE_UNSUPPORTED_VERSION,
130 NULL, { NULL }
131 },
132 {
133 nxt_string("GET /. HTTP/1.0\r\n\r\n"),
134 NXT_DONE,
135 &nxt_http_parse_test_request_line,
136 { .request_line = {
137 nxt_string("GET"),
138 nxt_string("/."),
139 nxt_null_string,
140 "HTTP/1.0",
141 1, 0, 0
142 }}
143 },
144 {
145 nxt_string("GET /# HTTP/1.0\r\n\r\n"),
146 NXT_DONE,
147 &nxt_http_parse_test_request_line,
148 { .request_line = {
149 nxt_string("GET"),
150 nxt_string("/#"),
151 nxt_null_string,
152 "HTTP/1.0",
153 1, 0, 0
154 }}
155 },
156 {
157 nxt_string("GET /?# HTTP/1.0\r\n\r\n"),
158 NXT_DONE,
159 &nxt_http_parse_test_request_line,
160 { .request_line = {
161 nxt_string("GET"),
162 nxt_string("/?#"),
163 nxt_string(""),
164 "HTTP/1.0",
165 1, 0, 0
166 }}
167 },
168 {
169 nxt_string("GET // HTTP/1.0\r\n\r\n"),
170 NXT_DONE,
171 &nxt_http_parse_test_request_line,
172 { .request_line = {
173 nxt_string("GET"),
174 nxt_string("//"),
175 nxt_null_string,
176 "HTTP/1.0",
177 1, 0, 0
178 }}
179 },
180 {
181 nxt_string("GET /%20 HTTP/1.0\r\n\r\n"),
182 NXT_DONE,
183 &nxt_http_parse_test_request_line,
184 { .request_line = {
185 nxt_string("GET"),
186 nxt_string("/%20"),
187 nxt_null_string,
188 "HTTP/1.0",
189 0, 1, 0
190 }}
191 },
192 {
193 nxt_string("GET / a HTTP/1.0\r\n\r\n"),
194 NXT_DONE,
195 &nxt_http_parse_test_request_line,
196 { .request_line = {
197 nxt_string("GET"),
198 nxt_string("/ a"),
199 nxt_null_string,
200 "HTTP/1.0",
201 0, 0, 1
202 }}
203 },
204 {
205 nxt_string("GET /na %20me.ext?args HTTP/1.0\r\n\r\n"),
206 NXT_DONE,
207 &nxt_http_parse_test_request_line,
208 { .request_line = {
209 nxt_string("GET"),
210 nxt_string("/na %20me.ext?args"),
211 nxt_string("args"),
212 "HTTP/1.0",
213 0, 1, 1
214 }}
215 },
216 {
217 nxt_string("GET / HTTP/1.0 HTTP/1.1\r\n\r\n"),
218 NXT_DONE,
219 &nxt_http_parse_test_request_line,
220 { .request_line = {
221 nxt_string("GET"),
222 nxt_string("/ HTTP/1.0"),
223 nxt_null_string,
224 "HTTP/1.1",
225 0, 0, 1
226 }}
227 },
228 {
229 nxt_string("GET / HTTP/1.1\r\n"
230 "Host: example.com\r\n\r\n"),
231 NXT_DONE,
232 NULL, { NULL }
233 },
234 {
235 nxt_string("GET / HTTP/1.1\r\n"
236 "Host:example.com \r\n\r\n"),
237 NXT_DONE,
238 NULL, { NULL }
239 },
240 {
241 nxt_string("GET / HTTP/1.1\r\n"
242 "Host:\r\n\r\n"),
243 NXT_DONE,
244 NULL, { NULL }
245 },
246 {
247 nxt_string("GET / HTTP/1.1\r\n"
248 "Host example.com\r\n\r\n"),
249 NXT_HTTP_PARSE_INVALID,
250 NULL, { NULL }
251 },
252 {
253 nxt_string("GET / HTTP/1.1\r\n"
254 ":Host: example.com\r\n\r\n"),
255 NXT_HTTP_PARSE_INVALID,
256 NULL, { NULL }
257 },
258 {
259 nxt_string("GET / HTTP/1.1\r\n"
260 "Ho_st: example.com\r\n\r\n"),
261 NXT_DONE,
262 NULL, { NULL }
263 },
264 {
265 nxt_string("GET / HTTP/1.1\r\n"
266 "Ho\0st: example.com\r\n\r\n"),
267 NXT_HTTP_PARSE_INVALID,
268 NULL, { NULL }
269 },
270 {
271 nxt_string("GET / HTTP/1.1\r\n"
272 "Ho\rst: example.com\r\n\r\n"),
273 NXT_HTTP_PARSE_INVALID,
274 NULL, { NULL }
275 },
276 {
277 nxt_string("GET / HTTP/1.1\r\n"
278 "Ho\nst: example.com\r\n\r\n"),
279 NXT_HTTP_PARSE_INVALID,
280 NULL, { NULL }
281 },
282 {
283 nxt_string("GET / HTTP/1.1\r\n"
284 "Host : example.com\r\n\r\n"),
285 NXT_HTTP_PARSE_INVALID,
286 NULL, { NULL }
287 },
288 {
289 nxt_string("GET / HTTP/1.1\r\n"
290 "Host: exa\0mple.com\r\n\r\n"),
291 NXT_HTTP_PARSE_INVALID,
292 NULL, { NULL }
293 },
294 {
295 nxt_string("GET / HTTP/1.1\r\n"
296 "Host: exa\rmple.com\r\n\r\n"),
297 NXT_HTTP_PARSE_INVALID,
298 NULL, { NULL }
299 },
300 {
301 nxt_string("GET / HTTP/1.1\r\n"
302 "Host: exa\bmple.com\r\n\r\n"),
303 NXT_HTTP_PARSE_INVALID,
304 NULL, { NULL }
305 },
306 {
307 nxt_string("GET / HTTP/1.1\r\n"
308 "Host: пример.испытание\r\n\r\n"),
309 NXT_DONE,
310 NULL, { NULL }
311 },
312 {
313 nxt_string("GET / HTTP/1.1\r\n"
314 "Host: xn--e1afmkfd.xn--80akhbyknj4f\r\n\r\n"),
315 NXT_DONE,
316 NULL, { NULL }
317 },
318 {
319 nxt_string("GET / HTTP/1.1\r\n"
320 "Host: exa\nmple.com\r\n\r\n"),
321 NXT_HTTP_PARSE_INVALID,
322 NULL, { NULL }
323 },
324 {
325 nxt_string("GET / HTTP/1.1\r\n"
326 "Host: exa\tmple.com\r\n\r\n"),
327 NXT_DONE,
328 NULL, { NULL }
329 },
330 {
331 nxt_string("GET / HTTP/1.1\r\n"
332 "X-Unknown-Header: value\r\n"
333 "X-Good-Header: value\r\n"
334 "!#$%&'*+.^_`|~: skipped\r\n\r\n"),
335 NXT_DONE,
336 &nxt_http_parse_test_fields,
337 { .fields = { NXT_OK, 1 } }
338 },
339 {
340 nxt_string("GET / HTTP/1.1\r\n"
341 "X-Good-Header: value\r\n"
342 "X-Unknown-Header: value\r\n"
343 "X-Bad-Header: value\r\n\r\n"),
344 NXT_DONE,
345 &nxt_http_parse_test_fields,
346 { .fields = { NXT_ERROR, 1 } }
347 },
348 {
349 nxt_string("GET / HTTP/1.1\r\n"
350 "!#$%&'*+.^_`|~: allowed\r\n\r\n"),
351 NXT_DONE,
352 &nxt_http_parse_test_fields,
353 { .fields = { NXT_ERROR, 0 } }
354 },
355 };
356
357
358 static nxt_http_field_proc_t nxt_http_test_fields[] = {
359 { nxt_string("X-Bad-Header"),
360 &nxt_http_test_header_return,
361 NXT_ERROR },
362
363 { nxt_string("X-Good-Header"),
364 &nxt_http_test_header_return,
365 NXT_OK },
366
367 { nxt_string("!#$%&'*+.^_`|~"),
368 &nxt_http_test_header_return,
369 NXT_ERROR },
370 };
371
372
373 static nxt_lvlhsh_t nxt_http_test_fields_hash;
374
375
376 static nxt_http_field_proc_t nxt_http_test_bench_fields[] = {
377 { nxt_string("Host"),
378 &nxt_http_test_header_return, NXT_OK },
379 { nxt_string("User-Agent"),
380 &nxt_http_test_header_return, NXT_OK },
381 { nxt_string("Accept"),
382 &nxt_http_test_header_return, NXT_OK },
383 { nxt_string("Accept-Encoding"),
384 &nxt_http_test_header_return, NXT_OK },
385 { nxt_string("Accept-Language"),
386 &nxt_http_test_header_return, NXT_OK },
387 { nxt_string("Connection"),
388 &nxt_http_test_header_return, NXT_OK },
389 { nxt_string("Content-Length"),
390 &nxt_http_test_header_return, NXT_OK },
391 { nxt_string("Content-Range"),
392 &nxt_http_test_header_return, NXT_OK },
393 { nxt_string("Content-Type"),
394 &nxt_http_test_header_return, NXT_OK },
395 { nxt_string("Cookie"),
396 &nxt_http_test_header_return, NXT_OK },
397 { nxt_string("Range"),
398 &nxt_http_test_header_return, NXT_OK },
399 { nxt_string("If-Range"),
400 &nxt_http_test_header_return, NXT_OK },
401 { nxt_string("Transfer-Encoding"),
402 &nxt_http_test_header_return, NXT_OK },
403 { nxt_string("Expect"),
404 &nxt_http_test_header_return, NXT_OK },
405 { nxt_string("Via"),
406 &nxt_http_test_header_return, NXT_OK },
407 { nxt_string("If-Modified-Since"),
408 &nxt_http_test_header_return, NXT_OK },
409 { nxt_string("If-Unmodified-Since"),
410 &nxt_http_test_header_return, NXT_OK },
411 { nxt_string("If-Match"),
412 &nxt_http_test_header_return, NXT_OK },
413 { nxt_string("If-None-Match"),
414 &nxt_http_test_header_return, NXT_OK },
415 { nxt_string("Referer"),
416 &nxt_http_test_header_return, NXT_OK },
417 { nxt_string("Date"),
418 &nxt_http_test_header_return, NXT_OK },
419 { nxt_string("Upgrade"),
420 &nxt_http_test_header_return, NXT_OK },
421 { nxt_string("Authorization"),
422 &nxt_http_test_header_return, NXT_OK },
423 { nxt_string("Keep-Alive"),
424 &nxt_http_test_header_return, NXT_OK },
425 { nxt_string("X-Forwarded-For"),
426 &nxt_http_test_header_return, NXT_OK },
427 { nxt_string("X-Forwarded-Host"),
428 &nxt_http_test_header_return, NXT_OK },
429 { nxt_string("X-Forwarded-Proto"),
430 &nxt_http_test_header_return, NXT_OK },
431 { nxt_string("X-Http-Method-Override"),
432 &nxt_http_test_header_return, NXT_OK },
433 { nxt_string("X-Real-IP"),
434 &nxt_http_test_header_return, NXT_OK },
435 { nxt_string("X-Request-ID"),
436 &nxt_http_test_header_return, NXT_OK },
437 { nxt_string("TE"),
438 &nxt_http_test_header_return, NXT_OK },
439 { nxt_string("Pragma"),
440 &nxt_http_test_header_return, NXT_OK },
441 { nxt_string("Cache-Control"),
442 &nxt_http_test_header_return, NXT_OK },
443 { nxt_string("Origin"),
444 &nxt_http_test_header_return, NXT_OK },
445 { nxt_string("Upgrade-Insecure-Requests"),
446 &nxt_http_test_header_return, NXT_OK },
447 };
448
449
450 static nxt_str_t nxt_http_test_simple_request = nxt_string(
451 "GET /page HTTP/1.1\r\n"
452 "Host: example.com\r\n\r\n"
453 );
454
455
456 static nxt_str_t nxt_http_test_big_request = nxt_string(
457 "POST /path/to/very/interesting/article/on.this.site?arg1=value&arg2=value"
458 "2&very_big_arg=even_bigger_value HTTP/1.1\r\n"
459 "Host: www.example.com\r\n"
460 "User-Agent: Mozilla/5.0 (X11; Gentoo Linux x86_64; rv:42.0) Firefox/42.0"
461 "\r\n"
462 "Accept: text/html,application/json,application/xml;q=0.9,*/*;q=0.8\r\n"
463 "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4\r\n"
464 "Accept-Encoding: gzip, deflate, br\r\n"
465 "If-Modified-Since: Wed, 31 Dec 1986 16:00:00 GMT\r\n"
466 "Referer: https://example.org/path/to/not-interesting/article.html\r\n"
467 "Cookie: name=value; name2=value2; some_big_cookie=iVBORw0KGgoAAAANSUhEUgA"
468 "AAEAAAABACAMAAACdt4HsAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAABmelRY"
469 "dFJhdyBwcm9maWxlIHR5cGUgZXhpZgAAeNptitsJgEAMBP9ThSWsZy6PcvKhcB1YvjEni"
470 "ODAwjAs7ec4aCmkEXc1cREk7OwtUgyTFRA3BU+vFPjS7gUI/p46Q0u2fP/1B7oA1Scbwk"
471 "nkf9gAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACfUExURQwMDDw8PFBQUAICAhQUFAcHBxs"
472 "bGxEREQkJCTk5OTU1NSAgIFRUVB8fH0xMTCUlJVtbW0pKSikpKS8vL0BAQEZGRjMzM2Bg"
473 "YL6+vsDAwLS0tF1dXXJycrGxsWVlZWhoaKenp29vb6urq8TExHp6epSUlLu7u66urqOjo"
474 "5ycnH9/f4CAgJOTk5qamo6OjoWFhYiIiHd3d8nJyc/Pz9LS0ojXP1QAAAihSURBVFjDZV"
475 "eHdqM6EBUYEEh0EM3gCu41+/7/294dCSfZsxOHeM8yV3f6iGVGYohNEtJPGEjPiSLpMTz"
476 "zokg8DmGOCOm/P0I6MTPaBGDPCGEYV3kEzchjzPOSPIkk8BzuM8fSCOFfALER+6MdpnaV"
477 "55FMoOP7UliioK8QzpiT0Qv0Fl4lDJvFPwChETuHFjhw7vhRVcGAXDqcfhhnRaZUWeJTW"
478 "pYVCBEYAJihtCsUpIhyq6win3ueDCoRBIknJRwACtz3AJhDYBhESsmyEjhaKv0MRJIIFR"
479 "d4XyYqC1RWwQFeBF2CcApCmEFI2KwHTRIrsMq8UnYcRUkehKtlaGeq8BjowKHEQf7oEgH"
480 "JcKRWpSeZpTIrs5dKlGX9fF7GfrtdWqDAuce1IyOtLbWyRKRYIIIPBo63gswO07q20/p6"
481 "2txvj+flvUZUZeQ4IODBGDoYivoReREzugaAJKuX637dP0/DbnMGwuWyTTNlBYX0ItL3E"
482 "q2ptUmYZi9+ANLt9r2+nrqmORKD1/W9Xi3hirisEumQOz+qRv5hUL/H1bg7tG0znKbHCy"
483 "Zs16u6TgmiQH5rLW2Ltslhf6kjO1bjOJ4PTfu1PwDgeR0BsF6BBCBQIThee+P78QvAQNS"
484 "X17mD/tfXYaMBejAAhWWahqoiB5q8dmYQ9rc+AF7Trmn2BLC7vy4XQ0ADpHZmJRQPznVO"
485 "0YcABJRnBwBg+Tofm3a//2q7zYREIAAyAQRQQKqAJ/ksH4CPC4wJy9uma2eA2+syjtsVn"
486 "LicKzDTRYaqMgi/AQyHQNSPY0uyb7vdHVEcezDQBhAHJXLPqLOZxN8+CLJVehmapoUX2u"
487 "54okzsIXACucAOYyunov62AUDiN0IQd69+dyAf7PfdsLlRGAGwXekowIgySRzoMzZzcAj"
488 "gpxIs9Ti+TsTghLMvV1Lfbvt+vbTR9ZAJtlWoXxSIwaxuohCUt8Pp3LTd+XHt01KF9XZL"
489 "iRhXkSwKCzYg7X2NwGYYJsRvCHU6nndNO3SH4TauV9v3OK7rUKHnUJaiTxRl4XODwD8mC"
490 "Gptn0Q8j1e4oOmmfi0iZY/naRuWaIyiNI1bxDljs/7M4Hcxlta9fzTd/qubrrdYpNZ2GL"
491 "ZxgJboFkmFVhGLLPE/6ubPp5nNTphOAGj/QHavtZ292t3KLouiQocqbXhRKOlr+/9hoA0"
492 "og/d+dzi0/+2b7nTr60vXbtZhJkQZx2GaLsNMxZ8ozk5gphN/M4i79nBo/uwHdJPn1Db7"
493 "c40aUgoDRVdTmhn3awbsXxOs4PZfc2i+vrrTNCEe+/0JnTmkoZOiJcT2co4i5z9hnHu6Z"
494 "bxoT7sWAM3mfp9O7Vd7rnUV6E8ap2lk/MdmJzD2eyRohKrf4+DmON2ej6HZ31epnnqpLg"
495 "ZV8dmFMw6fB0vww0Gs903ToJaviOifdnrXS6SxhgjjxNEF9BH6VlUVMKqf+STqPTLpeHr"
496 "0l2HYHaYeHohVZiOIYUYjhjHfx0cLAHI96Qrzi4BXeYxiRi94PjeH4/k8xshgO8u0HYoI"
497 "EIDvQgzEPOJIaGAlSSQQye54nzbH3Wb3wFSJ9SJAi0XAZ33NwXUXC5dJFIRHvZo7n0Z3J"
498 "oDNaYef0zVd2bFZJjDzEmhByWfQ8bi/gDDpuz7NCa4RidhivT90w7B51tfXpV+F2CVEqd"
499 "eamC+gj5cYznSYawCYwSPvEIbP3ArqXXdeXze3MUUNBJbSAGHgGuOZ7maazAfAoXnnaP8"
500 "yN9kdj8fhjPY8TNt6FWchDTbsVB4s196jANI3XwNQPPXM9LSLmZ/Ae0f8nuGC2lhPK5md"
501 "++zbh76B8V0Wmaz0aOB7epHy5XA4b3ZIgt1puvYYrCkaQZyhCrjZ1ehw+B//An2skMYLh"
502 "GDCXB3b43Q6dhSL+7NHQ0YZYW3yyVfgyUwoOI1WABje3IkkBRMHRPmmPWxupyM4nF/jek"
503 "mrp8pSSSqap++aSADA1ZuTtsLTewPgKmfadx2q8YwNZVwhDzJVZnbGfEcDOB8A/Y1wDAV"
504 "iRxtHVLF321EiTJf3u0b+osLgglyTximcUQr6NJ2ZvwDAxwa9ejg8l7wcDsOAZLptwzgr"
505 "LUXLdOC5nF5yPi6giFAYsbTwbwQHcRCejFCHA/lwwoZFZRBjvZlbGJ4mGylj8E27giJDo"
506 "SQCsvJyR702xwGz8X5dp7qSMuy7lGcmhBrB13XxC8Asw7zIueBJ/brvEINHvzRLeSmS3C"
507 "SfTgHDwaXKIOd5c4/RoYzrRHiOtbpOm8391dNuhXW3rECBzwC+qWQS+IAZABSBE+VoJzV"
508 "6P+e5Wl9u9wlZRJtNjEXTLq1INwHdhvxZH9GkcFI8HFqAsWDLhYw5k0W8Hl8Y0fUSFxBs"
509 "9CquLGFKQBfcDODPrQGPnPpRlADAiZEMCVb1/r0lAkjD0kq9xSJnmj/7NoEiYUxAElOOA"
510 "SMoFgwAUhbKpnmANhTTFSXD+x6jEjJm+CaUXIdfJhFuN3RLy3GbcBcqYjJPKH8QwGWdod"
511 "nbEgqOMQD6xpXQJ/fjelXlgKU9vghk4S0KwZIC15YSvXjZ15awslAHzP00008iUEE7oC4"
512 "r7nKHerJAl18gGRGPAMwzez2GVpmFFhEAAKOe5CN6ZL6v0znPpVcluBMyj2ZDHhWLhciT"
513 "Ctq4UKb9uIIfV3ChqzvJpxvpWBIeAOheSXQ8ZEEig2DhyjyqSqVoJ9j2W0y2knLW16dCd"
514 "6EjyQ0a/E23IDDwowJ5IFJsMzJaRAEoxOFy1S+tXDAAcMdlxoP4w7UtnABQe0nhUa1HES"
515 "5kVennooC/WWEpANRLK4mYjplkcy/ViU+n627I8gjXIJ9L5APiCDYiqFD7IIYLWKoKySj"
516 "lUXleNM9TzcSfdxRGqlKijGALtTVJA7bgi0RVRaByyhjqP1S73BxPyjoeM47LPRqvVInU"
517 "cvGoCit3GRpZ5VC0XZ1zpg6pb1AqLAhDD8L/AcHH1p8sEFAHAAAAAElFTkSuQmCC\r\n"
518 "Connection: keep-alive\r\n"
519 "Content-Length: 0\r\n"
520 "Upgrade-Insecure-Requests: 1\r\n"
521 "Pragma: no-cache\r\n"
522 "Cache-Control: no-cache\r\n"
523 "X-Forwarded-For: 192.0.2.0, 198.51.100.0, 203.0.113.0\r\n"
524 "\r\n"
525 );
526
527
528 nxt_int_t
nxt_http_parse_test(nxt_thread_t * thr)529 nxt_http_parse_test(nxt_thread_t *thr)
530 {
531 nxt_mp_t *mp_temp;
532 nxt_int_t rc;
533 nxt_uint_t i, colls, lvl_colls;
534 nxt_lvlhsh_t hash;
535 nxt_http_request_parse_t rp;
536 nxt_http_parse_test_case_t *test;
537
538 nxt_thread_time_update(thr);
539
540 rc = nxt_http_fields_hash(&nxt_http_test_fields_hash,
541 nxt_http_test_fields,
542 nxt_nitems(nxt_http_test_fields));
543 if (rc != NXT_OK) {
544 return NXT_ERROR;
545 }
546
547 for (i = 0; i < nxt_nitems(nxt_http_test_cases); i++) {
548 test = &nxt_http_test_cases[i];
549
550 nxt_memzero(&rp, sizeof(nxt_http_request_parse_t));
551
552 mp_temp = nxt_mp_create(1024, 128, 256, 32);
553 if (mp_temp == NULL) {
554 return NXT_ERROR;
555 }
556
557 if (nxt_http_parse_request_init(&rp, mp_temp) != NXT_OK) {
558 return NXT_ERROR;
559 }
560
561 if (test->handler == &nxt_http_parse_test_fields) {
562 rp.discard_unsafe_fields = test->data.fields.discard_unsafe_fields;
563 }
564
565 rc = nxt_http_parse_test_run(&rp, &test->request);
566
567 if (rc != test->result) {
568 nxt_log_alert(thr->log, "http parse test case failed:\n"
569 " - request:\n\"%V\"\n"
570 " - result: %i (expected: %i)",
571 &test->request, rc, test->result);
572 return NXT_ERROR;
573 }
574
575 if (test->handler != NULL
576 && test->handler(&rp, &test->data, &test->request, thr->log)
577 != NXT_OK)
578 {
579 return NXT_ERROR;
580 }
581
582 nxt_mp_destroy(mp_temp);
583 }
584
585 nxt_log_error(NXT_LOG_NOTICE, thr->log, "http parse test passed");
586
587 nxt_memzero(&hash, sizeof(nxt_lvlhsh_t));
588
589 colls = nxt_http_fields_hash_collisions(&hash,
590 nxt_http_test_bench_fields,
591 nxt_nitems(nxt_http_test_bench_fields),
592 0);
593
594 nxt_memzero(&hash, sizeof(nxt_lvlhsh_t));
595
596 lvl_colls = nxt_http_fields_hash_collisions(&hash,
597 nxt_http_test_bench_fields,
598 nxt_nitems(nxt_http_test_bench_fields),
599 1);
600
601 nxt_log_error(NXT_LOG_NOTICE, thr->log,
602 "http parse test hash collisions %ui out of %uz, level: %ui",
603 colls, nxt_nitems(nxt_http_test_bench_fields), lvl_colls);
604
605 nxt_memzero(&hash, sizeof(nxt_lvlhsh_t));
606
607 rc = nxt_http_fields_hash(&hash, nxt_http_test_bench_fields,
608 nxt_nitems(nxt_http_test_bench_fields));
609 if (rc != NXT_OK) {
610 return NXT_ERROR;
611 }
612
613 if (nxt_http_parse_test_bench(thr, &nxt_http_test_simple_request,
614 &hash, "simple", 1000000)
615 != NXT_OK)
616 {
617 return NXT_ERROR;
618 }
619
620 if (nxt_http_parse_test_bench(thr, &nxt_http_test_big_request,
621 &hash, "big", 100000)
622 != NXT_OK)
623 {
624 return NXT_ERROR;
625 }
626
627 return NXT_OK;
628 }
629
630
631 static nxt_int_t
nxt_http_parse_test_run(nxt_http_request_parse_t * rp,nxt_str_t * request)632 nxt_http_parse_test_run(nxt_http_request_parse_t *rp, nxt_str_t *request)
633 {
634 nxt_int_t rc;
635 nxt_buf_mem_t buf;
636
637 buf.start = request->start;
638 buf.end = request->start + request->length;
639
640 buf.pos = buf.start;
641 buf.free = buf.pos + 1;
642
643 do {
644 buf.free++;
645 rc = nxt_http_parse_request(rp, &buf);
646 } while (buf.free < buf.end && rc == NXT_AGAIN);
647
648 return rc;
649 }
650
651
652 static nxt_int_t
nxt_http_parse_test_bench(nxt_thread_t * thr,nxt_str_t * request,nxt_lvlhsh_t * hash,const char * name,nxt_uint_t n)653 nxt_http_parse_test_bench(nxt_thread_t *thr, nxt_str_t *request,
654 nxt_lvlhsh_t *hash, const char *name, nxt_uint_t n)
655 {
656 nxt_mp_t *mp;
657 nxt_nsec_t start, end;
658 nxt_uint_t i;
659 nxt_buf_mem_t buf;
660 nxt_http_request_parse_t rp;
661
662 nxt_log_error(NXT_LOG_NOTICE, thr->log,
663 "http parse %s request bench started: %uz bytes, %ui runs",
664 name, request->length, n);
665
666 buf.start = request->start;
667 buf.end = request->start + request->length;
668
669 nxt_thread_time_update(thr);
670 start = nxt_thread_monotonic_time(thr);
671
672 for (i = 0; nxt_fast_path(i < n); i++) {
673 nxt_memzero(&rp, sizeof(nxt_http_request_parse_t));
674
675 mp = nxt_mp_create(1024, 128, 256, 32);
676 if (nxt_slow_path(mp == NULL)) {
677 return NXT_ERROR;
678 }
679
680 if (nxt_slow_path(nxt_http_parse_request_init(&rp, mp) != NXT_OK)) {
681 return NXT_ERROR;
682 }
683
684 buf.pos = buf.start;
685 buf.free = buf.end;
686
687 if (nxt_slow_path(nxt_http_parse_request(&rp, &buf) != NXT_DONE)) {
688 nxt_log_alert(thr->log, "http parse %s request bench failed "
689 "while parsing", name);
690 return NXT_ERROR;
691 }
692
693 if (nxt_slow_path(nxt_http_fields_process(rp.fields, hash, NULL)
694 != NXT_OK))
695 {
696 nxt_log_alert(thr->log, "http parse %s request bench failed "
697 "while fields processing", name);
698 return NXT_ERROR;
699 }
700
701 nxt_mp_destroy(mp);
702 }
703
704 nxt_thread_time_update(thr);
705 end = nxt_thread_monotonic_time(thr);
706
707 nxt_log_error(NXT_LOG_NOTICE, thr->log,
708 "http parse %s request bench: %0.3fs",
709 name, (end - start) / 1000000000.0);
710
711 return NXT_OK;
712 }
713
714
715 static nxt_int_t
nxt_http_parse_test_request_line(nxt_http_request_parse_t * rp,nxt_http_parse_test_data_t * data,nxt_str_t * request,nxt_log_t * log)716 nxt_http_parse_test_request_line(nxt_http_request_parse_t *rp,
717 nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log)
718 {
719 nxt_str_t str;
720
721 nxt_http_parse_test_request_line_t *test = &data->request_line;
722
723 if (rp->method.start != test->method.start
724 && !nxt_strstr_eq(&rp->method, &test->method))
725 {
726 nxt_log_alert(log, "http parse test case failed:\n"
727 " - request:\n\"%V\"\n"
728 " - method: \"%V\" (expected: \"%V\")",
729 request, &rp->method, &test->method);
730 return NXT_ERROR;
731 }
732
733 str.length = rp->target_end - rp->target_start;
734 str.start = rp->target_start;
735
736 if (str.start != test->target.start
737 && !nxt_strstr_eq(&str, &test->target))
738 {
739 nxt_log_alert(log, "http parse test case failed:\n"
740 " - request:\n\"%V\"\n"
741 " - target: \"%V\" (expected: \"%V\")",
742 request, &str, &test->target);
743 return NXT_ERROR;
744 }
745
746 if (rp->args.start != test->args.start
747 && !nxt_strstr_eq(&rp->args, &test->args))
748 {
749 nxt_log_alert(log, "http parse test case failed:\n"
750 " - request:\n\"%V\"\n"
751 " - args: \"%V\" (expected: \"%V\")",
752 request, &rp->args, &test->args);
753 return NXT_ERROR;
754 }
755
756 if (memcmp(rp->version.str, test->version, 8) != 0) {
757 nxt_log_alert(log, "http parse test case failed:\n"
758 " - request:\n\"%V\"\n"
759 " - version: \"%*s\" (expected: \"%*s\")", request,
760 (size_t) 8, rp->version.str,
761 (size_t) 8, test->version);
762 return NXT_ERROR;
763 }
764
765 if (rp->complex_target != (test->complex_target | test->quoted_target)) {
766 nxt_log_alert(log, "http parse test case failed:\n"
767 " - request:\n\"%V\"\n"
768 " - complex_target: %d (expected: %d)",
769 request, rp->complex_target, test->complex_target);
770 return NXT_ERROR;
771 }
772
773 #if 0
774 if (rp->quoted_target != test->quoted_target) {
775 nxt_log_alert(log, "http parse test case failed:\n"
776 " - request:\n\"%V\"\n"
777 " - quoted_target: %d (expected: %d)",
778 request, rp->quoted_target, test->quoted_target);
779 return NXT_ERROR;
780 }
781
782 if (rp->space_in_target != test->space_in_target) {
783 nxt_log_alert(log, "http parse test case failed:\n"
784 " - request:\n\"%V\"\n"
785 " - space_in_target: %d (expected: %d)",
786 request, rp->space_in_target, test->space_in_target);
787 return NXT_ERROR;
788 }
789 #endif
790
791 return NXT_OK;
792 }
793
794
795 static nxt_int_t
nxt_http_parse_test_fields(nxt_http_request_parse_t * rp,nxt_http_parse_test_data_t * data,nxt_str_t * request,nxt_log_t * log)796 nxt_http_parse_test_fields(nxt_http_request_parse_t *rp,
797 nxt_http_parse_test_data_t *data, nxt_str_t *request, nxt_log_t *log)
798 {
799 nxt_int_t rc;
800
801 rc = nxt_http_fields_process(rp->fields, &nxt_http_test_fields_hash, NULL);
802
803 if (rc != data->fields.result) {
804 nxt_log_alert(log, "http parse test hash failed:\n"
805 " - request:\n\"%V\"\n"
806 " - result: %i (expected: %i)",
807 request, rc, data->fields.result);
808 return NXT_ERROR;
809 }
810
811 return NXT_OK;
812 }
813
814
815 static nxt_int_t
nxt_http_test_header_return(void * ctx,nxt_http_field_t * field,uintptr_t data)816 nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, uintptr_t data)
817 {
818 return data;
819 }
820