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 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 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 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 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 (nxt_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 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 816 nxt_http_test_header_return(void *ctx, nxt_http_field_t *field, uintptr_t data) 817 { 818 return data; 819 } 820