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 11static void nxt_h1p_read_header(nxt_task_t *task, void *obj, void *data); 12static void nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data); 13static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field, 14 uintptr_t data); 15static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, 16 uintptr_t data); 17static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r); 18static void nxt_h1p_body_read(nxt_task_t *task, void *obj, void *data); 19static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); 20static void nxt_h1p_request_header_send(nxt_task_t *task, 21 nxt_http_request_t *r); 22static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, 23 nxt_buf_t *out); 24static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, 25 nxt_buf_t *out); 26static void nxt_h1p_sent(nxt_task_t *task, void *obj, void *data); 27static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto); 28static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, 29 nxt_conn_t *c); 30static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c); 31static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data); 32static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); 33static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data); 34static nxt_msec_t nxt_h1p_timeout_value(nxt_conn_t *c, uintptr_t data); 35 36 37static const nxt_conn_state_t nxt_h1p_idle_state; 38static const nxt_conn_state_t nxt_h1p_read_header_state; 39static const nxt_conn_state_t nxt_h1p_read_body_state; 40static const nxt_conn_state_t nxt_h1p_send_state; 41 42 43const nxt_http_proto_body_read_t nxt_http_proto_body_read[3] = { 44 nxt_h1p_request_body_read, 45 NULL, 46 NULL, 47}; 48 49 50const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = { 51 nxt_h1p_request_local_addr, 52 NULL, 53 NULL, 54}; 55 56 57const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = { 58 nxt_h1p_request_header_send, 59 NULL, 60 NULL, 61}; 62 63 64const nxt_http_proto_send_t nxt_http_proto_send[3] = { 65 nxt_h1p_request_send, 66 NULL, 67 NULL, 68}; 69 70 71const nxt_http_proto_close_t nxt_http_proto_close[3] = { 72 nxt_h1p_request_close, 73 NULL, 74 NULL, 75}; 76 77 78static nxt_lvlhsh_t nxt_h1p_fields_hash; 79 80static nxt_http_field_proc_t nxt_h1p_fields[] = { 81 { nxt_string("Connection"), &nxt_h1p_connection, 0 }, 82 { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 }, 83 84 { nxt_string("Host"), &nxt_http_request_host, 0 }, 85 { nxt_string("Cookie"), &nxt_http_request_field, 86 offsetof(nxt_http_request_t, cookie) }, 87 { nxt_string("Content-Type"), &nxt_http_request_field, 88 offsetof(nxt_http_request_t, content_type) }, 89 { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 }, 90}; 91 92 93nxt_int_t 94nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt) 95{ 96 return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool, 97 nxt_h1p_fields, nxt_nitems(nxt_h1p_fields)); 98} 99 100 101void 102nxt_http_conn_init(nxt_task_t *task, void *obj, void *data) 103{ 104 nxt_conn_t *c; 105 nxt_socket_conf_t *skcf; 106 nxt_event_engine_t *engine; 107 nxt_socket_conf_joint_t *joint; 108 109 c = obj; 110 joint = data; 111 112 nxt_debug(task, "http conn init"); 113 114 c->joint = joint; 115 joint->count++; 116 117 skcf = joint->socket_conf; 118 c->local = skcf->sockaddr; 119 c->socket.data = NULL; 120 121 engine = task->thread->engine; 122 c->read_work_queue = &engine->fast_work_queue; 123 c->write_work_queue = &engine->fast_work_queue; 124 125 c->read_state = &nxt_h1p_idle_state; 126 127 nxt_conn_wait(c); 128} 129 130 131static const nxt_conn_state_t nxt_h1p_idle_state 132 nxt_aligned(64) = 133{ 134 .ready_handler = nxt_h1p_read_header, 135 .close_handler = nxt_h1p_conn_close, 136 .error_handler = nxt_h1p_conn_error, 137 138 .timer_handler = nxt_h1p_conn_timeout, 139 .timer_value = nxt_h1p_timeout_value, 140 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), 141}; 142 143 144static void 145nxt_h1p_read_header(nxt_task_t *task, void *obj, void *data) 146{ 147 size_t size; 148 nxt_conn_t *c; 149 nxt_socket_conf_joint_t *joint; 150 151 c = obj; 152 153 nxt_debug(task, "h1p read header"); 154 155 if (c->read == NULL) { 156 joint = c->joint; 157 size = joint->socket_conf->header_buffer_size; 158 159 c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 160 if (nxt_slow_path(c->read == NULL)) { 161 nxt_h1p_conn_error(task, c, c->socket.data); 162 return; 163 } 164 } 165 166 c->read_state = &nxt_h1p_read_header_state; 167 168 nxt_conn_read(task->thread->engine, c); 169} 170 171 172static const nxt_conn_state_t nxt_h1p_read_header_state 173 nxt_aligned(64) = 174{ 175 .ready_handler = nxt_h1p_header_parse, 176 .close_handler = nxt_h1p_conn_close, 177 .error_handler = nxt_h1p_conn_error, 178 179 .timer_handler = nxt_h1p_conn_timeout, 180 .timer_value = nxt_h1p_timeout_value, 181 .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 182}; 183 184 185static void 186nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data) 187{ 188 size_t size; 189 nxt_int_t ret; 190 nxt_buf_t *in, *b; 191 nxt_conn_t *c; 192 nxt_h1proto_t *h1p;
| 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 11static void nxt_h1p_read_header(nxt_task_t *task, void *obj, void *data); 12static void nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data); 13static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field, 14 uintptr_t data); 15static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, 16 uintptr_t data); 17static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r); 18static void nxt_h1p_body_read(nxt_task_t *task, void *obj, void *data); 19static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); 20static void nxt_h1p_request_header_send(nxt_task_t *task, 21 nxt_http_request_t *r); 22static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, 23 nxt_buf_t *out); 24static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, 25 nxt_buf_t *out); 26static void nxt_h1p_sent(nxt_task_t *task, void *obj, void *data); 27static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto); 28static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, 29 nxt_conn_t *c); 30static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c); 31static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data); 32static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); 33static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data); 34static nxt_msec_t nxt_h1p_timeout_value(nxt_conn_t *c, uintptr_t data); 35 36 37static const nxt_conn_state_t nxt_h1p_idle_state; 38static const nxt_conn_state_t nxt_h1p_read_header_state; 39static const nxt_conn_state_t nxt_h1p_read_body_state; 40static const nxt_conn_state_t nxt_h1p_send_state; 41 42 43const nxt_http_proto_body_read_t nxt_http_proto_body_read[3] = { 44 nxt_h1p_request_body_read, 45 NULL, 46 NULL, 47}; 48 49 50const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = { 51 nxt_h1p_request_local_addr, 52 NULL, 53 NULL, 54}; 55 56 57const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = { 58 nxt_h1p_request_header_send, 59 NULL, 60 NULL, 61}; 62 63 64const nxt_http_proto_send_t nxt_http_proto_send[3] = { 65 nxt_h1p_request_send, 66 NULL, 67 NULL, 68}; 69 70 71const nxt_http_proto_close_t nxt_http_proto_close[3] = { 72 nxt_h1p_request_close, 73 NULL, 74 NULL, 75}; 76 77 78static nxt_lvlhsh_t nxt_h1p_fields_hash; 79 80static nxt_http_field_proc_t nxt_h1p_fields[] = { 81 { nxt_string("Connection"), &nxt_h1p_connection, 0 }, 82 { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 }, 83 84 { nxt_string("Host"), &nxt_http_request_host, 0 }, 85 { nxt_string("Cookie"), &nxt_http_request_field, 86 offsetof(nxt_http_request_t, cookie) }, 87 { nxt_string("Content-Type"), &nxt_http_request_field, 88 offsetof(nxt_http_request_t, content_type) }, 89 { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 }, 90}; 91 92 93nxt_int_t 94nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt) 95{ 96 return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool, 97 nxt_h1p_fields, nxt_nitems(nxt_h1p_fields)); 98} 99 100 101void 102nxt_http_conn_init(nxt_task_t *task, void *obj, void *data) 103{ 104 nxt_conn_t *c; 105 nxt_socket_conf_t *skcf; 106 nxt_event_engine_t *engine; 107 nxt_socket_conf_joint_t *joint; 108 109 c = obj; 110 joint = data; 111 112 nxt_debug(task, "http conn init"); 113 114 c->joint = joint; 115 joint->count++; 116 117 skcf = joint->socket_conf; 118 c->local = skcf->sockaddr; 119 c->socket.data = NULL; 120 121 engine = task->thread->engine; 122 c->read_work_queue = &engine->fast_work_queue; 123 c->write_work_queue = &engine->fast_work_queue; 124 125 c->read_state = &nxt_h1p_idle_state; 126 127 nxt_conn_wait(c); 128} 129 130 131static const nxt_conn_state_t nxt_h1p_idle_state 132 nxt_aligned(64) = 133{ 134 .ready_handler = nxt_h1p_read_header, 135 .close_handler = nxt_h1p_conn_close, 136 .error_handler = nxt_h1p_conn_error, 137 138 .timer_handler = nxt_h1p_conn_timeout, 139 .timer_value = nxt_h1p_timeout_value, 140 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), 141}; 142 143 144static void 145nxt_h1p_read_header(nxt_task_t *task, void *obj, void *data) 146{ 147 size_t size; 148 nxt_conn_t *c; 149 nxt_socket_conf_joint_t *joint; 150 151 c = obj; 152 153 nxt_debug(task, "h1p read header"); 154 155 if (c->read == NULL) { 156 joint = c->joint; 157 size = joint->socket_conf->header_buffer_size; 158 159 c->read = nxt_buf_mem_alloc(c->mem_pool, size, 0); 160 if (nxt_slow_path(c->read == NULL)) { 161 nxt_h1p_conn_error(task, c, c->socket.data); 162 return; 163 } 164 } 165 166 c->read_state = &nxt_h1p_read_header_state; 167 168 nxt_conn_read(task->thread->engine, c); 169} 170 171 172static const nxt_conn_state_t nxt_h1p_read_header_state 173 nxt_aligned(64) = 174{ 175 .ready_handler = nxt_h1p_header_parse, 176 .close_handler = nxt_h1p_conn_close, 177 .error_handler = nxt_h1p_conn_error, 178 179 .timer_handler = nxt_h1p_conn_timeout, 180 .timer_value = nxt_h1p_timeout_value, 181 .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 182}; 183 184 185static void 186nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data) 187{ 188 size_t size; 189 nxt_int_t ret; 190 nxt_buf_t *in, *b; 191 nxt_conn_t *c; 192 nxt_h1proto_t *h1p;
|
304 return; 305 306fail: 307 308 nxt_h1p_conn_close(task, c, h1p); 309} 310 311 312static nxt_int_t 313nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) 314{ 315 nxt_http_request_t *r; 316 317 r = ctx; 318 319 if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) { 320 r->proto.h1->keepalive = 0; 321 } 322 323 return NXT_OK; 324} 325 326 327static nxt_int_t 328nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data) 329{ 330 nxt_http_te_t te; 331 nxt_http_request_t *r; 332 333 r = ctx; 334 335 if (field->value_length == 7 336 && nxt_memcmp(field->value, "chunked", 7) == 0) 337 { 338 te = NXT_HTTP_TE_CHUNKED; 339 340 } else { 341 te = NXT_HTTP_TE_UNSUPPORTED; 342 } 343 344 r->proto.h1->transfer_encoding = te; 345 346 return NXT_OK; 347} 348 349 350static void 351nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r) 352{ 353 size_t size, rest_length; 354 nxt_buf_t *in, *b; 355 nxt_conn_t *c; 356 nxt_h1proto_t *h1p; 357 nxt_http_status_t status; 358 359 h1p = r->proto.h1; 360 361 nxt_debug(task, "h1p body read %O te:%d", 362 r->content_length_n, h1p->transfer_encoding); 363 364 switch (h1p->transfer_encoding) { 365 366 case NXT_HTTP_TE_CHUNKED: 367 status = NXT_HTTP_LENGTH_REQUIRED; 368 goto error; 369 370 case NXT_HTTP_TE_UNSUPPORTED: 371 status = NXT_HTTP_NOT_IMPLEMENTED; 372 goto error; 373 374 default: 375 case NXT_HTTP_TE_NONE: 376 break; 377 } 378 379 if (r->content_length_n == -1 || r->content_length_n == 0) { 380 goto ready; 381 } 382 383 if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) { 384 status = NXT_HTTP_PAYLOAD_TOO_LARGE; 385 goto error; 386 } 387 388 rest_length = (size_t) r->content_length_n; 389 390 b = r->body; 391 392 if (b == NULL) { 393 b = nxt_buf_mem_alloc(r->mem_pool, rest_length, 0); 394 if (nxt_slow_path(b == NULL)) { 395 status = NXT_HTTP_INTERNAL_SERVER_ERROR; 396 goto error; 397 } 398 399 r->body = b; 400 } 401 402 in = h1p->conn->read; 403 404 size = nxt_buf_mem_used_size(&in->mem); 405 406 if (size != 0) { 407 if (size >= rest_length) { 408 size = rest_length; 409 rest_length = 0; 410 411 } else { 412 rest_length -= size; 413 } 414 415 b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size); 416 in->mem.pos += size; 417 } 418 419 nxt_debug(task, "h1p body rest: %O", rest_length); 420 421 r->rest_length = rest_length; 422 423 if (rest_length != 0) { 424 in->next = h1p->buffers; 425 h1p->buffers = in; 426 427 c = h1p->conn; 428 c->read = b; 429 c->read_state = &nxt_h1p_read_body_state; 430 431 nxt_conn_read(task->thread->engine, c); 432 return; 433 } 434 435ready: 436 437 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 438 r->state->ready_handler, task, r, NULL); 439 440 return; 441 442error: 443 444 h1p->keepalive = 0; 445 446 nxt_http_request_error(task, r, status); 447} 448 449 450static const nxt_conn_state_t nxt_h1p_read_body_state 451 nxt_aligned(64) = 452{ 453 .ready_handler = nxt_h1p_body_read, 454 .close_handler = nxt_h1p_conn_close, 455 .error_handler = nxt_h1p_conn_error, 456 457 .timer_handler = nxt_h1p_conn_timeout, 458 .timer_value = nxt_h1p_timeout_value, 459 .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 460 .timer_autoreset = 1, 461}; 462 463 464static void 465nxt_h1p_body_read(nxt_task_t *task, void *obj, void *data) 466{ 467 size_t size; 468 nxt_conn_t *c; 469 nxt_h1proto_t *h1p; 470 nxt_http_request_t *r; 471 472 c = obj; 473 h1p = data; 474 475 nxt_debug(task, "h1p body read"); 476 477 r = h1p->request; 478 size = nxt_buf_mem_used_size(&c->read->mem); 479 480 r->rest_length -= size; 481 482 nxt_debug(task, "h1p body rest: %O", r->rest_length); 483 484 if (r->rest_length != 0) { 485 nxt_conn_read(task->thread->engine, c); 486 487 } else { 488 c->read = NULL; 489 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 490 r->state->ready_handler, task, r, NULL); 491 } 492} 493 494 495static void 496nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 497{ 498 r->local = nxt_conn_local_addr(task, r->proto.h1->conn); 499} 500 501 502#define NXT_HTTP_LAST_SUCCESS \ 503 (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) 504 505static const nxt_str_t nxt_http_success[] = { 506 nxt_string("HTTP/1.1 200 OK\r\n"), 507 nxt_string("HTTP/1.1 201 Created\r\n"), 508 nxt_string("HTTP/1.1 202 Accepted\r\n"), 509 nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"), 510 nxt_string("HTTP/1.1 204 No Content\r\n"), 511 nxt_string("HTTP/1.1 205 Reset Content\r\n"), 512 nxt_string("HTTP/1.1 206 Partial Content\r\n"), 513}; 514 515 516#define NXT_HTTP_LAST_REDIRECTION \ 517 (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1) 518 519static const nxt_str_t nxt_http_redirection[] = { 520 nxt_string("HTTP/1.1 300 Multiple Choices\r\n"), 521 nxt_string("HTTP/1.1 301 Moved Permanently\r\n"), 522 nxt_string("HTTP/1.1 302 Found\r\n"), 523 nxt_string("HTTP/1.1 303 See Other\r\n"), 524 nxt_string("HTTP/1.1 304 Not Modified\r\n"), 525}; 526 527 528#define NXT_HTTP_LAST_CLIENT_ERROR \ 529 (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1) 530 531static const nxt_str_t nxt_http_client_error[] = { 532 nxt_string("HTTP/1.1 400 Bad Request\r\n"), 533 nxt_string("HTTP/1.1 401 Unauthorized\r\n"), 534 nxt_string("HTTP/1.1 402 Payment Required\r\n"), 535 nxt_string("HTTP/1.1 403 Forbidden\r\n"), 536 nxt_string("HTTP/1.1 404 Not Found\r\n"), 537 nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"), 538 nxt_string("HTTP/1.1 406 Not Acceptable\r\n"), 539 nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"), 540 nxt_string("HTTP/1.1 408 Request Timeout\r\n"), 541 nxt_string("HTTP/1.1 409 Conflict\r\n"), 542 nxt_string("HTTP/1.1 410 Gone\r\n"), 543 nxt_string("HTTP/1.1 411 Length Required\r\n"), 544 nxt_string("HTTP/1.1 412 Precondition Failed\r\n"), 545 nxt_string("HTTP/1.1 413 Payload Too Large\r\n"), 546 nxt_string("HTTP/1.1 414 URI Too Long\r\n"), 547 nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"), 548 nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"), 549 nxt_string("HTTP/1.1 417 Expectation Failed\r\n"), 550 nxt_string("HTTP/1.1 418\r\n"), 551 nxt_string("HTTP/1.1 419\r\n"), 552 nxt_string("HTTP/1.1 420\r\n"), 553 nxt_string("HTTP/1.1 421\r\n"), 554 nxt_string("HTTP/1.1 422\r\n"), 555 nxt_string("HTTP/1.1 423\r\n"), 556 nxt_string("HTTP/1.1 424\r\n"), 557 nxt_string("HTTP/1.1 425\r\n"), 558 nxt_string("HTTP/1.1 426\r\n"), 559 nxt_string("HTTP/1.1 427\r\n"), 560 nxt_string("HTTP/1.1 428\r\n"), 561 nxt_string("HTTP/1.1 429\r\n"), 562 nxt_string("HTTP/1.1 430\r\n"), 563 nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"), 564}; 565 566 567#define NXT_HTTP_LAST_SERVER_ERROR \ 568 (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1) 569 570static const nxt_str_t nxt_http_server_error[] = { 571 nxt_string("HTTP/1.1 500 Internal Server Error\r\n"), 572 nxt_string("HTTP/1.1 501 Not Implemented\r\n"), 573 nxt_string("HTTP/1.1 502 Bad Gateway\r\n"), 574 nxt_string("HTTP/1.1 503 Service Unavailable\r\n"), 575 nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"), 576}; 577 578 579#define UNKNOWN_STATUS_LENGTH (sizeof("HTTP/1.1 65536\r\n") - 1) 580 581static void 582nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 583{ 584 u_char *p; 585 size_t size; 586 nxt_buf_t *header; 587 nxt_str_t unknown_status; 588 nxt_int_t conn; 589 nxt_uint_t n; 590 nxt_bool_t http11; 591 nxt_conn_t *c; 592 nxt_h1proto_t *h1p; 593 const nxt_str_t *status; 594 nxt_http_field_t *field; 595 nxt_event_engine_t *engine; 596 u_char buf[UNKNOWN_STATUS_LENGTH]; 597 598 static const char chunked[] = "Transfer-Encoding: chunked\r\n"; 599 600 static const nxt_str_t connection[2] = { 601 nxt_string("Connection: close\r\n"), 602 nxt_string("Connection: keep-alive\r\n"), 603 }; 604 605 nxt_debug(task, "h1p request header send"); 606 607 r->header_sent = 1; 608 h1p = r->proto.h1; 609 n = r->status; 610 611 if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) { 612 status = &nxt_http_success[n - NXT_HTTP_OK]; 613 614 } else if (n >= NXT_HTTP_MULTIPLE_CHOICES 615 && n <= NXT_HTTP_LAST_REDIRECTION) 616 { 617 status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES]; 618 619 } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) { 620 status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST]; 621 622 } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR 623 && n <= NXT_HTTP_LAST_SERVER_ERROR) 624 { 625 status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR]; 626 627 } else { 628 p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH, 629 "HTTP/1.1 %03d\r\n", n); 630 631 unknown_status.length = p - buf; 632 unknown_status.start = buf; 633 status = &unknown_status; 634 } 635 636 size = status->length; 637 /* Trailing CRLF at the end of header. */ 638 size += sizeof("\r\n") - 1; 639 640 http11 = (h1p->parser.version.str[7] != '0'); 641 642 if (r->resp.content_length == NULL || r->resp.content_length->skip) { 643 if (http11) { 644 h1p->chunked = 1; 645 size += sizeof(chunked) - 1; 646 /* Trailing CRLF will be added by the first chunk header. */ 647 size -= sizeof("\r\n") - 1; 648 649 } else { 650 h1p->keepalive = 0; 651 } 652 } 653 654 conn = -1; 655 656 if (http11 ^ h1p->keepalive) { 657 conn = h1p->keepalive; 658 size += connection[conn].length; 659 } 660 661 nxt_list_each(field, r->resp.fields) { 662 663 if (!field->skip) { 664 size += field->name_length + field->value_length; 665 size += sizeof(": \r\n") - 1; 666 } 667 668 } nxt_list_loop; 669 670 header = nxt_buf_mem_alloc(r->mem_pool, size, 0); 671 if (nxt_slow_path(header == NULL)) { 672 /* The internal server error is set just for logging. */ 673 r->status = NXT_HTTP_INTERNAL_SERVER_ERROR; 674 nxt_h1p_conn_close(task, h1p->conn, h1p); 675 return; 676 } 677 678 p = header->mem.free; 679 680 p = nxt_cpymem(p, status->start, status->length); 681 682 nxt_list_each(field, r->resp.fields) { 683 684 if (!field->skip) { 685 p = nxt_cpymem(p, field->name, field->name_length); 686 *p++ = ':'; *p++ = ' '; 687 p = nxt_cpymem(p, field->value, field->value_length); 688 *p++ = '\r'; *p++ = '\n'; 689 } 690 691 } nxt_list_loop; 692 693 if (conn >= 0) { 694 p = nxt_cpymem(p, connection[conn].start, connection[conn].length); 695 } 696 697 if (h1p->chunked) { 698 p = nxt_cpymem(p, chunked, sizeof(chunked) - 1); 699 /* Trailing CRLF will be added by the first chunk header. */ 700 701 } else { 702 *p++ = '\r'; *p++ = '\n'; 703 } 704 705 header->mem.free = p; 706 707 c = h1p->conn; 708 709 c->write = header; 710 c->write_state = &nxt_h1p_send_state; 711 712 engine = task->thread->engine; 713 714 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler, 715 task, r, NULL); 716 717 nxt_conn_write(engine, c); 718} 719 720 721static const nxt_conn_state_t nxt_h1p_send_state 722 nxt_aligned(64) = 723{ 724 .ready_handler = nxt_h1p_sent, 725 .close_handler = nxt_h1p_conn_close, 726 .error_handler = nxt_h1p_conn_error, 727 728 .timer_handler = nxt_h1p_conn_timeout, 729 .timer_value = nxt_h1p_timeout_value, 730 .timer_data = offsetof(nxt_socket_conf_t, send_timeout), 731 .timer_autoreset = 1, 732}; 733 734 735static void 736nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 737{ 738 nxt_conn_t *c; 739 740 nxt_debug(task, "h1p request send"); 741 742 c = r->proto.h1->conn; 743 744 if (r->proto.h1->chunked) { 745 out = nxt_h1p_chunk_create(task, r, out); 746 if (nxt_slow_path(out == NULL)) { 747 nxt_h1p_conn_error(task, c, c->socket.data); 748 return; 749 } 750 } 751 752 if (c->write == NULL) { 753 c->write = out; 754 c->write_state = &nxt_h1p_send_state; 755 756 nxt_conn_write(task->thread->engine, c); 757 758 } else { 759 nxt_buf_chain_add(&c->write, out); 760 } 761} 762 763 764static nxt_buf_t * 765nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 766{ 767 size_t size; 768 nxt_buf_t *b, **prev, *header, *tail; 769 770 const size_t chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN; 771 static const char tail_chunk[] = "\r\n0\r\n\r\n"; 772 773 size = 0; 774 prev = &out; 775 776 for (b = out; b != NULL; b = b->next) { 777 778 if (nxt_buf_is_last(b)) { 779 tail = nxt_buf_mem_alloc(r->mem_pool, chunk_size, 0); 780 if (nxt_slow_path(tail == NULL)) { 781 return NULL; 782 } 783 784 *prev = tail; 785 tail->next = b; 786 /* 787 * The tail_chunk size with trailing zero is 8 bytes, so 788 * memcpy may be inlined with just single 8 byte move operation. 789 */ 790 nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk)); 791 tail->mem.free += sizeof(tail_chunk) - 1; 792 793 break; 794 } 795 796 size += nxt_buf_used_size(b); 797 prev = &b->next; 798 } 799 800 if (size == 0) { 801 return out; 802 } 803 804 header = nxt_buf_mem_alloc(r->mem_pool, chunk_size, 0); 805 if (nxt_slow_path(header == NULL)) { 806 return NULL; 807 } 808 809 header->next = out; 810 header->mem.free = nxt_sprintf(header->mem.free, header->mem.end, 811 "\r\n%xO\r\n", size); 812 return header; 813} 814 815 816static void 817nxt_h1p_sent(nxt_task_t *task, void *obj, void *data) 818{ 819 nxt_conn_t *c; 820 nxt_event_engine_t *engine; 821 822 c = obj; 823 824 nxt_debug(task, "h1p sent"); 825 826 engine = task->thread->engine; 827 828 c->write = nxt_sendbuf_completion0(task, &engine->fast_work_queue, 829 c->write); 830 if (c->write != NULL) { 831 nxt_conn_write(engine, c); 832 } 833} 834 835 836static void 837nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto) 838{ 839 nxt_conn_t *c; 840 nxt_h1proto_t *h1p; 841 842 nxt_debug(task, "h1p request close"); 843 844 h1p = proto.h1; 845 h1p->request = NULL; 846 847 c = h1p->conn; 848 849 if (h1p->keepalive) { 850 nxt_h1p_keepalive(task, h1p, c); 851 852 } else { 853 nxt_h1p_close(task, c); 854 } 855} 856 857 858static void 859nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) 860{ 861 size_t size; 862 nxt_buf_t *in, *b, *next; 863 864 nxt_debug(task, "h1p keepalive"); 865 866 if (!c->tcp_nodelay) { 867 nxt_conn_tcp_nodelay_on(task, c); 868 } 869 870 b = h1p->buffers; 871 872 nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn)); 873 874 in = c->read; 875 876 if (in == NULL) { 877 /* A request with large body. */ 878 in = b; 879 c->read = in; 880 881 b = in->next; 882 in->next = NULL; 883 } 884 885 while (b != NULL) { 886 next = b->next; 887 nxt_mp_free(c->mem_pool, b); 888 b = next; 889 } 890 891 size = nxt_buf_mem_used_size(&in->mem); 892 893 if (size == 0) { 894 in->mem.pos = in->mem.start; 895 in->mem.free = in->mem.start; 896 897 if (c->socket.read_ready) { 898 c->read_state = &nxt_h1p_read_header_state; 899 nxt_conn_read(task->thread->engine, c); 900 901 } else { 902 c->read_state = &nxt_h1p_idle_state; 903 nxt_conn_wait(c); 904 } 905 906 } else { 907 nxt_debug(task, "h1p pipelining"); 908 909 nxt_memmove(in->mem.start, in->mem.pos, size); 910 911 in->mem.pos = in->mem.start; 912 in->mem.free = in->mem.start + size; 913 914 nxt_h1p_header_parse(task, c, c->socket.data); 915 } 916} 917 918 919static void 920nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c) 921{ 922 nxt_debug(task, "h1p close"); 923 924 c->socket.data = NULL; 925 926 if (c->socket.fd != -1) { 927 c->write_state = &nxt_router_conn_close_state; 928 929 nxt_conn_close(task->thread->engine, c); 930 } 931} 932 933 934static void 935nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) 936{ 937 nxt_conn_t *c; 938 nxt_h1proto_t *h1p; 939 nxt_http_request_t *r; 940 941 c = obj; 942 h1p = data; 943 944 nxt_debug(task, "h1p conn close"); 945 946 if (h1p != NULL) { 947 r = h1p->request; 948 949 if (r != NULL) { 950 r->state->error_handler(task, r, r->proto.h1); 951 return; 952 } 953 } 954 955 nxt_h1p_close(task, c); 956} 957 958 959static void 960nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) 961{ 962 nxt_conn_t *c; 963 nxt_h1proto_t *h1p; 964 965 c = obj; 966 h1p = data; 967 968 nxt_debug(task, "h1p conn error"); 969 970 nxt_h1p_conn_close(task, c, h1p); 971} 972 973 974static void 975nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) 976{ 977 nxt_conn_t *c; 978 nxt_timer_t *timer; 979 980 timer = obj; 981 982 nxt_debug(task, "h1p conn timeout"); 983 984 c = nxt_read_timer_conn(timer); 985 986 nxt_h1p_conn_close(task, c, c->socket.data); 987} 988 989 990static nxt_msec_t 991nxt_h1p_timeout_value(nxt_conn_t *c, uintptr_t data) 992{ 993 nxt_socket_conf_joint_t *joint; 994 995 joint = c->joint; 996 997 return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 998}
| 325 return; 326 327fail: 328 329 nxt_h1p_conn_close(task, c, h1p); 330} 331 332 333static nxt_int_t 334nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) 335{ 336 nxt_http_request_t *r; 337 338 r = ctx; 339 340 if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) { 341 r->proto.h1->keepalive = 0; 342 } 343 344 return NXT_OK; 345} 346 347 348static nxt_int_t 349nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data) 350{ 351 nxt_http_te_t te; 352 nxt_http_request_t *r; 353 354 r = ctx; 355 356 if (field->value_length == 7 357 && nxt_memcmp(field->value, "chunked", 7) == 0) 358 { 359 te = NXT_HTTP_TE_CHUNKED; 360 361 } else { 362 te = NXT_HTTP_TE_UNSUPPORTED; 363 } 364 365 r->proto.h1->transfer_encoding = te; 366 367 return NXT_OK; 368} 369 370 371static void 372nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r) 373{ 374 size_t size, rest_length; 375 nxt_buf_t *in, *b; 376 nxt_conn_t *c; 377 nxt_h1proto_t *h1p; 378 nxt_http_status_t status; 379 380 h1p = r->proto.h1; 381 382 nxt_debug(task, "h1p body read %O te:%d", 383 r->content_length_n, h1p->transfer_encoding); 384 385 switch (h1p->transfer_encoding) { 386 387 case NXT_HTTP_TE_CHUNKED: 388 status = NXT_HTTP_LENGTH_REQUIRED; 389 goto error; 390 391 case NXT_HTTP_TE_UNSUPPORTED: 392 status = NXT_HTTP_NOT_IMPLEMENTED; 393 goto error; 394 395 default: 396 case NXT_HTTP_TE_NONE: 397 break; 398 } 399 400 if (r->content_length_n == -1 || r->content_length_n == 0) { 401 goto ready; 402 } 403 404 if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) { 405 status = NXT_HTTP_PAYLOAD_TOO_LARGE; 406 goto error; 407 } 408 409 rest_length = (size_t) r->content_length_n; 410 411 b = r->body; 412 413 if (b == NULL) { 414 b = nxt_buf_mem_alloc(r->mem_pool, rest_length, 0); 415 if (nxt_slow_path(b == NULL)) { 416 status = NXT_HTTP_INTERNAL_SERVER_ERROR; 417 goto error; 418 } 419 420 r->body = b; 421 } 422 423 in = h1p->conn->read; 424 425 size = nxt_buf_mem_used_size(&in->mem); 426 427 if (size != 0) { 428 if (size >= rest_length) { 429 size = rest_length; 430 rest_length = 0; 431 432 } else { 433 rest_length -= size; 434 } 435 436 b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size); 437 in->mem.pos += size; 438 } 439 440 nxt_debug(task, "h1p body rest: %O", rest_length); 441 442 r->rest_length = rest_length; 443 444 if (rest_length != 0) { 445 in->next = h1p->buffers; 446 h1p->buffers = in; 447 448 c = h1p->conn; 449 c->read = b; 450 c->read_state = &nxt_h1p_read_body_state; 451 452 nxt_conn_read(task->thread->engine, c); 453 return; 454 } 455 456ready: 457 458 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 459 r->state->ready_handler, task, r, NULL); 460 461 return; 462 463error: 464 465 h1p->keepalive = 0; 466 467 nxt_http_request_error(task, r, status); 468} 469 470 471static const nxt_conn_state_t nxt_h1p_read_body_state 472 nxt_aligned(64) = 473{ 474 .ready_handler = nxt_h1p_body_read, 475 .close_handler = nxt_h1p_conn_close, 476 .error_handler = nxt_h1p_conn_error, 477 478 .timer_handler = nxt_h1p_conn_timeout, 479 .timer_value = nxt_h1p_timeout_value, 480 .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 481 .timer_autoreset = 1, 482}; 483 484 485static void 486nxt_h1p_body_read(nxt_task_t *task, void *obj, void *data) 487{ 488 size_t size; 489 nxt_conn_t *c; 490 nxt_h1proto_t *h1p; 491 nxt_http_request_t *r; 492 493 c = obj; 494 h1p = data; 495 496 nxt_debug(task, "h1p body read"); 497 498 r = h1p->request; 499 size = nxt_buf_mem_used_size(&c->read->mem); 500 501 r->rest_length -= size; 502 503 nxt_debug(task, "h1p body rest: %O", r->rest_length); 504 505 if (r->rest_length != 0) { 506 nxt_conn_read(task->thread->engine, c); 507 508 } else { 509 c->read = NULL; 510 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 511 r->state->ready_handler, task, r, NULL); 512 } 513} 514 515 516static void 517nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 518{ 519 r->local = nxt_conn_local_addr(task, r->proto.h1->conn); 520} 521 522 523#define NXT_HTTP_LAST_SUCCESS \ 524 (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) 525 526static const nxt_str_t nxt_http_success[] = { 527 nxt_string("HTTP/1.1 200 OK\r\n"), 528 nxt_string("HTTP/1.1 201 Created\r\n"), 529 nxt_string("HTTP/1.1 202 Accepted\r\n"), 530 nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"), 531 nxt_string("HTTP/1.1 204 No Content\r\n"), 532 nxt_string("HTTP/1.1 205 Reset Content\r\n"), 533 nxt_string("HTTP/1.1 206 Partial Content\r\n"), 534}; 535 536 537#define NXT_HTTP_LAST_REDIRECTION \ 538 (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1) 539 540static const nxt_str_t nxt_http_redirection[] = { 541 nxt_string("HTTP/1.1 300 Multiple Choices\r\n"), 542 nxt_string("HTTP/1.1 301 Moved Permanently\r\n"), 543 nxt_string("HTTP/1.1 302 Found\r\n"), 544 nxt_string("HTTP/1.1 303 See Other\r\n"), 545 nxt_string("HTTP/1.1 304 Not Modified\r\n"), 546}; 547 548 549#define NXT_HTTP_LAST_CLIENT_ERROR \ 550 (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1) 551 552static const nxt_str_t nxt_http_client_error[] = { 553 nxt_string("HTTP/1.1 400 Bad Request\r\n"), 554 nxt_string("HTTP/1.1 401 Unauthorized\r\n"), 555 nxt_string("HTTP/1.1 402 Payment Required\r\n"), 556 nxt_string("HTTP/1.1 403 Forbidden\r\n"), 557 nxt_string("HTTP/1.1 404 Not Found\r\n"), 558 nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"), 559 nxt_string("HTTP/1.1 406 Not Acceptable\r\n"), 560 nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"), 561 nxt_string("HTTP/1.1 408 Request Timeout\r\n"), 562 nxt_string("HTTP/1.1 409 Conflict\r\n"), 563 nxt_string("HTTP/1.1 410 Gone\r\n"), 564 nxt_string("HTTP/1.1 411 Length Required\r\n"), 565 nxt_string("HTTP/1.1 412 Precondition Failed\r\n"), 566 nxt_string("HTTP/1.1 413 Payload Too Large\r\n"), 567 nxt_string("HTTP/1.1 414 URI Too Long\r\n"), 568 nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"), 569 nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"), 570 nxt_string("HTTP/1.1 417 Expectation Failed\r\n"), 571 nxt_string("HTTP/1.1 418\r\n"), 572 nxt_string("HTTP/1.1 419\r\n"), 573 nxt_string("HTTP/1.1 420\r\n"), 574 nxt_string("HTTP/1.1 421\r\n"), 575 nxt_string("HTTP/1.1 422\r\n"), 576 nxt_string("HTTP/1.1 423\r\n"), 577 nxt_string("HTTP/1.1 424\r\n"), 578 nxt_string("HTTP/1.1 425\r\n"), 579 nxt_string("HTTP/1.1 426\r\n"), 580 nxt_string("HTTP/1.1 427\r\n"), 581 nxt_string("HTTP/1.1 428\r\n"), 582 nxt_string("HTTP/1.1 429\r\n"), 583 nxt_string("HTTP/1.1 430\r\n"), 584 nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"), 585}; 586 587 588#define NXT_HTTP_LAST_SERVER_ERROR \ 589 (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1) 590 591static const nxt_str_t nxt_http_server_error[] = { 592 nxt_string("HTTP/1.1 500 Internal Server Error\r\n"), 593 nxt_string("HTTP/1.1 501 Not Implemented\r\n"), 594 nxt_string("HTTP/1.1 502 Bad Gateway\r\n"), 595 nxt_string("HTTP/1.1 503 Service Unavailable\r\n"), 596 nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"), 597}; 598 599 600#define UNKNOWN_STATUS_LENGTH (sizeof("HTTP/1.1 65536\r\n") - 1) 601 602static void 603nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 604{ 605 u_char *p; 606 size_t size; 607 nxt_buf_t *header; 608 nxt_str_t unknown_status; 609 nxt_int_t conn; 610 nxt_uint_t n; 611 nxt_bool_t http11; 612 nxt_conn_t *c; 613 nxt_h1proto_t *h1p; 614 const nxt_str_t *status; 615 nxt_http_field_t *field; 616 nxt_event_engine_t *engine; 617 u_char buf[UNKNOWN_STATUS_LENGTH]; 618 619 static const char chunked[] = "Transfer-Encoding: chunked\r\n"; 620 621 static const nxt_str_t connection[2] = { 622 nxt_string("Connection: close\r\n"), 623 nxt_string("Connection: keep-alive\r\n"), 624 }; 625 626 nxt_debug(task, "h1p request header send"); 627 628 r->header_sent = 1; 629 h1p = r->proto.h1; 630 n = r->status; 631 632 if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) { 633 status = &nxt_http_success[n - NXT_HTTP_OK]; 634 635 } else if (n >= NXT_HTTP_MULTIPLE_CHOICES 636 && n <= NXT_HTTP_LAST_REDIRECTION) 637 { 638 status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES]; 639 640 } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) { 641 status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST]; 642 643 } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR 644 && n <= NXT_HTTP_LAST_SERVER_ERROR) 645 { 646 status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR]; 647 648 } else { 649 p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH, 650 "HTTP/1.1 %03d\r\n", n); 651 652 unknown_status.length = p - buf; 653 unknown_status.start = buf; 654 status = &unknown_status; 655 } 656 657 size = status->length; 658 /* Trailing CRLF at the end of header. */ 659 size += sizeof("\r\n") - 1; 660 661 http11 = (h1p->parser.version.str[7] != '0'); 662 663 if (r->resp.content_length == NULL || r->resp.content_length->skip) { 664 if (http11) { 665 h1p->chunked = 1; 666 size += sizeof(chunked) - 1; 667 /* Trailing CRLF will be added by the first chunk header. */ 668 size -= sizeof("\r\n") - 1; 669 670 } else { 671 h1p->keepalive = 0; 672 } 673 } 674 675 conn = -1; 676 677 if (http11 ^ h1p->keepalive) { 678 conn = h1p->keepalive; 679 size += connection[conn].length; 680 } 681 682 nxt_list_each(field, r->resp.fields) { 683 684 if (!field->skip) { 685 size += field->name_length + field->value_length; 686 size += sizeof(": \r\n") - 1; 687 } 688 689 } nxt_list_loop; 690 691 header = nxt_buf_mem_alloc(r->mem_pool, size, 0); 692 if (nxt_slow_path(header == NULL)) { 693 /* The internal server error is set just for logging. */ 694 r->status = NXT_HTTP_INTERNAL_SERVER_ERROR; 695 nxt_h1p_conn_close(task, h1p->conn, h1p); 696 return; 697 } 698 699 p = header->mem.free; 700 701 p = nxt_cpymem(p, status->start, status->length); 702 703 nxt_list_each(field, r->resp.fields) { 704 705 if (!field->skip) { 706 p = nxt_cpymem(p, field->name, field->name_length); 707 *p++ = ':'; *p++ = ' '; 708 p = nxt_cpymem(p, field->value, field->value_length); 709 *p++ = '\r'; *p++ = '\n'; 710 } 711 712 } nxt_list_loop; 713 714 if (conn >= 0) { 715 p = nxt_cpymem(p, connection[conn].start, connection[conn].length); 716 } 717 718 if (h1p->chunked) { 719 p = nxt_cpymem(p, chunked, sizeof(chunked) - 1); 720 /* Trailing CRLF will be added by the first chunk header. */ 721 722 } else { 723 *p++ = '\r'; *p++ = '\n'; 724 } 725 726 header->mem.free = p; 727 728 c = h1p->conn; 729 730 c->write = header; 731 c->write_state = &nxt_h1p_send_state; 732 733 engine = task->thread->engine; 734 735 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler, 736 task, r, NULL); 737 738 nxt_conn_write(engine, c); 739} 740 741 742static const nxt_conn_state_t nxt_h1p_send_state 743 nxt_aligned(64) = 744{ 745 .ready_handler = nxt_h1p_sent, 746 .close_handler = nxt_h1p_conn_close, 747 .error_handler = nxt_h1p_conn_error, 748 749 .timer_handler = nxt_h1p_conn_timeout, 750 .timer_value = nxt_h1p_timeout_value, 751 .timer_data = offsetof(nxt_socket_conf_t, send_timeout), 752 .timer_autoreset = 1, 753}; 754 755 756static void 757nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 758{ 759 nxt_conn_t *c; 760 761 nxt_debug(task, "h1p request send"); 762 763 c = r->proto.h1->conn; 764 765 if (r->proto.h1->chunked) { 766 out = nxt_h1p_chunk_create(task, r, out); 767 if (nxt_slow_path(out == NULL)) { 768 nxt_h1p_conn_error(task, c, c->socket.data); 769 return; 770 } 771 } 772 773 if (c->write == NULL) { 774 c->write = out; 775 c->write_state = &nxt_h1p_send_state; 776 777 nxt_conn_write(task->thread->engine, c); 778 779 } else { 780 nxt_buf_chain_add(&c->write, out); 781 } 782} 783 784 785static nxt_buf_t * 786nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 787{ 788 size_t size; 789 nxt_buf_t *b, **prev, *header, *tail; 790 791 const size_t chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN; 792 static const char tail_chunk[] = "\r\n0\r\n\r\n"; 793 794 size = 0; 795 prev = &out; 796 797 for (b = out; b != NULL; b = b->next) { 798 799 if (nxt_buf_is_last(b)) { 800 tail = nxt_buf_mem_alloc(r->mem_pool, chunk_size, 0); 801 if (nxt_slow_path(tail == NULL)) { 802 return NULL; 803 } 804 805 *prev = tail; 806 tail->next = b; 807 /* 808 * The tail_chunk size with trailing zero is 8 bytes, so 809 * memcpy may be inlined with just single 8 byte move operation. 810 */ 811 nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk)); 812 tail->mem.free += sizeof(tail_chunk) - 1; 813 814 break; 815 } 816 817 size += nxt_buf_used_size(b); 818 prev = &b->next; 819 } 820 821 if (size == 0) { 822 return out; 823 } 824 825 header = nxt_buf_mem_alloc(r->mem_pool, chunk_size, 0); 826 if (nxt_slow_path(header == NULL)) { 827 return NULL; 828 } 829 830 header->next = out; 831 header->mem.free = nxt_sprintf(header->mem.free, header->mem.end, 832 "\r\n%xO\r\n", size); 833 return header; 834} 835 836 837static void 838nxt_h1p_sent(nxt_task_t *task, void *obj, void *data) 839{ 840 nxt_conn_t *c; 841 nxt_event_engine_t *engine; 842 843 c = obj; 844 845 nxt_debug(task, "h1p sent"); 846 847 engine = task->thread->engine; 848 849 c->write = nxt_sendbuf_completion0(task, &engine->fast_work_queue, 850 c->write); 851 if (c->write != NULL) { 852 nxt_conn_write(engine, c); 853 } 854} 855 856 857static void 858nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto) 859{ 860 nxt_conn_t *c; 861 nxt_h1proto_t *h1p; 862 863 nxt_debug(task, "h1p request close"); 864 865 h1p = proto.h1; 866 h1p->request = NULL; 867 868 c = h1p->conn; 869 870 if (h1p->keepalive) { 871 nxt_h1p_keepalive(task, h1p, c); 872 873 } else { 874 nxt_h1p_close(task, c); 875 } 876} 877 878 879static void 880nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) 881{ 882 size_t size; 883 nxt_buf_t *in, *b, *next; 884 885 nxt_debug(task, "h1p keepalive"); 886 887 if (!c->tcp_nodelay) { 888 nxt_conn_tcp_nodelay_on(task, c); 889 } 890 891 b = h1p->buffers; 892 893 nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn)); 894 895 in = c->read; 896 897 if (in == NULL) { 898 /* A request with large body. */ 899 in = b; 900 c->read = in; 901 902 b = in->next; 903 in->next = NULL; 904 } 905 906 while (b != NULL) { 907 next = b->next; 908 nxt_mp_free(c->mem_pool, b); 909 b = next; 910 } 911 912 size = nxt_buf_mem_used_size(&in->mem); 913 914 if (size == 0) { 915 in->mem.pos = in->mem.start; 916 in->mem.free = in->mem.start; 917 918 if (c->socket.read_ready) { 919 c->read_state = &nxt_h1p_read_header_state; 920 nxt_conn_read(task->thread->engine, c); 921 922 } else { 923 c->read_state = &nxt_h1p_idle_state; 924 nxt_conn_wait(c); 925 } 926 927 } else { 928 nxt_debug(task, "h1p pipelining"); 929 930 nxt_memmove(in->mem.start, in->mem.pos, size); 931 932 in->mem.pos = in->mem.start; 933 in->mem.free = in->mem.start + size; 934 935 nxt_h1p_header_parse(task, c, c->socket.data); 936 } 937} 938 939 940static void 941nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c) 942{ 943 nxt_debug(task, "h1p close"); 944 945 c->socket.data = NULL; 946 947 if (c->socket.fd != -1) { 948 c->write_state = &nxt_router_conn_close_state; 949 950 nxt_conn_close(task->thread->engine, c); 951 } 952} 953 954 955static void 956nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) 957{ 958 nxt_conn_t *c; 959 nxt_h1proto_t *h1p; 960 nxt_http_request_t *r; 961 962 c = obj; 963 h1p = data; 964 965 nxt_debug(task, "h1p conn close"); 966 967 if (h1p != NULL) { 968 r = h1p->request; 969 970 if (r != NULL) { 971 r->state->error_handler(task, r, r->proto.h1); 972 return; 973 } 974 } 975 976 nxt_h1p_close(task, c); 977} 978 979 980static void 981nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) 982{ 983 nxt_conn_t *c; 984 nxt_h1proto_t *h1p; 985 986 c = obj; 987 h1p = data; 988 989 nxt_debug(task, "h1p conn error"); 990 991 nxt_h1p_conn_close(task, c, h1p); 992} 993 994 995static void 996nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) 997{ 998 nxt_conn_t *c; 999 nxt_timer_t *timer; 1000 1001 timer = obj; 1002 1003 nxt_debug(task, "h1p conn timeout"); 1004 1005 c = nxt_read_timer_conn(timer); 1006 1007 nxt_h1p_conn_close(task, c, c->socket.data); 1008} 1009 1010 1011static nxt_msec_t 1012nxt_h1p_timeout_value(nxt_conn_t *c, uintptr_t data) 1013{ 1014 nxt_socket_conf_joint_t *joint; 1015 1016 joint = c->joint; 1017 1018 return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 1019}
|