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