1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_router.h> 8 #include <nxt_http.h> 9 10 11 static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); 12 static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); 13 static void nxt_http_request_action(nxt_task_t *task, void *obj, void *data); 14 static void nxt_http_request_proto_info(nxt_task_t *task, 15 nxt_http_request_t *r); 16 static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, 17 void *data); 18 static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); 19 20 static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, 21 struct tm *tm, size_t size, const char *format); 22 23 24 static const nxt_http_request_state_t nxt_http_request_init_state; 25 static const nxt_http_request_state_t nxt_http_request_body_state; 26 27 28 nxt_time_string_t nxt_http_date_cache = { 29 (nxt_atomic_uint_t) -1, 30 nxt_http_date_cache_handler, 31 NULL, 32 NXT_HTTP_DATE_LEN, 33 NXT_THREAD_TIME_GMT, 34 NXT_THREAD_TIME_SEC, 35 }; 36 37 38 nxt_int_t 39 nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt) 40 { 41 nxt_int_t ret; 42 43 ret = nxt_h1p_init(task, rt); 44 45 if (ret != NXT_OK) { 46 return ret; 47 } 48 49 return nxt_http_response_hash_init(task, rt); 50 } 51 52 53 nxt_int_t 54 nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) 55 { 56 nxt_int_t ret; 57 nxt_str_t host; 58 nxt_http_request_t *r; 59 60 r = ctx; 61 62 if (nxt_slow_path(r->host.start != NULL)) { 63 return NXT_HTTP_BAD_REQUEST; 64 } 65 66 host.length = field->value_length; 67 host.start = field->value; 68 69 ret = nxt_http_validate_host(&host, r->mem_pool); 70 71 if (nxt_fast_path(ret == NXT_OK)) { 72 r->host = host; 73 } 74 75 return ret; 76 } 77 78 79 static nxt_int_t 80 nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) 81 { 82 u_char *h, ch; 83 size_t i, dot_pos, host_length; 84 nxt_bool_t lowcase; 85 86 enum { 87 sw_usual, 88 sw_literal, 89 sw_rest 90 } state; 91 92 dot_pos = host->length; 93 host_length = host->length; 94 95 h = host->start; 96 97 lowcase = 0; 98 state = sw_usual; 99 100 for (i = 0; i < host->length; i++) { 101 ch = h[i]; 102 103 if (ch > ']') { 104 /* Short path. */ 105 continue; 106 } 107 108 switch (ch) { 109 110 case '.': 111 if (dot_pos == i - 1) { 112 return NXT_HTTP_BAD_REQUEST; 113 } 114 115 dot_pos = i; 116 break; 117 118 case ':': 119 if (state == sw_usual) { 120 host_length = i; 121 state = sw_rest; 122 } 123 124 break; 125 126 case '[': 127 if (i == 0) { 128 state = sw_literal; 129 } 130 131 break; 132 133 case ']': 134 if (state == sw_literal) { 135 host_length = i + 1; 136 state = sw_rest; 137 } 138 139 break; 140 141 case '/': 142 return NXT_HTTP_BAD_REQUEST; 143 144 default: 145 if (ch >= 'A' && ch <= 'Z') { 146 lowcase = 1; 147 } 148 149 break; 150 } 151 } 152 153 if (dot_pos == host_length - 1) { 154 host_length--; 155 } 156 157 host->length = host_length; 158 159 if (lowcase) { 160 host->start = nxt_mp_nget(mp, host_length); 161 if (nxt_slow_path(host->start == NULL)) { 162 return NXT_HTTP_INTERNAL_SERVER_ERROR; 163 } 164 165 nxt_memcpy_lowcase(host->start, h, host_length); 166 } 167 168 return NXT_OK; 169 } 170 171 172 nxt_int_t 173 nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) 174 { 175 nxt_http_request_t *r; 176 177 r = ctx; 178 179 nxt_value_at(nxt_http_field_t *, r, offset) = field; 180 181 return NXT_OK; 182 } 183 184 185 nxt_int_t 186 nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, 187 uintptr_t data) 188 { 189 nxt_off_t n, max_body_size; 190 nxt_http_request_t *r; 191 192 r = ctx; 193 194 if (nxt_fast_path(r->content_length == NULL)) { 195 r->content_length = field; 196 197 n = nxt_off_t_parse(field->value, field->value_length); 198 199 if (nxt_fast_path(n >= 0)) { 200 r->content_length_n = n; 201 202 max_body_size = r->conf->socket_conf->max_body_size; 203 204 if (nxt_slow_path(n > max_body_size)) { 205 return NXT_HTTP_PAYLOAD_TOO_LARGE; 206 } 207 208 return NXT_OK; 209 } 210 } 211 212 return NXT_HTTP_BAD_REQUEST; 213 } 214 215 216 nxt_http_request_t * 217 nxt_http_request_create(nxt_task_t *task) 218 { 219 nxt_mp_t *mp; 220 nxt_buf_t *last; 221 nxt_http_request_t *r; 222 223 mp = nxt_mp_create(1024, 128, 256, 32); 224 if (nxt_slow_path(mp == NULL)) { 225 return NULL; 226 } 227 228 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); 229 if (nxt_slow_path(r == NULL)) { 230 goto fail; 231 } 232 233 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 234 if (nxt_slow_path(r->resp.fields == NULL)) { 235 goto fail; 236 } 237 238 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE); 239 if (nxt_slow_path(last == NULL)) { 240 goto fail; 241 } 242 243 nxt_buf_set_sync(last); 244 nxt_buf_set_last(last); 245 last->completion_handler = nxt_http_request_done; 246 last->parent = r; 247 r->last = last; 248 249 r->mem_pool = mp; 250 r->content_length_n = -1; 251 r->resp.content_length_n = -1; 252 r->state = &nxt_http_request_init_state; 253 254 return r; 255 256 fail: 257 258 nxt_mp_release(mp); 259 260 return NULL; 261 } 262 263 264 static const nxt_http_request_state_t nxt_http_request_init_state 265 nxt_aligned(64) = 266 { 267 .ready_handler = nxt_http_request_start, 268 .error_handler = nxt_http_request_close_handler, 269 }; 270 271 272 static void 273 nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 274 { 275 nxt_http_request_t *r; 276 277 r = obj; 278 279 r->state = &nxt_http_request_body_state; 280 281 nxt_http_request_read_body(task, r); 282 } 283 284 285 static const nxt_http_request_state_t nxt_http_request_body_state 286 nxt_aligned(64) = 287 { 288 .ready_handler = nxt_http_request_action, 289 .error_handler = nxt_http_request_close_handler, 290 }; 291 292 293 static void 294 nxt_http_request_action(nxt_task_t *task, void *obj, void *data) 295 { 296 nxt_http_action_t *action; 297 nxt_http_request_t *r; 298 299 r = obj; 300 301 action = r->conf->socket_conf->action; 302 303 if (nxt_fast_path(action != NULL)) { 304 305 do { 306 nxt_debug(task, "http request route: %V", &action->name); 307 308 action = action->handler(task, r, action); 309 310 if (action == NULL) { 311 return; 312 } 313 314 if (action == NXT_HTTP_ACTION_ERROR) { 315 break; 316 } 317 318 } while (r->pass_count++ < 255); 319 } 320 321 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 322 } 323 324 325 nxt_http_action_t * 326 nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, 327 nxt_http_action_t *action) 328 { 329 nxt_event_engine_t *engine; 330 331 nxt_debug(task, "http application handler"); 332 333 nxt_mp_retain(r->mem_pool); 334 335 engine = task->thread->engine; 336 r->timer.task = &engine->task; 337 r->timer.work_queue = &engine->fast_work_queue; 338 r->timer.log = engine->task.log; 339 r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 340 341 /* 342 * TODO: need an application flag to get local address 343 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 344 */ 345 nxt_http_request_proto_info(task, r); 346 347 if (r->host.length != 0) { 348 r->server_name = r->host; 349 350 } else { 351 nxt_str_set(&r->server_name, "localhost"); 352 } 353 354 nxt_router_process_http_request(task, r, action->u.application); 355 356 return NULL; 357 } 358 359 360 static void 361 nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) 362 { 363 if (nxt_fast_path(r->proto.any != NULL)) { 364 nxt_http_proto[r->protocol].local_addr(task, r); 365 } 366 } 367 368 369 void 370 nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 371 { 372 if (nxt_fast_path(r->proto.any != NULL)) { 373 nxt_http_proto[r->protocol].body_read(task, r); 374 } 375 } 376 377 378 void 379 nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, 380 nxt_work_handler_t body_handler, void *data) 381 { 382 u_char *p, *end; 383 nxt_http_field_t *server, *date, *content_length; 384 385 /* 386 * TODO: "Server", "Date", and "Content-Length" processing should be moved 387 * to the last header filter. 388 */ 389 390 server = nxt_list_zero_add(r->resp.fields); 391 if (nxt_slow_path(server == NULL)) { 392 goto fail; 393 } 394 395 nxt_http_field_set(server, "Server", NXT_SERVER); 396 397 if (r->resp.date == NULL) { 398 date = nxt_list_zero_add(r->resp.fields); 399 if (nxt_slow_path(date == NULL)) { 400 goto fail; 401 } 402 403 nxt_http_field_name_set(date, "Date"); 404 405 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 406 if (nxt_slow_path(p == NULL)) { 407 goto fail; 408 } 409 410 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 411 412 date->value = p; 413 date->value_length = nxt_http_date_cache.size; 414 415 r->resp.date = date; 416 } 417 418 if (r->resp.content_length_n != -1 419 && (r->resp.content_length == NULL || r->resp.content_length->skip)) 420 { 421 content_length = nxt_list_zero_add(r->resp.fields); 422 if (nxt_slow_path(content_length == NULL)) { 423 goto fail; 424 } 425 426 nxt_http_field_name_set(content_length, "Content-Length"); 427 428 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 429 if (nxt_slow_path(p == NULL)) { 430 goto fail; 431 } 432 433 content_length->value = p; 434 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 435 content_length->value_length = end - p; 436 437 r->resp.content_length = content_length; 438 } 439 440 if (nxt_fast_path(r->proto.any != NULL)) { 441 nxt_http_proto[r->protocol].header_send(task, r, body_handler, data); 442 } 443 444 return; 445 446 fail: 447 448 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 449 } 450 451 452 void 453 nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, 454 nxt_buf_t *ws_frame) 455 { 456 if (r->proto.any != NULL) { 457 nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame); 458 } 459 } 460 461 462 void 463 nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 464 { 465 if (nxt_fast_path(r->proto.any != NULL)) { 466 nxt_http_proto[r->protocol].send(task, r, out); 467 } 468 } 469 470 471 nxt_buf_t * 472 nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 473 { 474 nxt_buf_t *b; 475 476 b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 477 if (nxt_fast_path(b != NULL)) { 478 b->completion_handler = nxt_http_request_mem_buf_completion; 479 b->parent = r; 480 nxt_mp_retain(r->mem_pool); 481 482 } else { 483 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 484 } 485 486 return b; 487 } 488 489 490 static void 491 nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 492 { 493 nxt_buf_t *b, *next; 494 nxt_http_request_t *r; 495 496 b = obj; 497 r = data; 498 499 do { 500 next = b->next; 501 502 nxt_mp_free(r->mem_pool, b); 503 nxt_mp_release(r->mem_pool); 504 505 b = next; 506 } while (b != NULL); 507 } 508 509 510 nxt_buf_t * 511 nxt_http_buf_last(nxt_http_request_t *r) 512 { 513 nxt_buf_t *last; 514 515 last = r->last; 516 r->last = NULL; 517 518 return last; 519 } 520 521 522 static void 523 nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 524 { 525 nxt_http_request_t *r; 526 527 r = data; 528 529 nxt_debug(task, "http request done"); 530 531 nxt_http_request_close_handler(task, r, r->proto.any); 532 } 533 534 535 void 536 nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 537 { 538 nxt_http_proto_t proto; 539 nxt_http_request_t *r; 540 541 r = obj; 542 proto.any = data; 543 544 nxt_debug(task, "http request error handler"); 545 546 r->error = 1; 547 548 if (nxt_fast_path(proto.any != NULL)) { 549 nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r)); 550 } 551 } 552 553 554 void 555 nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 556 { 557 nxt_http_proto_t proto; 558 nxt_http_request_t *r; 559 nxt_http_protocol_t protocol; 560 nxt_socket_conf_joint_t *conf; 561 nxt_router_access_log_t *access_log; 562 563 r = obj; 564 proto.any = data; 565 566 nxt_debug(task, "http request close handler"); 567 568 conf = r->conf; 569 570 if (!r->logged) { 571 r->logged = 1; 572 573 access_log = conf->socket_conf->router_conf->access_log; 574 575 if (access_log != NULL) { 576 access_log->handler(task, r, access_log); 577 } 578 } 579 580 r->proto.any = NULL; 581 582 if (nxt_fast_path(proto.any != NULL)) { 583 protocol = r->protocol; 584 585 nxt_http_proto[protocol].close(task, proto, conf); 586 587 nxt_mp_release(r->mem_pool); 588 } 589 } 590 591 592 static u_char * 593 nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, 594 size_t size, const char *format) 595 { 596 return nxt_http_date(buf, tm); 597 } 598