nxt_h1proto.c (683:5c7dd85fabd5) nxt_h1proto.c (703:2d536dde84d2)
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/*
12 * nxt_h1p_conn_ prefix is used for connection handlers.
13 * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods.
14 */
15
16static ssize_t nxt_h1p_conn_io_read_handler(nxt_conn_t *c);
17static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data);
18static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data);
19static void nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj,
20 void *data);
21static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p,
22 nxt_http_request_t *r);
23static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task,
24 nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf);
25static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field,
26 uintptr_t data);
27static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field,
28 uintptr_t data);
29static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
30static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
31 void *data);
32static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
33static void nxt_h1p_request_header_send(nxt_task_t *task,
34 nxt_http_request_t *r);
35static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
36 nxt_buf_t *out);
37static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r,
38 nxt_buf_t *out);
39static void nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data);
40static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task,
41 nxt_http_proto_t proto);
42static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
43 nxt_buf_t *last);
44static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
45 nxt_socket_conf_joint_t *joint);
46static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p,
47 nxt_conn_t *c);
48static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data);
49static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data);
50static nxt_msec_t nxt_h1p_conn_timeout_value(nxt_conn_t *c,
51 uintptr_t data);
52static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c);
53static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data);
54static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data);
55static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj,
56 void *data);
57static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj,
58 void *data);
59static nxt_msec_t nxt_h1p_conn_request_timeout_value(nxt_conn_t *c,
60 uintptr_t data);
61nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r);
62
63
64static const nxt_conn_state_t nxt_h1p_idle_state;
65static const nxt_conn_state_t nxt_h1p_header_parse_state;
66static const nxt_conn_state_t nxt_h1p_read_body_state;
67static const nxt_conn_state_t nxt_h1p_send_state;
68static const nxt_conn_state_t nxt_h1p_keepalive_state;
69static const nxt_conn_state_t nxt_h1p_close_state;
70
71
72const nxt_http_proto_body_read_t nxt_http_proto_body_read[3] = {
73 nxt_h1p_request_body_read,
74 NULL,
75 NULL,
76};
77
78
79const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = {
80 nxt_h1p_request_local_addr,
81 NULL,
82 NULL,
83};
84
85
86const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = {
87 nxt_h1p_request_header_send,
88 NULL,
89 NULL,
90};
91
92
93const nxt_http_proto_send_t nxt_http_proto_send[3] = {
94 nxt_h1p_request_send,
95 NULL,
96 NULL,
97};
98
99
100const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[3] = {
101 nxt_h1p_request_body_bytes_sent,
102 NULL,
103 NULL,
104};
105
106
107const nxt_http_proto_discard_t nxt_http_proto_discard[3] = {
108 nxt_h1p_request_discard,
109 NULL,
110 NULL,
111};
112
113
114const nxt_http_proto_close_t nxt_http_proto_close[3] = {
115 nxt_h1p_request_close,
116 NULL,
117 NULL,
118};
119
120
121static nxt_lvlhsh_t nxt_h1p_fields_hash;
122
123static nxt_http_field_proc_t nxt_h1p_fields[] = {
124 { nxt_string("Connection"), &nxt_h1p_connection, 0 },
125 { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 },
126
127 { nxt_string("Host"), &nxt_http_request_host, 0 },
128 { nxt_string("Cookie"), &nxt_http_request_field,
129 offsetof(nxt_http_request_t, cookie) },
130 { nxt_string("Referer"), &nxt_http_request_field,
131 offsetof(nxt_http_request_t, referer) },
132 { nxt_string("User-Agent"), &nxt_http_request_field,
133 offsetof(nxt_http_request_t, user_agent) },
134 { nxt_string("Content-Type"), &nxt_http_request_field,
135 offsetof(nxt_http_request_t, content_type) },
136 { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 },
137};
138
139
140nxt_int_t
141nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt)
142{
143 return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool,
144 nxt_h1p_fields, nxt_nitems(nxt_h1p_fields));
145}
146
147
148void
149nxt_http_conn_init(nxt_task_t *task, void *obj, void *data)
150{
151 nxt_conn_t *c;
152 nxt_socket_conf_t *skcf;
153 nxt_event_engine_t *engine;
154 nxt_listen_event_t *lev;
155 nxt_socket_conf_joint_t *joint;
156
157 c = obj;
158 lev = data;
159
160 nxt_debug(task, "http conn init");
161
162 joint = lev->socket.data;
163 skcf = joint->socket_conf;
164 c->local = skcf->sockaddr;
165
166 engine = task->thread->engine;
167 c->read_work_queue = &engine->fast_work_queue;
168 c->write_work_queue = &engine->fast_work_queue;
169
170 c->read_state = &nxt_h1p_idle_state;
171
172 nxt_conn_read(engine, c);
173}
174
175
176static const nxt_conn_state_t nxt_h1p_idle_state
177 nxt_aligned(64) =
178{
179 .ready_handler = nxt_h1p_conn_proto_init,
180 .close_handler = nxt_h1p_conn_error,
181 .error_handler = nxt_h1p_conn_error,
182
183 .io_read_handler = nxt_h1p_conn_io_read_handler,
184
185 .timer_handler = nxt_h1p_conn_timeout,
186 .timer_value = nxt_h1p_conn_timeout_value,
187 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
188 .timer_autoreset = 1,
189};
190
191
192static ssize_t
193nxt_h1p_conn_io_read_handler(nxt_conn_t *c)
194{
195 size_t size;
196 ssize_t n;
197 nxt_buf_t *b;
198 nxt_socket_conf_joint_t *joint;
199
200 joint = c->listen->socket.data;
201 size = joint->socket_conf->header_buffer_size;
202
203 b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
204 if (nxt_slow_path(b == NULL)) {
205 c->socket.error = NXT_ENOMEM;
206 return NXT_ERROR;
207 }
208
209 n = c->io->recvbuf(c, b);
210
211 if (n > 0) {
212 c->read = b;
213
214 } else {
215 nxt_mp_free(c->mem_pool, b);
216 }
217
218 return n;
219}
220
221
222static void
223nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data)
224{
225 nxt_conn_t *c;
226 nxt_h1proto_t *h1p;
227
228 c = obj;
229
230 nxt_debug(task, "h1p conn proto init");
231
232 h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t));
233 if (nxt_slow_path(h1p == NULL)) {
234 nxt_h1p_close(task, c);
235 return;
236 }
237
238 c->socket.data = h1p;
239 h1p->conn = c;
240
241 nxt_h1p_conn_request_init(task, c, h1p);
242}
243
244
245static void
246nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
247{
248 nxt_int_t ret;
249 nxt_conn_t *c;
250 nxt_h1proto_t *h1p;
251 nxt_http_request_t *r;
252 nxt_socket_conf_joint_t *joint;
253
254 c = obj;
255 h1p = data;
256
257 nxt_debug(task, "h1p conn request init");
258
259 r = nxt_http_request_create(task);
260
261 if (nxt_fast_path(r != NULL)) {
262 h1p->request = r;
263 r->proto.h1 = h1p;
264
265 r->remote = c->remote;
266
267 ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
268
269 if (nxt_fast_path(ret == NXT_OK)) {
270 joint = c->listen->socket.data;
271 joint->count++;
272
273 r->conf = joint;
274 c->local = joint->socket_conf->sockaddr;
275
276 nxt_h1p_conn_request_header_parse(task, c, h1p);
277 return;
278 }
279
280 /*
281 * The request is very incomplete here,
282 * so "internal server error" useless here.
283 */
284 nxt_mp_release(r->mem_pool);
285 }
286
287 nxt_h1p_close(task, c);
288}
289
290
291static const nxt_conn_state_t nxt_h1p_header_parse_state
292 nxt_aligned(64) =
293{
294 .ready_handler = nxt_h1p_conn_request_header_parse,
295 .close_handler = nxt_h1p_conn_request_error,
296 .error_handler = nxt_h1p_conn_request_error,
297
298 .timer_handler = nxt_h1p_conn_request_timeout,
299 .timer_value = nxt_h1p_conn_request_timeout_value,
300 .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
301};
302
303
304static void
305nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, void *data)
306{
307 nxt_int_t ret;
308 nxt_conn_t *c;
309 nxt_h1proto_t *h1p;
310 nxt_http_status_t status;
311 nxt_http_request_t *r;
312
313 c = obj;
314 h1p = data;
315
316 nxt_debug(task, "h1p conn header parse");
317
318 ret = nxt_http_parse_request(&h1p->parser, &c->read->mem);
319
320 ret = nxt_expect(NXT_DONE, ret);
321
322 if (ret != NXT_AGAIN) {
323 nxt_timer_disable(task->thread->engine, &c->read_timer);
324 }
325
326 r = h1p->request;
327
328 switch (ret) {
329
330 case NXT_DONE:
331 /*
332 * By default the keepalive mode is disabled in HTTP/1.0 and
333 * enabled in HTTP/1.1. The mode can be overridden later by
334 * the "Connection" field processed in nxt_h1p_connection().
335 */
336 h1p->keepalive = (h1p->parser.version.s.minor != '0');
337
338 ret = nxt_h1p_header_process(h1p, r);
339
340 if (nxt_fast_path(ret == NXT_OK)) {
341 r->state->ready_handler(task, r, NULL);
342 return;
343 }
344
345 /* ret == NXT_ERROR */
346 status = NXT_HTTP_BAD_REQUEST;
347
348 goto error;
349
350 case NXT_AGAIN:
351 status = nxt_h1p_header_buffer_test(task, h1p, c, r->conf->socket_conf);
352
353 if (nxt_fast_path(status == NXT_OK)) {
354 c->read_state = &nxt_h1p_header_parse_state;
355
356 nxt_conn_read(task->thread->engine, c);
357 return;
358 }
359
360 break;
361
362 case NXT_HTTP_PARSE_INVALID:
363 status = NXT_HTTP_BAD_REQUEST;
364 break;
365
366 case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
367 status = NXT_HTTP_VERSION_NOT_SUPPORTED;
368 break;
369
370 case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
371 status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
372 break;
373
374 default:
375 case NXT_ERROR:
376 status = NXT_HTTP_INTERNAL_SERVER_ERROR;
377 break;
378 }
379
380 (void) nxt_h1p_header_process(h1p, r);
381
382error:
383
384 nxt_http_request_error(task, r, status);
385}
386
387
388static nxt_int_t
389nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r)
390{
391 r->target.start = h1p->parser.target_start;
392 r->target.length = h1p->parser.target_end - h1p->parser.target_start;
393
394 if (h1p->parser.version.ui64 != 0) {
395 r->version.start = h1p->parser.version.str;
396 r->version.length = sizeof(h1p->parser.version.str);
397 }
398
399 r->method = &h1p->parser.method;
400 r->path = &h1p->parser.path;
401 r->args = &h1p->parser.args;
402
403 r->fields = h1p->parser.fields;
404
405 return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r);
406}
407
408
409static nxt_int_t
410nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
411 nxt_socket_conf_t *skcf)
412{
413 size_t size, used;
414 nxt_buf_t *in, *b;
415
416 in = c->read;
417
418 if (nxt_buf_mem_free_size(&in->mem) == 0) {
419 size = skcf->large_header_buffer_size;
420 used = nxt_buf_mem_used_size(&in->mem);
421
422 if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
423 return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
424 }
425
426 b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
427 if (nxt_slow_path(b == NULL)) {
428 return NXT_HTTP_INTERNAL_SERVER_ERROR;
429 }
430
431 b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
432
433 in->next = h1p->buffers;
434 h1p->buffers = in;
435 h1p->nbuffers++;
436
437 c->read = b;
438 }
439
440 return NXT_OK;
441}
442
443
444static nxt_int_t
445nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
446{
447 nxt_http_request_t *r;
448
449 r = ctx;
450
451 if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) {
452 r->proto.h1->keepalive = 0;
453 }
454
455 return NXT_OK;
456}
457
458
459static nxt_int_t
460nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data)
461{
462 nxt_http_te_t te;
463 nxt_http_request_t *r;
464
465 r = ctx;
466
467 if (field->value_length == 7
468 && nxt_memcmp(field->value, "chunked", 7) == 0)
469 {
470 te = NXT_HTTP_TE_CHUNKED;
471
472 } else {
473 te = NXT_HTTP_TE_UNSUPPORTED;
474 }
475
476 r->proto.h1->transfer_encoding = te;
477
478 return NXT_OK;
479}
480
481
482static void
483nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
484{
485 size_t size, body_length;
486 nxt_buf_t *in, *b;
487 nxt_conn_t *c;
488 nxt_h1proto_t *h1p;
489 nxt_http_status_t status;
490
491 h1p = r->proto.h1;
492
493 nxt_debug(task, "h1p request body read %O te:%d",
494 r->content_length_n, h1p->transfer_encoding);
495
496 switch (h1p->transfer_encoding) {
497
498 case NXT_HTTP_TE_CHUNKED:
499 status = NXT_HTTP_LENGTH_REQUIRED;
500 goto error;
501
502 case NXT_HTTP_TE_UNSUPPORTED:
503 status = NXT_HTTP_NOT_IMPLEMENTED;
504 goto error;
505
506 default:
507 case NXT_HTTP_TE_NONE:
508 break;
509 }
510
511 if (r->content_length_n == -1 || r->content_length_n == 0) {
512 goto ready;
513 }
514
515 if (r->content_length_n > (nxt_off_t) r->conf->socket_conf->max_body_size) {
516 status = NXT_HTTP_PAYLOAD_TOO_LARGE;
517 goto error;
518 }
519
520 body_length = (size_t) r->content_length_n;
521
522 b = r->body;
523
524 if (b == NULL) {
525 b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0);
526 if (nxt_slow_path(b == NULL)) {
527 status = NXT_HTTP_INTERNAL_SERVER_ERROR;
528 goto error;
529 }
530
531 r->body = b;
532 }
533
534 in = h1p->conn->read;
535
536 size = nxt_buf_mem_used_size(&in->mem);
537
538 if (size != 0) {
539 if (size > body_length) {
540 size = body_length;
541 }
542
543 b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
544 in->mem.pos += size;
545 }
546
547 size = nxt_buf_mem_free_size(&b->mem);
548
549 nxt_debug(task, "h1p body rest: %uz", size);
550
551 if (size != 0) {
552 in->next = h1p->buffers;
553 h1p->buffers = in;
554
555 c = h1p->conn;
556 c->read = b;
557 c->read_state = &nxt_h1p_read_body_state;
558
559 nxt_conn_read(task->thread->engine, c);
560 return;
561 }
562
563ready:
564
565 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
566 r->state->ready_handler, task, r, NULL);
567
568 return;
569
570error:
571
572 h1p->keepalive = 0;
573
574 nxt_http_request_error(task, r, status);
575}
576
577
578static const nxt_conn_state_t nxt_h1p_read_body_state
579 nxt_aligned(64) =
580{
581 .ready_handler = nxt_h1p_conn_request_body_read,
582 .close_handler = nxt_h1p_conn_request_error,
583 .error_handler = nxt_h1p_conn_request_error,
584
585 .timer_handler = nxt_h1p_conn_request_timeout,
586 .timer_value = nxt_h1p_conn_request_timeout_value,
587 .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
588 .timer_autoreset = 1,
589};
590
591
592static void
593nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, void *data)
594{
595 size_t size;
596 nxt_conn_t *c;
597 nxt_h1proto_t *h1p;
598 nxt_http_request_t *r;
599 nxt_event_engine_t *engine;
600
601 c = obj;
602 h1p = data;
603
604 nxt_debug(task, "h1p conn request body read");
605
606 size = nxt_buf_mem_free_size(&c->read->mem);
607
608 nxt_debug(task, "h1p body rest: %uz", size);
609
610 engine = task->thread->engine;
611
612 if (size != 0) {
613 nxt_conn_read(engine, c);
614
615 } else {
616 c->read = NULL;
617 r = h1p->request;
618
619 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
620 task, r, NULL);
621 }
622}
623
624
625static void
626nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
627{
628 r->local = nxt_conn_local_addr(task, r->proto.h1->conn);
629}
630
631
632#define NXT_HTTP_LAST_SUCCESS \
633 (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
634
635static const nxt_str_t nxt_http_success[] = {
636 nxt_string("HTTP/1.1 200 OK\r\n"),
637 nxt_string("HTTP/1.1 201 Created\r\n"),
638 nxt_string("HTTP/1.1 202 Accepted\r\n"),
639 nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"),
640 nxt_string("HTTP/1.1 204 No Content\r\n"),
641 nxt_string("HTTP/1.1 205 Reset Content\r\n"),
642 nxt_string("HTTP/1.1 206 Partial Content\r\n"),
643};
644
645
646#define NXT_HTTP_LAST_REDIRECTION \
647 (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1)
648
649static const nxt_str_t nxt_http_redirection[] = {
650 nxt_string("HTTP/1.1 300 Multiple Choices\r\n"),
651 nxt_string("HTTP/1.1 301 Moved Permanently\r\n"),
652 nxt_string("HTTP/1.1 302 Found\r\n"),
653 nxt_string("HTTP/1.1 303 See Other\r\n"),
654 nxt_string("HTTP/1.1 304 Not Modified\r\n"),
655};
656
657
658#define NXT_HTTP_LAST_CLIENT_ERROR \
659 (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1)
660
661static const nxt_str_t nxt_http_client_error[] = {
662 nxt_string("HTTP/1.1 400 Bad Request\r\n"),
663 nxt_string("HTTP/1.1 401 Unauthorized\r\n"),
664 nxt_string("HTTP/1.1 402 Payment Required\r\n"),
665 nxt_string("HTTP/1.1 403 Forbidden\r\n"),
666 nxt_string("HTTP/1.1 404 Not Found\r\n"),
667 nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"),
668 nxt_string("HTTP/1.1 406 Not Acceptable\r\n"),
669 nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"),
670 nxt_string("HTTP/1.1 408 Request Timeout\r\n"),
671 nxt_string("HTTP/1.1 409 Conflict\r\n"),
672 nxt_string("HTTP/1.1 410 Gone\r\n"),
673 nxt_string("HTTP/1.1 411 Length Required\r\n"),
674 nxt_string("HTTP/1.1 412 Precondition Failed\r\n"),
675 nxt_string("HTTP/1.1 413 Payload Too Large\r\n"),
676 nxt_string("HTTP/1.1 414 URI Too Long\r\n"),
677 nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"),
678 nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"),
679 nxt_string("HTTP/1.1 417 Expectation Failed\r\n"),
680 nxt_string("HTTP/1.1 418\r\n"),
681 nxt_string("HTTP/1.1 419\r\n"),
682 nxt_string("HTTP/1.1 420\r\n"),
683 nxt_string("HTTP/1.1 421\r\n"),
684 nxt_string("HTTP/1.1 422\r\n"),
685 nxt_string("HTTP/1.1 423\r\n"),
686 nxt_string("HTTP/1.1 424\r\n"),
687 nxt_string("HTTP/1.1 425\r\n"),
688 nxt_string("HTTP/1.1 426\r\n"),
689 nxt_string("HTTP/1.1 427\r\n"),
690 nxt_string("HTTP/1.1 428\r\n"),
691 nxt_string("HTTP/1.1 429\r\n"),
692 nxt_string("HTTP/1.1 430\r\n"),
693 nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"),
694};
695
696
697#define NXT_HTTP_LAST_SERVER_ERROR \
698 (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1)
699
700static const nxt_str_t nxt_http_server_error[] = {
701 nxt_string("HTTP/1.1 500 Internal Server Error\r\n"),
702 nxt_string("HTTP/1.1 501 Not Implemented\r\n"),
703 nxt_string("HTTP/1.1 502 Bad Gateway\r\n"),
704 nxt_string("HTTP/1.1 503 Service Unavailable\r\n"),
705 nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"),
706 nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"),
707};
708
709
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/*
12 * nxt_h1p_conn_ prefix is used for connection handlers.
13 * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods.
14 */
15
16static ssize_t nxt_h1p_conn_io_read_handler(nxt_conn_t *c);
17static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data);
18static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data);
19static void nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj,
20 void *data);
21static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p,
22 nxt_http_request_t *r);
23static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task,
24 nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf);
25static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field,
26 uintptr_t data);
27static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field,
28 uintptr_t data);
29static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
30static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
31 void *data);
32static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
33static void nxt_h1p_request_header_send(nxt_task_t *task,
34 nxt_http_request_t *r);
35static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
36 nxt_buf_t *out);
37static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r,
38 nxt_buf_t *out);
39static void nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data);
40static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task,
41 nxt_http_proto_t proto);
42static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
43 nxt_buf_t *last);
44static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
45 nxt_socket_conf_joint_t *joint);
46static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p,
47 nxt_conn_t *c);
48static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data);
49static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data);
50static nxt_msec_t nxt_h1p_conn_timeout_value(nxt_conn_t *c,
51 uintptr_t data);
52static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c);
53static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data);
54static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data);
55static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj,
56 void *data);
57static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj,
58 void *data);
59static nxt_msec_t nxt_h1p_conn_request_timeout_value(nxt_conn_t *c,
60 uintptr_t data);
61nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r);
62
63
64static const nxt_conn_state_t nxt_h1p_idle_state;
65static const nxt_conn_state_t nxt_h1p_header_parse_state;
66static const nxt_conn_state_t nxt_h1p_read_body_state;
67static const nxt_conn_state_t nxt_h1p_send_state;
68static const nxt_conn_state_t nxt_h1p_keepalive_state;
69static const nxt_conn_state_t nxt_h1p_close_state;
70
71
72const nxt_http_proto_body_read_t nxt_http_proto_body_read[3] = {
73 nxt_h1p_request_body_read,
74 NULL,
75 NULL,
76};
77
78
79const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = {
80 nxt_h1p_request_local_addr,
81 NULL,
82 NULL,
83};
84
85
86const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = {
87 nxt_h1p_request_header_send,
88 NULL,
89 NULL,
90};
91
92
93const nxt_http_proto_send_t nxt_http_proto_send[3] = {
94 nxt_h1p_request_send,
95 NULL,
96 NULL,
97};
98
99
100const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[3] = {
101 nxt_h1p_request_body_bytes_sent,
102 NULL,
103 NULL,
104};
105
106
107const nxt_http_proto_discard_t nxt_http_proto_discard[3] = {
108 nxt_h1p_request_discard,
109 NULL,
110 NULL,
111};
112
113
114const nxt_http_proto_close_t nxt_http_proto_close[3] = {
115 nxt_h1p_request_close,
116 NULL,
117 NULL,
118};
119
120
121static nxt_lvlhsh_t nxt_h1p_fields_hash;
122
123static nxt_http_field_proc_t nxt_h1p_fields[] = {
124 { nxt_string("Connection"), &nxt_h1p_connection, 0 },
125 { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 },
126
127 { nxt_string("Host"), &nxt_http_request_host, 0 },
128 { nxt_string("Cookie"), &nxt_http_request_field,
129 offsetof(nxt_http_request_t, cookie) },
130 { nxt_string("Referer"), &nxt_http_request_field,
131 offsetof(nxt_http_request_t, referer) },
132 { nxt_string("User-Agent"), &nxt_http_request_field,
133 offsetof(nxt_http_request_t, user_agent) },
134 { nxt_string("Content-Type"), &nxt_http_request_field,
135 offsetof(nxt_http_request_t, content_type) },
136 { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 },
137};
138
139
140nxt_int_t
141nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt)
142{
143 return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool,
144 nxt_h1p_fields, nxt_nitems(nxt_h1p_fields));
145}
146
147
148void
149nxt_http_conn_init(nxt_task_t *task, void *obj, void *data)
150{
151 nxt_conn_t *c;
152 nxt_socket_conf_t *skcf;
153 nxt_event_engine_t *engine;
154 nxt_listen_event_t *lev;
155 nxt_socket_conf_joint_t *joint;
156
157 c = obj;
158 lev = data;
159
160 nxt_debug(task, "http conn init");
161
162 joint = lev->socket.data;
163 skcf = joint->socket_conf;
164 c->local = skcf->sockaddr;
165
166 engine = task->thread->engine;
167 c->read_work_queue = &engine->fast_work_queue;
168 c->write_work_queue = &engine->fast_work_queue;
169
170 c->read_state = &nxt_h1p_idle_state;
171
172 nxt_conn_read(engine, c);
173}
174
175
176static const nxt_conn_state_t nxt_h1p_idle_state
177 nxt_aligned(64) =
178{
179 .ready_handler = nxt_h1p_conn_proto_init,
180 .close_handler = nxt_h1p_conn_error,
181 .error_handler = nxt_h1p_conn_error,
182
183 .io_read_handler = nxt_h1p_conn_io_read_handler,
184
185 .timer_handler = nxt_h1p_conn_timeout,
186 .timer_value = nxt_h1p_conn_timeout_value,
187 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
188 .timer_autoreset = 1,
189};
190
191
192static ssize_t
193nxt_h1p_conn_io_read_handler(nxt_conn_t *c)
194{
195 size_t size;
196 ssize_t n;
197 nxt_buf_t *b;
198 nxt_socket_conf_joint_t *joint;
199
200 joint = c->listen->socket.data;
201 size = joint->socket_conf->header_buffer_size;
202
203 b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
204 if (nxt_slow_path(b == NULL)) {
205 c->socket.error = NXT_ENOMEM;
206 return NXT_ERROR;
207 }
208
209 n = c->io->recvbuf(c, b);
210
211 if (n > 0) {
212 c->read = b;
213
214 } else {
215 nxt_mp_free(c->mem_pool, b);
216 }
217
218 return n;
219}
220
221
222static void
223nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data)
224{
225 nxt_conn_t *c;
226 nxt_h1proto_t *h1p;
227
228 c = obj;
229
230 nxt_debug(task, "h1p conn proto init");
231
232 h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t));
233 if (nxt_slow_path(h1p == NULL)) {
234 nxt_h1p_close(task, c);
235 return;
236 }
237
238 c->socket.data = h1p;
239 h1p->conn = c;
240
241 nxt_h1p_conn_request_init(task, c, h1p);
242}
243
244
245static void
246nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
247{
248 nxt_int_t ret;
249 nxt_conn_t *c;
250 nxt_h1proto_t *h1p;
251 nxt_http_request_t *r;
252 nxt_socket_conf_joint_t *joint;
253
254 c = obj;
255 h1p = data;
256
257 nxt_debug(task, "h1p conn request init");
258
259 r = nxt_http_request_create(task);
260
261 if (nxt_fast_path(r != NULL)) {
262 h1p->request = r;
263 r->proto.h1 = h1p;
264
265 r->remote = c->remote;
266
267 ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
268
269 if (nxt_fast_path(ret == NXT_OK)) {
270 joint = c->listen->socket.data;
271 joint->count++;
272
273 r->conf = joint;
274 c->local = joint->socket_conf->sockaddr;
275
276 nxt_h1p_conn_request_header_parse(task, c, h1p);
277 return;
278 }
279
280 /*
281 * The request is very incomplete here,
282 * so "internal server error" useless here.
283 */
284 nxt_mp_release(r->mem_pool);
285 }
286
287 nxt_h1p_close(task, c);
288}
289
290
291static const nxt_conn_state_t nxt_h1p_header_parse_state
292 nxt_aligned(64) =
293{
294 .ready_handler = nxt_h1p_conn_request_header_parse,
295 .close_handler = nxt_h1p_conn_request_error,
296 .error_handler = nxt_h1p_conn_request_error,
297
298 .timer_handler = nxt_h1p_conn_request_timeout,
299 .timer_value = nxt_h1p_conn_request_timeout_value,
300 .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
301};
302
303
304static void
305nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, void *data)
306{
307 nxt_int_t ret;
308 nxt_conn_t *c;
309 nxt_h1proto_t *h1p;
310 nxt_http_status_t status;
311 nxt_http_request_t *r;
312
313 c = obj;
314 h1p = data;
315
316 nxt_debug(task, "h1p conn header parse");
317
318 ret = nxt_http_parse_request(&h1p->parser, &c->read->mem);
319
320 ret = nxt_expect(NXT_DONE, ret);
321
322 if (ret != NXT_AGAIN) {
323 nxt_timer_disable(task->thread->engine, &c->read_timer);
324 }
325
326 r = h1p->request;
327
328 switch (ret) {
329
330 case NXT_DONE:
331 /*
332 * By default the keepalive mode is disabled in HTTP/1.0 and
333 * enabled in HTTP/1.1. The mode can be overridden later by
334 * the "Connection" field processed in nxt_h1p_connection().
335 */
336 h1p->keepalive = (h1p->parser.version.s.minor != '0');
337
338 ret = nxt_h1p_header_process(h1p, r);
339
340 if (nxt_fast_path(ret == NXT_OK)) {
341 r->state->ready_handler(task, r, NULL);
342 return;
343 }
344
345 /* ret == NXT_ERROR */
346 status = NXT_HTTP_BAD_REQUEST;
347
348 goto error;
349
350 case NXT_AGAIN:
351 status = nxt_h1p_header_buffer_test(task, h1p, c, r->conf->socket_conf);
352
353 if (nxt_fast_path(status == NXT_OK)) {
354 c->read_state = &nxt_h1p_header_parse_state;
355
356 nxt_conn_read(task->thread->engine, c);
357 return;
358 }
359
360 break;
361
362 case NXT_HTTP_PARSE_INVALID:
363 status = NXT_HTTP_BAD_REQUEST;
364 break;
365
366 case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
367 status = NXT_HTTP_VERSION_NOT_SUPPORTED;
368 break;
369
370 case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
371 status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
372 break;
373
374 default:
375 case NXT_ERROR:
376 status = NXT_HTTP_INTERNAL_SERVER_ERROR;
377 break;
378 }
379
380 (void) nxt_h1p_header_process(h1p, r);
381
382error:
383
384 nxt_http_request_error(task, r, status);
385}
386
387
388static nxt_int_t
389nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r)
390{
391 r->target.start = h1p->parser.target_start;
392 r->target.length = h1p->parser.target_end - h1p->parser.target_start;
393
394 if (h1p->parser.version.ui64 != 0) {
395 r->version.start = h1p->parser.version.str;
396 r->version.length = sizeof(h1p->parser.version.str);
397 }
398
399 r->method = &h1p->parser.method;
400 r->path = &h1p->parser.path;
401 r->args = &h1p->parser.args;
402
403 r->fields = h1p->parser.fields;
404
405 return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r);
406}
407
408
409static nxt_int_t
410nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
411 nxt_socket_conf_t *skcf)
412{
413 size_t size, used;
414 nxt_buf_t *in, *b;
415
416 in = c->read;
417
418 if (nxt_buf_mem_free_size(&in->mem) == 0) {
419 size = skcf->large_header_buffer_size;
420 used = nxt_buf_mem_used_size(&in->mem);
421
422 if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
423 return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
424 }
425
426 b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
427 if (nxt_slow_path(b == NULL)) {
428 return NXT_HTTP_INTERNAL_SERVER_ERROR;
429 }
430
431 b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
432
433 in->next = h1p->buffers;
434 h1p->buffers = in;
435 h1p->nbuffers++;
436
437 c->read = b;
438 }
439
440 return NXT_OK;
441}
442
443
444static nxt_int_t
445nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
446{
447 nxt_http_request_t *r;
448
449 r = ctx;
450
451 if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) {
452 r->proto.h1->keepalive = 0;
453 }
454
455 return NXT_OK;
456}
457
458
459static nxt_int_t
460nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data)
461{
462 nxt_http_te_t te;
463 nxt_http_request_t *r;
464
465 r = ctx;
466
467 if (field->value_length == 7
468 && nxt_memcmp(field->value, "chunked", 7) == 0)
469 {
470 te = NXT_HTTP_TE_CHUNKED;
471
472 } else {
473 te = NXT_HTTP_TE_UNSUPPORTED;
474 }
475
476 r->proto.h1->transfer_encoding = te;
477
478 return NXT_OK;
479}
480
481
482static void
483nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
484{
485 size_t size, body_length;
486 nxt_buf_t *in, *b;
487 nxt_conn_t *c;
488 nxt_h1proto_t *h1p;
489 nxt_http_status_t status;
490
491 h1p = r->proto.h1;
492
493 nxt_debug(task, "h1p request body read %O te:%d",
494 r->content_length_n, h1p->transfer_encoding);
495
496 switch (h1p->transfer_encoding) {
497
498 case NXT_HTTP_TE_CHUNKED:
499 status = NXT_HTTP_LENGTH_REQUIRED;
500 goto error;
501
502 case NXT_HTTP_TE_UNSUPPORTED:
503 status = NXT_HTTP_NOT_IMPLEMENTED;
504 goto error;
505
506 default:
507 case NXT_HTTP_TE_NONE:
508 break;
509 }
510
511 if (r->content_length_n == -1 || r->content_length_n == 0) {
512 goto ready;
513 }
514
515 if (r->content_length_n > (nxt_off_t) r->conf->socket_conf->max_body_size) {
516 status = NXT_HTTP_PAYLOAD_TOO_LARGE;
517 goto error;
518 }
519
520 body_length = (size_t) r->content_length_n;
521
522 b = r->body;
523
524 if (b == NULL) {
525 b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0);
526 if (nxt_slow_path(b == NULL)) {
527 status = NXT_HTTP_INTERNAL_SERVER_ERROR;
528 goto error;
529 }
530
531 r->body = b;
532 }
533
534 in = h1p->conn->read;
535
536 size = nxt_buf_mem_used_size(&in->mem);
537
538 if (size != 0) {
539 if (size > body_length) {
540 size = body_length;
541 }
542
543 b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
544 in->mem.pos += size;
545 }
546
547 size = nxt_buf_mem_free_size(&b->mem);
548
549 nxt_debug(task, "h1p body rest: %uz", size);
550
551 if (size != 0) {
552 in->next = h1p->buffers;
553 h1p->buffers = in;
554
555 c = h1p->conn;
556 c->read = b;
557 c->read_state = &nxt_h1p_read_body_state;
558
559 nxt_conn_read(task->thread->engine, c);
560 return;
561 }
562
563ready:
564
565 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
566 r->state->ready_handler, task, r, NULL);
567
568 return;
569
570error:
571
572 h1p->keepalive = 0;
573
574 nxt_http_request_error(task, r, status);
575}
576
577
578static const nxt_conn_state_t nxt_h1p_read_body_state
579 nxt_aligned(64) =
580{
581 .ready_handler = nxt_h1p_conn_request_body_read,
582 .close_handler = nxt_h1p_conn_request_error,
583 .error_handler = nxt_h1p_conn_request_error,
584
585 .timer_handler = nxt_h1p_conn_request_timeout,
586 .timer_value = nxt_h1p_conn_request_timeout_value,
587 .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
588 .timer_autoreset = 1,
589};
590
591
592static void
593nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, void *data)
594{
595 size_t size;
596 nxt_conn_t *c;
597 nxt_h1proto_t *h1p;
598 nxt_http_request_t *r;
599 nxt_event_engine_t *engine;
600
601 c = obj;
602 h1p = data;
603
604 nxt_debug(task, "h1p conn request body read");
605
606 size = nxt_buf_mem_free_size(&c->read->mem);
607
608 nxt_debug(task, "h1p body rest: %uz", size);
609
610 engine = task->thread->engine;
611
612 if (size != 0) {
613 nxt_conn_read(engine, c);
614
615 } else {
616 c->read = NULL;
617 r = h1p->request;
618
619 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
620 task, r, NULL);
621 }
622}
623
624
625static void
626nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
627{
628 r->local = nxt_conn_local_addr(task, r->proto.h1->conn);
629}
630
631
632#define NXT_HTTP_LAST_SUCCESS \
633 (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
634
635static const nxt_str_t nxt_http_success[] = {
636 nxt_string("HTTP/1.1 200 OK\r\n"),
637 nxt_string("HTTP/1.1 201 Created\r\n"),
638 nxt_string("HTTP/1.1 202 Accepted\r\n"),
639 nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"),
640 nxt_string("HTTP/1.1 204 No Content\r\n"),
641 nxt_string("HTTP/1.1 205 Reset Content\r\n"),
642 nxt_string("HTTP/1.1 206 Partial Content\r\n"),
643};
644
645
646#define NXT_HTTP_LAST_REDIRECTION \
647 (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1)
648
649static const nxt_str_t nxt_http_redirection[] = {
650 nxt_string("HTTP/1.1 300 Multiple Choices\r\n"),
651 nxt_string("HTTP/1.1 301 Moved Permanently\r\n"),
652 nxt_string("HTTP/1.1 302 Found\r\n"),
653 nxt_string("HTTP/1.1 303 See Other\r\n"),
654 nxt_string("HTTP/1.1 304 Not Modified\r\n"),
655};
656
657
658#define NXT_HTTP_LAST_CLIENT_ERROR \
659 (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1)
660
661static const nxt_str_t nxt_http_client_error[] = {
662 nxt_string("HTTP/1.1 400 Bad Request\r\n"),
663 nxt_string("HTTP/1.1 401 Unauthorized\r\n"),
664 nxt_string("HTTP/1.1 402 Payment Required\r\n"),
665 nxt_string("HTTP/1.1 403 Forbidden\r\n"),
666 nxt_string("HTTP/1.1 404 Not Found\r\n"),
667 nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"),
668 nxt_string("HTTP/1.1 406 Not Acceptable\r\n"),
669 nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"),
670 nxt_string("HTTP/1.1 408 Request Timeout\r\n"),
671 nxt_string("HTTP/1.1 409 Conflict\r\n"),
672 nxt_string("HTTP/1.1 410 Gone\r\n"),
673 nxt_string("HTTP/1.1 411 Length Required\r\n"),
674 nxt_string("HTTP/1.1 412 Precondition Failed\r\n"),
675 nxt_string("HTTP/1.1 413 Payload Too Large\r\n"),
676 nxt_string("HTTP/1.1 414 URI Too Long\r\n"),
677 nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"),
678 nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"),
679 nxt_string("HTTP/1.1 417 Expectation Failed\r\n"),
680 nxt_string("HTTP/1.1 418\r\n"),
681 nxt_string("HTTP/1.1 419\r\n"),
682 nxt_string("HTTP/1.1 420\r\n"),
683 nxt_string("HTTP/1.1 421\r\n"),
684 nxt_string("HTTP/1.1 422\r\n"),
685 nxt_string("HTTP/1.1 423\r\n"),
686 nxt_string("HTTP/1.1 424\r\n"),
687 nxt_string("HTTP/1.1 425\r\n"),
688 nxt_string("HTTP/1.1 426\r\n"),
689 nxt_string("HTTP/1.1 427\r\n"),
690 nxt_string("HTTP/1.1 428\r\n"),
691 nxt_string("HTTP/1.1 429\r\n"),
692 nxt_string("HTTP/1.1 430\r\n"),
693 nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"),
694};
695
696
697#define NXT_HTTP_LAST_SERVER_ERROR \
698 (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1)
699
700static const nxt_str_t nxt_http_server_error[] = {
701 nxt_string("HTTP/1.1 500 Internal Server Error\r\n"),
702 nxt_string("HTTP/1.1 501 Not Implemented\r\n"),
703 nxt_string("HTTP/1.1 502 Bad Gateway\r\n"),
704 nxt_string("HTTP/1.1 503 Service Unavailable\r\n"),
705 nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"),
706 nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"),
707};
708
709
710#define UNKNOWN_STATUS_LENGTH (sizeof("HTTP/1.1 65536\r\n") - 1)
710#define UNKNOWN_STATUS_LENGTH nxt_length("HTTP/1.1 65536\r\n")
711
712static void
713nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
714{
715 u_char *p;
716 size_t size;
717 nxt_buf_t *header;
718 nxt_str_t unknown_status;
719 nxt_int_t conn;
720 nxt_uint_t n;
721 nxt_bool_t http11;
722 nxt_conn_t *c;
723 nxt_h1proto_t *h1p;
724 const nxt_str_t *status;
725 nxt_http_field_t *field;
726 nxt_event_engine_t *engine;
727 u_char buf[UNKNOWN_STATUS_LENGTH];
728
729 static const char chunked[] = "Transfer-Encoding: chunked\r\n";
730
731 static const nxt_str_t connection[2] = {
732 nxt_string("Connection: close\r\n"),
733 nxt_string("Connection: keep-alive\r\n"),
734 };
735
736 nxt_debug(task, "h1p request header send");
737
738 r->header_sent = 1;
739 h1p = r->proto.h1;
740 n = r->status;
741
742 if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) {
743 status = &nxt_http_success[n - NXT_HTTP_OK];
744
745 } else if (n >= NXT_HTTP_MULTIPLE_CHOICES
746 && n <= NXT_HTTP_LAST_REDIRECTION)
747 {
748 status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES];
749
750 } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) {
751 status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST];
752
753 } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR
754 && n <= NXT_HTTP_LAST_SERVER_ERROR)
755 {
756 status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR];
757
758 } else {
759 p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH,
760 "HTTP/1.1 %03d\r\n", n);
761
762 unknown_status.length = p - buf;
763 unknown_status.start = buf;
764 status = &unknown_status;
765 }
766
767 size = status->length;
768 /* Trailing CRLF at the end of header. */
711
712static void
713nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
714{
715 u_char *p;
716 size_t size;
717 nxt_buf_t *header;
718 nxt_str_t unknown_status;
719 nxt_int_t conn;
720 nxt_uint_t n;
721 nxt_bool_t http11;
722 nxt_conn_t *c;
723 nxt_h1proto_t *h1p;
724 const nxt_str_t *status;
725 nxt_http_field_t *field;
726 nxt_event_engine_t *engine;
727 u_char buf[UNKNOWN_STATUS_LENGTH];
728
729 static const char chunked[] = "Transfer-Encoding: chunked\r\n";
730
731 static const nxt_str_t connection[2] = {
732 nxt_string("Connection: close\r\n"),
733 nxt_string("Connection: keep-alive\r\n"),
734 };
735
736 nxt_debug(task, "h1p request header send");
737
738 r->header_sent = 1;
739 h1p = r->proto.h1;
740 n = r->status;
741
742 if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) {
743 status = &nxt_http_success[n - NXT_HTTP_OK];
744
745 } else if (n >= NXT_HTTP_MULTIPLE_CHOICES
746 && n <= NXT_HTTP_LAST_REDIRECTION)
747 {
748 status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES];
749
750 } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) {
751 status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST];
752
753 } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR
754 && n <= NXT_HTTP_LAST_SERVER_ERROR)
755 {
756 status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR];
757
758 } else {
759 p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH,
760 "HTTP/1.1 %03d\r\n", n);
761
762 unknown_status.length = p - buf;
763 unknown_status.start = buf;
764 status = &unknown_status;
765 }
766
767 size = status->length;
768 /* Trailing CRLF at the end of header. */
769 size += sizeof("\r\n") - 1;
769 size += nxt_length("\r\n");
770
771 http11 = (h1p->parser.version.s.minor != '0');
772
773 if (r->resp.content_length == NULL || r->resp.content_length->skip) {
774 if (http11) {
775 h1p->chunked = 1;
770
771 http11 = (h1p->parser.version.s.minor != '0');
772
773 if (r->resp.content_length == NULL || r->resp.content_length->skip) {
774 if (http11) {
775 h1p->chunked = 1;
776 size += sizeof(chunked) - 1;
776 size += nxt_length(chunked);
777 /* Trailing CRLF will be added by the first chunk header. */
777 /* Trailing CRLF will be added by the first chunk header. */
778 size -= sizeof("\r\n") - 1;
778 size -= nxt_length("\r\n");
779
780 } else {
781 h1p->keepalive = 0;
782 }
783 }
784
785 conn = -1;
786
787 if (http11 ^ h1p->keepalive) {
788 conn = h1p->keepalive;
789 size += connection[conn].length;
790 }
791
792 nxt_list_each(field, r->resp.fields) {
793
794 if (!field->skip) {
795 size += field->name_length + field->value_length;
779
780 } else {
781 h1p->keepalive = 0;
782 }
783 }
784
785 conn = -1;
786
787 if (http11 ^ h1p->keepalive) {
788 conn = h1p->keepalive;
789 size += connection[conn].length;
790 }
791
792 nxt_list_each(field, r->resp.fields) {
793
794 if (!field->skip) {
795 size += field->name_length + field->value_length;
796 size += sizeof(": \r\n") - 1;
796 size += nxt_length(": \r\n");
797 }
798
799 } nxt_list_loop;
800
801 header = nxt_http_buf_mem(task, r, size);
802 if (nxt_slow_path(header == NULL)) {
803 nxt_h1p_request_error(task, r);
804 return;
805 }
806
807 p = header->mem.free;
808
809 p = nxt_cpymem(p, status->start, status->length);
810
811 nxt_list_each(field, r->resp.fields) {
812
813 if (!field->skip) {
814 p = nxt_cpymem(p, field->name, field->name_length);
815 *p++ = ':'; *p++ = ' ';
816 p = nxt_cpymem(p, field->value, field->value_length);
817 *p++ = '\r'; *p++ = '\n';
818 }
819
820 } nxt_list_loop;
821
822 if (conn >= 0) {
823 p = nxt_cpymem(p, connection[conn].start, connection[conn].length);
824 }
825
826 if (h1p->chunked) {
797 }
798
799 } nxt_list_loop;
800
801 header = nxt_http_buf_mem(task, r, size);
802 if (nxt_slow_path(header == NULL)) {
803 nxt_h1p_request_error(task, r);
804 return;
805 }
806
807 p = header->mem.free;
808
809 p = nxt_cpymem(p, status->start, status->length);
810
811 nxt_list_each(field, r->resp.fields) {
812
813 if (!field->skip) {
814 p = nxt_cpymem(p, field->name, field->name_length);
815 *p++ = ':'; *p++ = ' ';
816 p = nxt_cpymem(p, field->value, field->value_length);
817 *p++ = '\r'; *p++ = '\n';
818 }
819
820 } nxt_list_loop;
821
822 if (conn >= 0) {
823 p = nxt_cpymem(p, connection[conn].start, connection[conn].length);
824 }
825
826 if (h1p->chunked) {
827 p = nxt_cpymem(p, chunked, sizeof(chunked) - 1);
827 p = nxt_cpymem(p, chunked, nxt_length(chunked));
828 /* Trailing CRLF will be added by the first chunk header. */
829
830 } else {
831 *p++ = '\r'; *p++ = '\n';
832 }
833
834 header->mem.free = p;
835
836 h1p->header_size = nxt_buf_mem_used_size(&header->mem);
837
838 c = h1p->conn;
839
840 c->write = header;
841 c->write_state = &nxt_h1p_send_state;
842
843 engine = task->thread->engine;
844
845 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
846 task, r, NULL);
847
848 nxt_conn_write(engine, c);
849}
850
851
852static const nxt_conn_state_t nxt_h1p_send_state
853 nxt_aligned(64) =
854{
855 .ready_handler = nxt_h1p_conn_request_sent,
856 .error_handler = nxt_h1p_conn_request_error,
857
858 .timer_handler = nxt_h1p_conn_request_send_timeout,
859 .timer_value = nxt_h1p_conn_request_timeout_value,
860 .timer_data = offsetof(nxt_socket_conf_t, send_timeout),
861 .timer_autoreset = 1,
862};
863
864
865static void
866nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
867{
868 nxt_conn_t *c;
869
870 nxt_debug(task, "h1p request send");
871
872 c = r->proto.h1->conn;
873
874 if (r->proto.h1->chunked) {
875 out = nxt_h1p_chunk_create(task, r, out);
876 if (nxt_slow_path(out == NULL)) {
877 nxt_h1p_request_error(task, r);
878 return;
879 }
880 }
881
882 if (c->write == NULL) {
883 c->write = out;
884 c->write_state = &nxt_h1p_send_state;
885
886 nxt_conn_write(task->thread->engine, c);
887
888 } else {
889 nxt_buf_chain_add(&c->write, out);
890 }
891}
892
893
894static nxt_buf_t *
895nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
896{
897 nxt_off_t size;
898 nxt_buf_t *b, **prev, *header, *tail;
899
828 /* Trailing CRLF will be added by the first chunk header. */
829
830 } else {
831 *p++ = '\r'; *p++ = '\n';
832 }
833
834 header->mem.free = p;
835
836 h1p->header_size = nxt_buf_mem_used_size(&header->mem);
837
838 c = h1p->conn;
839
840 c->write = header;
841 c->write_state = &nxt_h1p_send_state;
842
843 engine = task->thread->engine;
844
845 nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
846 task, r, NULL);
847
848 nxt_conn_write(engine, c);
849}
850
851
852static const nxt_conn_state_t nxt_h1p_send_state
853 nxt_aligned(64) =
854{
855 .ready_handler = nxt_h1p_conn_request_sent,
856 .error_handler = nxt_h1p_conn_request_error,
857
858 .timer_handler = nxt_h1p_conn_request_send_timeout,
859 .timer_value = nxt_h1p_conn_request_timeout_value,
860 .timer_data = offsetof(nxt_socket_conf_t, send_timeout),
861 .timer_autoreset = 1,
862};
863
864
865static void
866nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
867{
868 nxt_conn_t *c;
869
870 nxt_debug(task, "h1p request send");
871
872 c = r->proto.h1->conn;
873
874 if (r->proto.h1->chunked) {
875 out = nxt_h1p_chunk_create(task, r, out);
876 if (nxt_slow_path(out == NULL)) {
877 nxt_h1p_request_error(task, r);
878 return;
879 }
880 }
881
882 if (c->write == NULL) {
883 c->write = out;
884 c->write_state = &nxt_h1p_send_state;
885
886 nxt_conn_write(task->thread->engine, c);
887
888 } else {
889 nxt_buf_chain_add(&c->write, out);
890 }
891}
892
893
894static nxt_buf_t *
895nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
896{
897 nxt_off_t size;
898 nxt_buf_t *b, **prev, *header, *tail;
899
900 const size_t chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN;
900 const size_t chunk_size = 2 * nxt_length("\r\n") + NXT_OFF_T_HEXLEN;
901 static const char tail_chunk[] = "\r\n0\r\n\r\n";
902
903 size = 0;
904 prev = &out;
905
906 for (b = out; b != NULL; b = b->next) {
907
908 if (nxt_buf_is_last(b)) {
909 tail = nxt_http_buf_mem(task, r, chunk_size);
910 if (nxt_slow_path(tail == NULL)) {
911 return NULL;
912 }
913
914 *prev = tail;
915 tail->next = b;
916 /*
917 * The tail_chunk size with trailing zero is 8 bytes, so
918 * memcpy may be inlined with just single 8 byte move operation.
919 */
920 nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk));
901 static const char tail_chunk[] = "\r\n0\r\n\r\n";
902
903 size = 0;
904 prev = &out;
905
906 for (b = out; b != NULL; b = b->next) {
907
908 if (nxt_buf_is_last(b)) {
909 tail = nxt_http_buf_mem(task, r, chunk_size);
910 if (nxt_slow_path(tail == NULL)) {
911 return NULL;
912 }
913
914 *prev = tail;
915 tail->next = b;
916 /*
917 * The tail_chunk size with trailing zero is 8 bytes, so
918 * memcpy may be inlined with just single 8 byte move operation.
919 */
920 nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk));
921 tail->mem.free += sizeof(tail_chunk) - 1;
921 tail->mem.free += nxt_length(tail_chunk);
922
923 break;
924 }
925
926 size += nxt_buf_used_size(b);
927 prev = &b->next;
928 }
929
930 if (size == 0) {
931 return out;
932 }
933
934 header = nxt_http_buf_mem(task, r, chunk_size);
935 if (nxt_slow_path(header == NULL)) {
936 return NULL;
937 }
938
939 header->next = out;
940 header->mem.free = nxt_sprintf(header->mem.free, header->mem.end,
941 "\r\n%xO\r\n", size);
942 return header;
943}
944
945
946static void
947nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data)
948{
949 nxt_conn_t *c;
950 nxt_event_engine_t *engine;
951
952 c = obj;
953
954 nxt_debug(task, "h1p conn request sent");
955
956 engine = task->thread->engine;
957
958 c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
959
960 if (c->write != NULL) {
961 nxt_conn_write(engine, c);
962 }
963}
964
965
966static nxt_off_t
967nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto)
968{
969 nxt_off_t sent;
970 nxt_h1proto_t *h1p;
971
972 h1p = proto.h1;
973
974 sent = h1p->conn->sent - h1p->header_size;
975
976 return (sent > 0) ? sent : 0;
977}
978
979
980static void
981nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
982 nxt_buf_t *last)
983{
984 nxt_buf_t *b;
985 nxt_conn_t *c;
986 nxt_h1proto_t *h1p;
987 nxt_work_queue_t *wq;
988
989 nxt_debug(task, "h1p request discard");
990
991 h1p = r->proto.h1;
992 h1p->keepalive = 0;
993
994 c = h1p->conn;
995 b = c->write;
996 c->write = NULL;
997
998 wq = &task->thread->engine->fast_work_queue;
999
1000 nxt_sendbuf_drain(task, wq, b);
1001 nxt_sendbuf_drain(task, wq, last);
1002}
1003
1004
1005static void
1006nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
1007 nxt_socket_conf_joint_t *joint)
1008{
1009 nxt_conn_t *c;
1010 nxt_h1proto_t *h1p;
1011
1012 nxt_debug(task, "h1p request close");
1013
1014 h1p = proto.h1;
1015 h1p->request = NULL;
1016
1017 nxt_router_conf_release(task, joint);
1018
1019 c = h1p->conn;
1020
1021 if (h1p->keepalive) {
1022 nxt_h1p_keepalive(task, h1p, c);
1023
1024 } else {
1025 nxt_h1p_close(task, c);
1026 }
1027}
1028
1029
1030static void
1031nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c)
1032{
1033 size_t size;
1034 nxt_buf_t *in, *b, *next;
1035
1036 nxt_debug(task, "h1p keepalive");
1037
1038 if (!c->tcp_nodelay) {
1039 nxt_conn_tcp_nodelay_on(task, c);
1040 }
1041
1042 b = h1p->buffers;
1043
1044 nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn));
1045
1046 c->sent = 0;
1047
1048 in = c->read;
1049
1050 if (in == NULL) {
1051 /* A request with large body. */
1052 in = b;
1053 c->read = in;
1054
1055 b = in->next;
1056 in->next = NULL;
1057 }
1058
1059 while (b != NULL) {
1060 next = b->next;
1061 nxt_mp_free(c->mem_pool, b);
1062 b = next;
1063 }
1064
1065 size = nxt_buf_mem_used_size(&in->mem);
1066
1067 if (size == 0) {
1068 nxt_mp_free(c->mem_pool, in);
1069
1070 c->read = NULL;
1071 c->read_state = &nxt_h1p_keepalive_state;
1072
1073 nxt_conn_read(task->thread->engine, c);
1074
1075 } else {
1076 nxt_debug(task, "h1p pipelining");
1077
1078 nxt_memmove(in->mem.start, in->mem.pos, size);
1079
1080 in->mem.pos = in->mem.start;
1081 in->mem.free = in->mem.start + size;
1082
1083 nxt_h1p_conn_request_init(task, c, c->socket.data);
1084 }
1085}
1086
1087
1088static const nxt_conn_state_t nxt_h1p_keepalive_state
1089 nxt_aligned(64) =
1090{
1091 .ready_handler = nxt_h1p_conn_request_init,
1092 .close_handler = nxt_h1p_conn_error,
1093 .error_handler = nxt_h1p_conn_error,
1094
1095 .io_read_handler = nxt_h1p_conn_io_read_handler,
1096
1097 .timer_handler = nxt_h1p_conn_timeout,
1098 .timer_value = nxt_h1p_conn_timeout_value,
1099 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
1100 .timer_autoreset = 1,
1101};
1102
1103
1104static void
1105nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data)
1106{
1107 nxt_conn_t *c;
1108
1109 c = obj;
1110
1111 nxt_debug(task, "h1p conn error");
1112
1113 nxt_h1p_close(task, c);
1114}
1115
1116
1117static void
1118nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data)
1119{
1120 nxt_conn_t *c;
1121 nxt_timer_t *timer;
1122
1123 timer = obj;
1124
1125 nxt_debug(task, "h1p conn timeout");
1126
1127 c = nxt_read_timer_conn(timer);
1128
1129 nxt_h1p_close(task, c);
1130}
1131
1132
1133static nxt_msec_t
1134nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
1135{
1136 nxt_socket_conf_joint_t *joint;
1137
1138 joint = c->listen->socket.data;
1139
1140 return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
1141}
1142
1143
1144static void
1145nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c)
1146{
1147 nxt_debug(task, "h1p close");
1148
1149 c->socket.data = NULL;
1150
1151 c->write_state = &nxt_h1p_close_state;
1152
1153 nxt_conn_close(task->thread->engine, c);
1154}
1155
1156
1157static const nxt_conn_state_t nxt_h1p_close_state
1158 nxt_aligned(64) =
1159{
1160 .ready_handler = nxt_h1p_conn_free,
1161};
1162
1163
1164static void
1165nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data)
1166{
1167 nxt_conn_t *c;
1168 nxt_listen_event_t *lev;
1169 nxt_event_engine_t *engine;
1170
1171 c = obj;
1172
1173 nxt_debug(task, "h1p conn free");
1174
1175 nxt_queue_remove(&c->link);
1176
1177 engine = task->thread->engine;
1178
1179 nxt_sockaddr_cache_free(engine, c);
1180
1181 lev = c->listen;
1182
1183 nxt_conn_free(task, c);
1184
1185 nxt_router_listen_event_release(&engine->task, lev, NULL);
1186}
1187
1188
1189static void
1190nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data)
1191{
1192 nxt_h1proto_t *h1p;
1193 nxt_http_request_t *r;
1194
1195 h1p = data;
1196
1197 nxt_debug(task, "h1p conn request error");
1198
1199 r = h1p->request;
1200
1201 if (r->fields == NULL) {
1202 (void) nxt_h1p_header_process(h1p, r);
1203 }
1204
1205 if (r->status == 0) {
1206 r->status = NXT_HTTP_BAD_REQUEST;
1207 }
1208
1209 nxt_h1p_request_error(task, r);
1210}
1211
1212
1213static void
1214nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data)
1215{
1216 nxt_conn_t *c;
1217 nxt_timer_t *timer;
1218 nxt_h1proto_t *h1p;
1219 nxt_http_request_t *r;
1220
1221 timer = obj;
1222
1223 nxt_debug(task, "h1p conn request timeout");
1224
1225 c = nxt_read_timer_conn(timer);
1226 /*
1227 * Disable SO_LINGER off during socket closing
1228 * to send "408 Request Timeout" error response.
1229 */
1230 c->socket.timedout = 0;
1231
1232 h1p = c->socket.data;
1233 r = h1p->request;
1234
1235 if (r->fields == NULL) {
1236 (void) nxt_h1p_header_process(h1p, r);
1237 }
1238
1239 nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT);
1240}
1241
1242
1243static void
1244nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data)
1245{
1246 nxt_conn_t *c;
1247 nxt_timer_t *timer;
1248 nxt_h1proto_t *h1p;
1249
1250 timer = obj;
1251
1252 nxt_debug(task, "h1p conn request send timeout");
1253
1254 c = nxt_read_timer_conn(timer);
1255 h1p = c->socket.data;
1256
1257 nxt_h1p_request_error(task, h1p->request);
1258}
1259
1260
1261static nxt_msec_t
1262nxt_h1p_conn_request_timeout_value(nxt_conn_t *c, uintptr_t data)
1263{
1264 nxt_h1proto_t *h1p;
1265
1266 h1p = c->socket.data;
1267
1268 return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data);
1269}
1270
1271
1272nxt_inline void
1273nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r)
1274{
1275 r->state->error_handler(task, r, r->proto.h1);
1276}
922
923 break;
924 }
925
926 size += nxt_buf_used_size(b);
927 prev = &b->next;
928 }
929
930 if (size == 0) {
931 return out;
932 }
933
934 header = nxt_http_buf_mem(task, r, chunk_size);
935 if (nxt_slow_path(header == NULL)) {
936 return NULL;
937 }
938
939 header->next = out;
940 header->mem.free = nxt_sprintf(header->mem.free, header->mem.end,
941 "\r\n%xO\r\n", size);
942 return header;
943}
944
945
946static void
947nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data)
948{
949 nxt_conn_t *c;
950 nxt_event_engine_t *engine;
951
952 c = obj;
953
954 nxt_debug(task, "h1p conn request sent");
955
956 engine = task->thread->engine;
957
958 c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
959
960 if (c->write != NULL) {
961 nxt_conn_write(engine, c);
962 }
963}
964
965
966static nxt_off_t
967nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto)
968{
969 nxt_off_t sent;
970 nxt_h1proto_t *h1p;
971
972 h1p = proto.h1;
973
974 sent = h1p->conn->sent - h1p->header_size;
975
976 return (sent > 0) ? sent : 0;
977}
978
979
980static void
981nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
982 nxt_buf_t *last)
983{
984 nxt_buf_t *b;
985 nxt_conn_t *c;
986 nxt_h1proto_t *h1p;
987 nxt_work_queue_t *wq;
988
989 nxt_debug(task, "h1p request discard");
990
991 h1p = r->proto.h1;
992 h1p->keepalive = 0;
993
994 c = h1p->conn;
995 b = c->write;
996 c->write = NULL;
997
998 wq = &task->thread->engine->fast_work_queue;
999
1000 nxt_sendbuf_drain(task, wq, b);
1001 nxt_sendbuf_drain(task, wq, last);
1002}
1003
1004
1005static void
1006nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
1007 nxt_socket_conf_joint_t *joint)
1008{
1009 nxt_conn_t *c;
1010 nxt_h1proto_t *h1p;
1011
1012 nxt_debug(task, "h1p request close");
1013
1014 h1p = proto.h1;
1015 h1p->request = NULL;
1016
1017 nxt_router_conf_release(task, joint);
1018
1019 c = h1p->conn;
1020
1021 if (h1p->keepalive) {
1022 nxt_h1p_keepalive(task, h1p, c);
1023
1024 } else {
1025 nxt_h1p_close(task, c);
1026 }
1027}
1028
1029
1030static void
1031nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c)
1032{
1033 size_t size;
1034 nxt_buf_t *in, *b, *next;
1035
1036 nxt_debug(task, "h1p keepalive");
1037
1038 if (!c->tcp_nodelay) {
1039 nxt_conn_tcp_nodelay_on(task, c);
1040 }
1041
1042 b = h1p->buffers;
1043
1044 nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn));
1045
1046 c->sent = 0;
1047
1048 in = c->read;
1049
1050 if (in == NULL) {
1051 /* A request with large body. */
1052 in = b;
1053 c->read = in;
1054
1055 b = in->next;
1056 in->next = NULL;
1057 }
1058
1059 while (b != NULL) {
1060 next = b->next;
1061 nxt_mp_free(c->mem_pool, b);
1062 b = next;
1063 }
1064
1065 size = nxt_buf_mem_used_size(&in->mem);
1066
1067 if (size == 0) {
1068 nxt_mp_free(c->mem_pool, in);
1069
1070 c->read = NULL;
1071 c->read_state = &nxt_h1p_keepalive_state;
1072
1073 nxt_conn_read(task->thread->engine, c);
1074
1075 } else {
1076 nxt_debug(task, "h1p pipelining");
1077
1078 nxt_memmove(in->mem.start, in->mem.pos, size);
1079
1080 in->mem.pos = in->mem.start;
1081 in->mem.free = in->mem.start + size;
1082
1083 nxt_h1p_conn_request_init(task, c, c->socket.data);
1084 }
1085}
1086
1087
1088static const nxt_conn_state_t nxt_h1p_keepalive_state
1089 nxt_aligned(64) =
1090{
1091 .ready_handler = nxt_h1p_conn_request_init,
1092 .close_handler = nxt_h1p_conn_error,
1093 .error_handler = nxt_h1p_conn_error,
1094
1095 .io_read_handler = nxt_h1p_conn_io_read_handler,
1096
1097 .timer_handler = nxt_h1p_conn_timeout,
1098 .timer_value = nxt_h1p_conn_timeout_value,
1099 .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
1100 .timer_autoreset = 1,
1101};
1102
1103
1104static void
1105nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data)
1106{
1107 nxt_conn_t *c;
1108
1109 c = obj;
1110
1111 nxt_debug(task, "h1p conn error");
1112
1113 nxt_h1p_close(task, c);
1114}
1115
1116
1117static void
1118nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data)
1119{
1120 nxt_conn_t *c;
1121 nxt_timer_t *timer;
1122
1123 timer = obj;
1124
1125 nxt_debug(task, "h1p conn timeout");
1126
1127 c = nxt_read_timer_conn(timer);
1128
1129 nxt_h1p_close(task, c);
1130}
1131
1132
1133static nxt_msec_t
1134nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
1135{
1136 nxt_socket_conf_joint_t *joint;
1137
1138 joint = c->listen->socket.data;
1139
1140 return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
1141}
1142
1143
1144static void
1145nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c)
1146{
1147 nxt_debug(task, "h1p close");
1148
1149 c->socket.data = NULL;
1150
1151 c->write_state = &nxt_h1p_close_state;
1152
1153 nxt_conn_close(task->thread->engine, c);
1154}
1155
1156
1157static const nxt_conn_state_t nxt_h1p_close_state
1158 nxt_aligned(64) =
1159{
1160 .ready_handler = nxt_h1p_conn_free,
1161};
1162
1163
1164static void
1165nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data)
1166{
1167 nxt_conn_t *c;
1168 nxt_listen_event_t *lev;
1169 nxt_event_engine_t *engine;
1170
1171 c = obj;
1172
1173 nxt_debug(task, "h1p conn free");
1174
1175 nxt_queue_remove(&c->link);
1176
1177 engine = task->thread->engine;
1178
1179 nxt_sockaddr_cache_free(engine, c);
1180
1181 lev = c->listen;
1182
1183 nxt_conn_free(task, c);
1184
1185 nxt_router_listen_event_release(&engine->task, lev, NULL);
1186}
1187
1188
1189static void
1190nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data)
1191{
1192 nxt_h1proto_t *h1p;
1193 nxt_http_request_t *r;
1194
1195 h1p = data;
1196
1197 nxt_debug(task, "h1p conn request error");
1198
1199 r = h1p->request;
1200
1201 if (r->fields == NULL) {
1202 (void) nxt_h1p_header_process(h1p, r);
1203 }
1204
1205 if (r->status == 0) {
1206 r->status = NXT_HTTP_BAD_REQUEST;
1207 }
1208
1209 nxt_h1p_request_error(task, r);
1210}
1211
1212
1213static void
1214nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data)
1215{
1216 nxt_conn_t *c;
1217 nxt_timer_t *timer;
1218 nxt_h1proto_t *h1p;
1219 nxt_http_request_t *r;
1220
1221 timer = obj;
1222
1223 nxt_debug(task, "h1p conn request timeout");
1224
1225 c = nxt_read_timer_conn(timer);
1226 /*
1227 * Disable SO_LINGER off during socket closing
1228 * to send "408 Request Timeout" error response.
1229 */
1230 c->socket.timedout = 0;
1231
1232 h1p = c->socket.data;
1233 r = h1p->request;
1234
1235 if (r->fields == NULL) {
1236 (void) nxt_h1p_header_process(h1p, r);
1237 }
1238
1239 nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT);
1240}
1241
1242
1243static void
1244nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data)
1245{
1246 nxt_conn_t *c;
1247 nxt_timer_t *timer;
1248 nxt_h1proto_t *h1p;
1249
1250 timer = obj;
1251
1252 nxt_debug(task, "h1p conn request send timeout");
1253
1254 c = nxt_read_timer_conn(timer);
1255 h1p = c->socket.data;
1256
1257 nxt_h1p_request_error(task, h1p->request);
1258}
1259
1260
1261static nxt_msec_t
1262nxt_h1p_conn_request_timeout_value(nxt_conn_t *c, uintptr_t data)
1263{
1264 nxt_h1proto_t *h1p;
1265
1266 h1p = c->socket.data;
1267
1268 return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data);
1269}
1270
1271
1272nxt_inline void
1273nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r)
1274{
1275 r->state->error_handler(task, r, r->proto.h1);
1276}