xref: /unit/src/nxt_h1proto.c (revision 630)
1431Sigor@sysoev.ru 
2431Sigor@sysoev.ru /*
3431Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4431Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5431Sigor@sysoev.ru  */
6431Sigor@sysoev.ru 
7431Sigor@sysoev.ru #include <nxt_router.h>
8431Sigor@sysoev.ru #include <nxt_http.h>
9431Sigor@sysoev.ru 
10431Sigor@sysoev.ru 
11624Sigor@sysoev.ru /*
12624Sigor@sysoev.ru  * nxt_h1p_conn_ prefix is used for connection handlers.
13624Sigor@sysoev.ru  * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods.
14624Sigor@sysoev.ru  */
15624Sigor@sysoev.ru 
16629Sigor@sysoev.ru static ssize_t nxt_h1p_conn_io_read_handler(nxt_conn_t *c);
17624Sigor@sysoev.ru static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data);
18624Sigor@sysoev.ru static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data);
19624Sigor@sysoev.ru static void nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data);
20620Svbart@nginx.com static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p,
21620Svbart@nginx.com     nxt_http_request_t *r);
22625Sigor@sysoev.ru static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task,
23625Sigor@sysoev.ru     nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf);
24431Sigor@sysoev.ru static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field,
25431Sigor@sysoev.ru     uintptr_t data);
26431Sigor@sysoev.ru static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field,
27431Sigor@sysoev.ru     uintptr_t data);
28431Sigor@sysoev.ru static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
29624Sigor@sysoev.ru static void nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data);
30431Sigor@sysoev.ru static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
31431Sigor@sysoev.ru static void nxt_h1p_request_header_send(nxt_task_t *task,
32431Sigor@sysoev.ru     nxt_http_request_t *r);
33431Sigor@sysoev.ru static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
34431Sigor@sysoev.ru     nxt_buf_t *out);
35431Sigor@sysoev.ru static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r,
36431Sigor@sysoev.ru     nxt_buf_t *out);
37624Sigor@sysoev.ru static void nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data);
38*630Svbart@nginx.com static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task,
39*630Svbart@nginx.com     nxt_http_proto_t proto);
40608Sigor@sysoev.ru static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
41608Sigor@sysoev.ru     nxt_buf_t *last);
42431Sigor@sysoev.ru static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto);
43431Sigor@sysoev.ru static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p,
44431Sigor@sysoev.ru     nxt_conn_t *c);
45431Sigor@sysoev.ru static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data);
46431Sigor@sysoev.ru static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data);
47624Sigor@sysoev.ru static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c);
48624Sigor@sysoev.ru static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data);
49624Sigor@sysoev.ru static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj,
50624Sigor@sysoev.ru     void *data);
51626Sigor@sysoev.ru static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj,
52626Sigor@sysoev.ru     void *data);
53624Sigor@sysoev.ru nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r);
54624Sigor@sysoev.ru static nxt_msec_t nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data);
55431Sigor@sysoev.ru 
56431Sigor@sysoev.ru 
57431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_idle_state;
58624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_header_parse_state;
59431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_read_body_state;
60431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_send_state;
61624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_keepalive_state;
62431Sigor@sysoev.ru 
63431Sigor@sysoev.ru 
64431Sigor@sysoev.ru const nxt_http_proto_body_read_t  nxt_http_proto_body_read[3] = {
65431Sigor@sysoev.ru     nxt_h1p_request_body_read,
66431Sigor@sysoev.ru     NULL,
67431Sigor@sysoev.ru     NULL,
68431Sigor@sysoev.ru };
69431Sigor@sysoev.ru 
70431Sigor@sysoev.ru 
71431Sigor@sysoev.ru const nxt_http_proto_local_addr_t  nxt_http_proto_local_addr[3] = {
72431Sigor@sysoev.ru     nxt_h1p_request_local_addr,
73431Sigor@sysoev.ru     NULL,
74431Sigor@sysoev.ru     NULL,
75431Sigor@sysoev.ru };
76431Sigor@sysoev.ru 
77431Sigor@sysoev.ru 
78431Sigor@sysoev.ru const nxt_http_proto_header_send_t  nxt_http_proto_header_send[3] = {
79431Sigor@sysoev.ru     nxt_h1p_request_header_send,
80431Sigor@sysoev.ru     NULL,
81431Sigor@sysoev.ru     NULL,
82431Sigor@sysoev.ru };
83431Sigor@sysoev.ru 
84431Sigor@sysoev.ru 
85431Sigor@sysoev.ru const nxt_http_proto_send_t  nxt_http_proto_send[3] = {
86431Sigor@sysoev.ru     nxt_h1p_request_send,
87431Sigor@sysoev.ru     NULL,
88431Sigor@sysoev.ru     NULL,
89431Sigor@sysoev.ru };
90431Sigor@sysoev.ru 
91431Sigor@sysoev.ru 
92*630Svbart@nginx.com const nxt_http_proto_body_bytes_sent_t  nxt_http_proto_body_bytes_sent[3] = {
93*630Svbart@nginx.com     nxt_h1p_request_body_bytes_sent,
94*630Svbart@nginx.com     NULL,
95*630Svbart@nginx.com     NULL,
96*630Svbart@nginx.com };
97*630Svbart@nginx.com 
98*630Svbart@nginx.com 
99608Sigor@sysoev.ru const nxt_http_proto_discard_t  nxt_http_proto_discard[3] = {
100608Sigor@sysoev.ru     nxt_h1p_request_discard,
101608Sigor@sysoev.ru     NULL,
102608Sigor@sysoev.ru     NULL,
103608Sigor@sysoev.ru };
104608Sigor@sysoev.ru 
105608Sigor@sysoev.ru 
106431Sigor@sysoev.ru const nxt_http_proto_close_t  nxt_http_proto_close[3] = {
107431Sigor@sysoev.ru     nxt_h1p_request_close,
108431Sigor@sysoev.ru     NULL,
109431Sigor@sysoev.ru     NULL,
110431Sigor@sysoev.ru };
111431Sigor@sysoev.ru 
112431Sigor@sysoev.ru 
113431Sigor@sysoev.ru static nxt_lvlhsh_t            nxt_h1p_fields_hash;
114431Sigor@sysoev.ru 
115431Sigor@sysoev.ru static nxt_http_field_proc_t   nxt_h1p_fields[] = {
116431Sigor@sysoev.ru     { nxt_string("Connection"),        &nxt_h1p_connection, 0 },
117431Sigor@sysoev.ru     { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 },
118431Sigor@sysoev.ru 
119431Sigor@sysoev.ru     { nxt_string("Host"),              &nxt_http_request_host, 0 },
120431Sigor@sysoev.ru     { nxt_string("Cookie"),            &nxt_http_request_field,
121431Sigor@sysoev.ru         offsetof(nxt_http_request_t, cookie) },
122*630Svbart@nginx.com     { nxt_string("Referer"),           &nxt_http_request_field,
123*630Svbart@nginx.com         offsetof(nxt_http_request_t, referer) },
124*630Svbart@nginx.com     { nxt_string("User-Agent"),        &nxt_http_request_field,
125*630Svbart@nginx.com         offsetof(nxt_http_request_t, user_agent) },
126431Sigor@sysoev.ru     { nxt_string("Content-Type"),      &nxt_http_request_field,
127431Sigor@sysoev.ru         offsetof(nxt_http_request_t, content_type) },
128431Sigor@sysoev.ru     { nxt_string("Content-Length"),    &nxt_http_request_content_length, 0 },
129431Sigor@sysoev.ru };
130431Sigor@sysoev.ru 
131431Sigor@sysoev.ru 
132431Sigor@sysoev.ru nxt_int_t
133431Sigor@sysoev.ru nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt)
134431Sigor@sysoev.ru {
135431Sigor@sysoev.ru     return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool,
136431Sigor@sysoev.ru                                 nxt_h1p_fields, nxt_nitems(nxt_h1p_fields));
137431Sigor@sysoev.ru }
138431Sigor@sysoev.ru 
139431Sigor@sysoev.ru 
140431Sigor@sysoev.ru void
141431Sigor@sysoev.ru nxt_http_conn_init(nxt_task_t *task, void *obj, void *data)
142431Sigor@sysoev.ru {
143431Sigor@sysoev.ru     nxt_conn_t               *c;
144431Sigor@sysoev.ru     nxt_socket_conf_t        *skcf;
145431Sigor@sysoev.ru     nxt_event_engine_t       *engine;
146431Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
147431Sigor@sysoev.ru 
148431Sigor@sysoev.ru     c = obj;
149431Sigor@sysoev.ru     joint = data;
150431Sigor@sysoev.ru 
151431Sigor@sysoev.ru     nxt_debug(task, "http conn init");
152431Sigor@sysoev.ru 
153431Sigor@sysoev.ru     c->joint = joint;
154431Sigor@sysoev.ru     joint->count++;
155431Sigor@sysoev.ru 
156431Sigor@sysoev.ru     skcf = joint->socket_conf;
157431Sigor@sysoev.ru     c->local = skcf->sockaddr;
158431Sigor@sysoev.ru     c->socket.data = NULL;
159431Sigor@sysoev.ru 
160431Sigor@sysoev.ru     engine = task->thread->engine;
161431Sigor@sysoev.ru     c->read_work_queue = &engine->fast_work_queue;
162431Sigor@sysoev.ru     c->write_work_queue = &engine->fast_work_queue;
163431Sigor@sysoev.ru 
164431Sigor@sysoev.ru     c->read_state = &nxt_h1p_idle_state;
165431Sigor@sysoev.ru 
166629Sigor@sysoev.ru     nxt_conn_read(task->thread->engine, c);
167431Sigor@sysoev.ru }
168431Sigor@sysoev.ru 
169431Sigor@sysoev.ru 
170431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_idle_state
171431Sigor@sysoev.ru     nxt_aligned(64) =
172431Sigor@sysoev.ru {
173629Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_proto_init,
174624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_error,
175431Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_error,
176431Sigor@sysoev.ru 
177629Sigor@sysoev.ru     .io_read_handler = nxt_h1p_conn_io_read_handler,
178431Sigor@sysoev.ru 
179431Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_timeout,
180624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
181431Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
182431Sigor@sysoev.ru };
183431Sigor@sysoev.ru 
184431Sigor@sysoev.ru 
185629Sigor@sysoev.ru static ssize_t
186629Sigor@sysoev.ru nxt_h1p_conn_io_read_handler(nxt_conn_t *c)
187629Sigor@sysoev.ru {
188629Sigor@sysoev.ru     size_t                   size;
189629Sigor@sysoev.ru     ssize_t                  n;
190629Sigor@sysoev.ru     nxt_buf_t                *b;
191629Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
192629Sigor@sysoev.ru 
193629Sigor@sysoev.ru     joint = c->joint;
194629Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
195629Sigor@sysoev.ru 
196629Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
197629Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
198629Sigor@sysoev.ru         c->socket.error = NXT_ENOMEM;
199629Sigor@sysoev.ru         return NXT_ERROR;
200629Sigor@sysoev.ru     }
201629Sigor@sysoev.ru 
202629Sigor@sysoev.ru     n = c->io->recvbuf(c, b);
203629Sigor@sysoev.ru 
204629Sigor@sysoev.ru     if (n > 0) {
205629Sigor@sysoev.ru         c->read = b;
206629Sigor@sysoev.ru 
207629Sigor@sysoev.ru     } else {
208629Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, b);
209629Sigor@sysoev.ru     }
210629Sigor@sysoev.ru 
211629Sigor@sysoev.ru     return n;
212629Sigor@sysoev.ru }
213629Sigor@sysoev.ru 
214629Sigor@sysoev.ru 
215431Sigor@sysoev.ru static void
216624Sigor@sysoev.ru nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data)
217431Sigor@sysoev.ru {
218624Sigor@sysoev.ru     nxt_conn_t     *c;
219624Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
220624Sigor@sysoev.ru 
221624Sigor@sysoev.ru     c = obj;
222624Sigor@sysoev.ru 
223624Sigor@sysoev.ru     nxt_debug(task, "h1p conn proto init");
224624Sigor@sysoev.ru 
225624Sigor@sysoev.ru     h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t));
226624Sigor@sysoev.ru     if (nxt_slow_path(h1p == NULL)) {
227624Sigor@sysoev.ru         nxt_h1p_close(task, c);
228624Sigor@sysoev.ru         return;
229624Sigor@sysoev.ru     }
230624Sigor@sysoev.ru 
231624Sigor@sysoev.ru     c->socket.data = h1p;
232624Sigor@sysoev.ru     h1p->conn = c;
233624Sigor@sysoev.ru 
234624Sigor@sysoev.ru     nxt_h1p_conn_request_init(task, c, h1p);
235624Sigor@sysoev.ru }
236624Sigor@sysoev.ru 
237624Sigor@sysoev.ru 
238624Sigor@sysoev.ru static void
239624Sigor@sysoev.ru nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
240624Sigor@sysoev.ru {
241431Sigor@sysoev.ru     nxt_int_t                ret;
242431Sigor@sysoev.ru     nxt_conn_t               *c;
243431Sigor@sysoev.ru     nxt_h1proto_t            *h1p;
244431Sigor@sysoev.ru     nxt_http_request_t       *r;
245431Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
246431Sigor@sysoev.ru 
247431Sigor@sysoev.ru     c = obj;
248431Sigor@sysoev.ru     h1p = data;
249431Sigor@sysoev.ru 
250624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request init");
251431Sigor@sysoev.ru 
252624Sigor@sysoev.ru     r = nxt_http_request_create(task);
253431Sigor@sysoev.ru 
254624Sigor@sysoev.ru     if (nxt_fast_path(r != NULL)) {
255431Sigor@sysoev.ru         h1p->request = r;
256431Sigor@sysoev.ru         r->proto.h1 = h1p;
257624Sigor@sysoev.ru 
258431Sigor@sysoev.ru         joint = c->joint;
259431Sigor@sysoev.ru         r->socket_conf = joint->socket_conf;
260431Sigor@sysoev.ru 
261431Sigor@sysoev.ru         r->remote = c->remote;
262431Sigor@sysoev.ru 
263431Sigor@sysoev.ru         ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
264624Sigor@sysoev.ru 
265624Sigor@sysoev.ru         if (nxt_fast_path(ret == NXT_OK)) {
266624Sigor@sysoev.ru             nxt_h1p_conn_header_parse(task, c, h1p);
267624Sigor@sysoev.ru             return;
268431Sigor@sysoev.ru         }
269624Sigor@sysoev.ru 
270624Sigor@sysoev.ru         /*
271624Sigor@sysoev.ru          * The request is very incomplete here,
272624Sigor@sysoev.ru          * so "internal server error" useless here.
273624Sigor@sysoev.ru          */
274624Sigor@sysoev.ru         nxt_mp_release(r->mem_pool);
275431Sigor@sysoev.ru     }
276431Sigor@sysoev.ru 
277624Sigor@sysoev.ru     nxt_h1p_close(task, c);
278624Sigor@sysoev.ru }
279624Sigor@sysoev.ru 
280624Sigor@sysoev.ru 
281624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_header_parse_state
282624Sigor@sysoev.ru     nxt_aligned(64) =
283624Sigor@sysoev.ru {
284624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_header_parse,
285624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_request_error,
286624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
287624Sigor@sysoev.ru 
288624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_timeout,
289624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
290624Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
291624Sigor@sysoev.ru };
292624Sigor@sysoev.ru 
293624Sigor@sysoev.ru 
294624Sigor@sysoev.ru static void
295624Sigor@sysoev.ru nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
296624Sigor@sysoev.ru {
297624Sigor@sysoev.ru     nxt_int_t           ret;
298624Sigor@sysoev.ru     nxt_conn_t          *c;
299624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
300624Sigor@sysoev.ru     nxt_http_status_t   status;
301624Sigor@sysoev.ru     nxt_http_request_t  *r;
302624Sigor@sysoev.ru 
303624Sigor@sysoev.ru     c = obj;
304624Sigor@sysoev.ru     h1p = data;
305624Sigor@sysoev.ru 
306624Sigor@sysoev.ru     nxt_debug(task, "h1p conn header parse");
307624Sigor@sysoev.ru 
308431Sigor@sysoev.ru     ret = nxt_http_parse_request(&h1p->parser, &c->read->mem);
309431Sigor@sysoev.ru 
310624Sigor@sysoev.ru     r = h1p->request;
311624Sigor@sysoev.ru 
312625Sigor@sysoev.ru     ret = nxt_expect(NXT_DONE, ret);
313625Sigor@sysoev.ru 
314625Sigor@sysoev.ru     switch (ret) {
315625Sigor@sysoev.ru 
316625Sigor@sysoev.ru     case NXT_DONE:
317431Sigor@sysoev.ru         /*
318431Sigor@sysoev.ru          * By default the keepalive mode is disabled in HTTP/1.0 and
319431Sigor@sysoev.ru          * enabled in HTTP/1.1.  The mode can be overridden later by
320431Sigor@sysoev.ru          * the "Connection" field processed in nxt_h1p_connection().
321431Sigor@sysoev.ru          */
322481Svbart@nginx.com         h1p->keepalive = (h1p->parser.version.s.minor != '0');
323431Sigor@sysoev.ru 
324620Svbart@nginx.com         ret = nxt_h1p_header_process(h1p, r);
325431Sigor@sysoev.ru 
326431Sigor@sysoev.ru         if (nxt_fast_path(ret == NXT_OK)) {
327431Sigor@sysoev.ru             r->state->ready_handler(task, r, NULL);
328431Sigor@sysoev.ru             return;
329431Sigor@sysoev.ru         }
330431Sigor@sysoev.ru 
331480Svbart@nginx.com         /* ret == NXT_ERROR */
332625Sigor@sysoev.ru         status = NXT_HTTP_BAD_REQUEST;
333480Svbart@nginx.com 
334625Sigor@sysoev.ru         goto error;
335431Sigor@sysoev.ru 
336625Sigor@sysoev.ru     case NXT_AGAIN:
337625Sigor@sysoev.ru         status = nxt_h1p_header_buffer_test(task, h1p, c, r->socket_conf);
338431Sigor@sysoev.ru 
339625Sigor@sysoev.ru         if (nxt_fast_path(status == NXT_OK)) {
340625Sigor@sysoev.ru             c->read_state = &nxt_h1p_header_parse_state;
341431Sigor@sysoev.ru 
342625Sigor@sysoev.ru             nxt_conn_read(task->thread->engine, c);
343625Sigor@sysoev.ru             return;
344431Sigor@sysoev.ru         }
345431Sigor@sysoev.ru 
346625Sigor@sysoev.ru         break;
347480Svbart@nginx.com 
348480Svbart@nginx.com     case NXT_HTTP_PARSE_INVALID:
349480Svbart@nginx.com         status = NXT_HTTP_BAD_REQUEST;
350480Svbart@nginx.com         break;
351431Sigor@sysoev.ru 
352482Svbart@nginx.com     case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
353482Svbart@nginx.com         status = NXT_HTTP_VERSION_NOT_SUPPORTED;
354482Svbart@nginx.com         break;
355482Svbart@nginx.com 
356480Svbart@nginx.com     case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
357480Svbart@nginx.com         status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
358480Svbart@nginx.com         break;
359480Svbart@nginx.com 
360480Svbart@nginx.com     default:
361480Svbart@nginx.com     case NXT_ERROR:
362480Svbart@nginx.com         status = NXT_HTTP_INTERNAL_SERVER_ERROR;
363480Svbart@nginx.com         break;
364480Svbart@nginx.com     }
365480Svbart@nginx.com 
366620Svbart@nginx.com     (void) nxt_h1p_header_process(h1p, r);
367625Sigor@sysoev.ru 
368625Sigor@sysoev.ru error:
369625Sigor@sysoev.ru 
370480Svbart@nginx.com     nxt_http_request_error(task, r, status);
371431Sigor@sysoev.ru }
372431Sigor@sysoev.ru 
373431Sigor@sysoev.ru 
374431Sigor@sysoev.ru static nxt_int_t
375620Svbart@nginx.com nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r)
376620Svbart@nginx.com {
377620Svbart@nginx.com     r->target.start = h1p->parser.target_start;
378620Svbart@nginx.com     r->target.length = h1p->parser.target_end - h1p->parser.target_start;
379620Svbart@nginx.com 
380620Svbart@nginx.com     if (h1p->parser.version.ui64 != 0) {
381620Svbart@nginx.com         r->version.start = h1p->parser.version.str;
382620Svbart@nginx.com         r->version.length = sizeof(h1p->parser.version.str);
383620Svbart@nginx.com     }
384620Svbart@nginx.com 
385620Svbart@nginx.com     r->method = &h1p->parser.method;
386620Svbart@nginx.com     r->path = &h1p->parser.path;
387620Svbart@nginx.com     r->args = &h1p->parser.args;
388620Svbart@nginx.com 
389620Svbart@nginx.com     r->fields = h1p->parser.fields;
390620Svbart@nginx.com 
391620Svbart@nginx.com     return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r);
392620Svbart@nginx.com }
393620Svbart@nginx.com 
394620Svbart@nginx.com 
395620Svbart@nginx.com static nxt_int_t
396625Sigor@sysoev.ru nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
397625Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
398625Sigor@sysoev.ru {
399625Sigor@sysoev.ru     size_t     size, used;
400625Sigor@sysoev.ru     nxt_buf_t  *in, *b;
401625Sigor@sysoev.ru 
402625Sigor@sysoev.ru     in = c->read;
403625Sigor@sysoev.ru 
404625Sigor@sysoev.ru     if (nxt_buf_mem_free_size(&in->mem) == 0) {
405625Sigor@sysoev.ru         size = skcf->large_header_buffer_size;
406625Sigor@sysoev.ru         used = nxt_buf_mem_used_size(&in->mem);
407625Sigor@sysoev.ru 
408625Sigor@sysoev.ru         if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
409625Sigor@sysoev.ru             return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
410625Sigor@sysoev.ru         }
411625Sigor@sysoev.ru 
412625Sigor@sysoev.ru         b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
413625Sigor@sysoev.ru         if (nxt_slow_path(b == NULL)) {
414625Sigor@sysoev.ru             return NXT_HTTP_INTERNAL_SERVER_ERROR;
415625Sigor@sysoev.ru         }
416625Sigor@sysoev.ru 
417625Sigor@sysoev.ru         b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
418625Sigor@sysoev.ru 
419625Sigor@sysoev.ru         in->next = h1p->buffers;
420625Sigor@sysoev.ru         h1p->buffers = in;
421625Sigor@sysoev.ru         h1p->nbuffers++;
422625Sigor@sysoev.ru 
423625Sigor@sysoev.ru         c->read = b;
424625Sigor@sysoev.ru     }
425625Sigor@sysoev.ru 
426625Sigor@sysoev.ru     return NXT_OK;
427625Sigor@sysoev.ru }
428625Sigor@sysoev.ru 
429625Sigor@sysoev.ru 
430625Sigor@sysoev.ru static nxt_int_t
431431Sigor@sysoev.ru nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
432431Sigor@sysoev.ru {
433431Sigor@sysoev.ru     nxt_http_request_t  *r;
434431Sigor@sysoev.ru 
435431Sigor@sysoev.ru     r = ctx;
436431Sigor@sysoev.ru 
437431Sigor@sysoev.ru     if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) {
438431Sigor@sysoev.ru         r->proto.h1->keepalive = 0;
439431Sigor@sysoev.ru     }
440431Sigor@sysoev.ru 
441431Sigor@sysoev.ru     return NXT_OK;
442431Sigor@sysoev.ru }
443431Sigor@sysoev.ru 
444431Sigor@sysoev.ru 
445431Sigor@sysoev.ru static nxt_int_t
446431Sigor@sysoev.ru nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data)
447431Sigor@sysoev.ru {
448431Sigor@sysoev.ru     nxt_http_te_t       te;
449431Sigor@sysoev.ru     nxt_http_request_t  *r;
450431Sigor@sysoev.ru 
451431Sigor@sysoev.ru     r = ctx;
452431Sigor@sysoev.ru 
453431Sigor@sysoev.ru     if (field->value_length == 7
454431Sigor@sysoev.ru         && nxt_memcmp(field->value, "chunked", 7) == 0)
455431Sigor@sysoev.ru     {
456431Sigor@sysoev.ru         te = NXT_HTTP_TE_CHUNKED;
457431Sigor@sysoev.ru 
458431Sigor@sysoev.ru     } else {
459431Sigor@sysoev.ru         te = NXT_HTTP_TE_UNSUPPORTED;
460431Sigor@sysoev.ru     }
461431Sigor@sysoev.ru 
462431Sigor@sysoev.ru     r->proto.h1->transfer_encoding = te;
463431Sigor@sysoev.ru 
464431Sigor@sysoev.ru     return NXT_OK;
465431Sigor@sysoev.ru }
466431Sigor@sysoev.ru 
467431Sigor@sysoev.ru 
468431Sigor@sysoev.ru static void
469431Sigor@sysoev.ru nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
470431Sigor@sysoev.ru {
471527Svbart@nginx.com     size_t             size, body_length;
472459Sigor@sysoev.ru     nxt_buf_t          *in, *b;
473431Sigor@sysoev.ru     nxt_conn_t         *c;
474459Sigor@sysoev.ru     nxt_h1proto_t      *h1p;
475431Sigor@sysoev.ru     nxt_http_status_t  status;
476431Sigor@sysoev.ru 
477459Sigor@sysoev.ru     h1p = r->proto.h1;
478459Sigor@sysoev.ru 
479624Sigor@sysoev.ru     nxt_debug(task, "h1p request body read %O te:%d",
480459Sigor@sysoev.ru               r->content_length_n, h1p->transfer_encoding);
481431Sigor@sysoev.ru 
482459Sigor@sysoev.ru     switch (h1p->transfer_encoding) {
483431Sigor@sysoev.ru 
484431Sigor@sysoev.ru     case NXT_HTTP_TE_CHUNKED:
485431Sigor@sysoev.ru         status = NXT_HTTP_LENGTH_REQUIRED;
486431Sigor@sysoev.ru         goto error;
487431Sigor@sysoev.ru 
488431Sigor@sysoev.ru     case NXT_HTTP_TE_UNSUPPORTED:
489431Sigor@sysoev.ru         status = NXT_HTTP_NOT_IMPLEMENTED;
490431Sigor@sysoev.ru         goto error;
491431Sigor@sysoev.ru 
492431Sigor@sysoev.ru     default:
493431Sigor@sysoev.ru     case NXT_HTTP_TE_NONE:
494431Sigor@sysoev.ru         break;
495431Sigor@sysoev.ru     }
496431Sigor@sysoev.ru 
497431Sigor@sysoev.ru     if (r->content_length_n == -1 || r->content_length_n == 0) {
498431Sigor@sysoev.ru         goto ready;
499431Sigor@sysoev.ru     }
500431Sigor@sysoev.ru 
501431Sigor@sysoev.ru     if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) {
502431Sigor@sysoev.ru         status = NXT_HTTP_PAYLOAD_TOO_LARGE;
503431Sigor@sysoev.ru         goto error;
504431Sigor@sysoev.ru     }
505431Sigor@sysoev.ru 
506527Svbart@nginx.com     body_length = (size_t) r->content_length_n;
507431Sigor@sysoev.ru 
508431Sigor@sysoev.ru     b = r->body;
509431Sigor@sysoev.ru 
510431Sigor@sysoev.ru     if (b == NULL) {
511527Svbart@nginx.com         b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0);
512431Sigor@sysoev.ru         if (nxt_slow_path(b == NULL)) {
513431Sigor@sysoev.ru             status = NXT_HTTP_INTERNAL_SERVER_ERROR;
514431Sigor@sysoev.ru             goto error;
515431Sigor@sysoev.ru         }
516431Sigor@sysoev.ru 
517431Sigor@sysoev.ru         r->body = b;
518431Sigor@sysoev.ru     }
519431Sigor@sysoev.ru 
520459Sigor@sysoev.ru     in = h1p->conn->read;
521431Sigor@sysoev.ru 
522459Sigor@sysoev.ru     size = nxt_buf_mem_used_size(&in->mem);
523431Sigor@sysoev.ru 
524431Sigor@sysoev.ru     if (size != 0) {
525527Svbart@nginx.com         if (size > body_length) {
526527Svbart@nginx.com             size = body_length;
527431Sigor@sysoev.ru         }
528431Sigor@sysoev.ru 
529459Sigor@sysoev.ru         b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
530459Sigor@sysoev.ru         in->mem.pos += size;
531431Sigor@sysoev.ru     }
532431Sigor@sysoev.ru 
533527Svbart@nginx.com     size = nxt_buf_mem_free_size(&b->mem);
534431Sigor@sysoev.ru 
535527Svbart@nginx.com     nxt_debug(task, "h1p body rest: %uz", size);
536431Sigor@sysoev.ru 
537527Svbart@nginx.com     if (size != 0) {
538459Sigor@sysoev.ru         in->next = h1p->buffers;
539459Sigor@sysoev.ru         h1p->buffers = in;
540459Sigor@sysoev.ru 
541459Sigor@sysoev.ru         c = h1p->conn;
542431Sigor@sysoev.ru         c->read = b;
543431Sigor@sysoev.ru         c->read_state = &nxt_h1p_read_body_state;
544431Sigor@sysoev.ru 
545431Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
546431Sigor@sysoev.ru         return;
547431Sigor@sysoev.ru     }
548431Sigor@sysoev.ru 
549431Sigor@sysoev.ru ready:
550431Sigor@sysoev.ru 
551431Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
552431Sigor@sysoev.ru                        r->state->ready_handler, task, r, NULL);
553431Sigor@sysoev.ru 
554431Sigor@sysoev.ru     return;
555431Sigor@sysoev.ru 
556431Sigor@sysoev.ru error:
557431Sigor@sysoev.ru 
558459Sigor@sysoev.ru     h1p->keepalive = 0;
559431Sigor@sysoev.ru 
560431Sigor@sysoev.ru     nxt_http_request_error(task, r, status);
561431Sigor@sysoev.ru }
562431Sigor@sysoev.ru 
563431Sigor@sysoev.ru 
564431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_read_body_state
565431Sigor@sysoev.ru     nxt_aligned(64) =
566431Sigor@sysoev.ru {
567624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_body_read,
568624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_request_error,
569624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
570431Sigor@sysoev.ru 
571624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_timeout,
572624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
573431Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
574431Sigor@sysoev.ru     .timer_autoreset = 1,
575431Sigor@sysoev.ru };
576431Sigor@sysoev.ru 
577431Sigor@sysoev.ru 
578431Sigor@sysoev.ru static void
579624Sigor@sysoev.ru nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data)
580431Sigor@sysoev.ru {
581431Sigor@sysoev.ru     size_t              size;
582431Sigor@sysoev.ru     nxt_conn_t          *c;
583431Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
584431Sigor@sysoev.ru     nxt_http_request_t  *r;
585431Sigor@sysoev.ru 
586431Sigor@sysoev.ru     c = obj;
587431Sigor@sysoev.ru     h1p = data;
588431Sigor@sysoev.ru 
589624Sigor@sysoev.ru     nxt_debug(task, "h1p conn body read");
590431Sigor@sysoev.ru 
591527Svbart@nginx.com     size = nxt_buf_mem_free_size(&c->read->mem);
592431Sigor@sysoev.ru 
593527Svbart@nginx.com     nxt_debug(task, "h1p body rest: %uz", size);
594431Sigor@sysoev.ru 
595527Svbart@nginx.com     if (size != 0) {
596431Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
597431Sigor@sysoev.ru 
598431Sigor@sysoev.ru     } else {
599527Svbart@nginx.com         r = h1p->request;
600459Sigor@sysoev.ru         c->read = NULL;
601431Sigor@sysoev.ru         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
602431Sigor@sysoev.ru                            r->state->ready_handler, task, r, NULL);
603431Sigor@sysoev.ru     }
604431Sigor@sysoev.ru }
605431Sigor@sysoev.ru 
606431Sigor@sysoev.ru 
607431Sigor@sysoev.ru static void
608431Sigor@sysoev.ru nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
609431Sigor@sysoev.ru {
610431Sigor@sysoev.ru     r->local = nxt_conn_local_addr(task, r->proto.h1->conn);
611431Sigor@sysoev.ru }
612431Sigor@sysoev.ru 
613431Sigor@sysoev.ru 
614431Sigor@sysoev.ru #define NXT_HTTP_LAST_SUCCESS                                                 \
615431Sigor@sysoev.ru     (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
616431Sigor@sysoev.ru 
617431Sigor@sysoev.ru static const nxt_str_t  nxt_http_success[] = {
618431Sigor@sysoev.ru     nxt_string("HTTP/1.1 200 OK\r\n"),
619431Sigor@sysoev.ru     nxt_string("HTTP/1.1 201 Created\r\n"),
620431Sigor@sysoev.ru     nxt_string("HTTP/1.1 202 Accepted\r\n"),
621431Sigor@sysoev.ru     nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"),
622431Sigor@sysoev.ru     nxt_string("HTTP/1.1 204 No Content\r\n"),
623431Sigor@sysoev.ru     nxt_string("HTTP/1.1 205 Reset Content\r\n"),
624431Sigor@sysoev.ru     nxt_string("HTTP/1.1 206 Partial Content\r\n"),
625431Sigor@sysoev.ru };
626431Sigor@sysoev.ru 
627431Sigor@sysoev.ru 
628431Sigor@sysoev.ru #define NXT_HTTP_LAST_REDIRECTION                                             \
629431Sigor@sysoev.ru     (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1)
630431Sigor@sysoev.ru 
631431Sigor@sysoev.ru static const nxt_str_t  nxt_http_redirection[] = {
632431Sigor@sysoev.ru     nxt_string("HTTP/1.1 300 Multiple Choices\r\n"),
633431Sigor@sysoev.ru     nxt_string("HTTP/1.1 301 Moved Permanently\r\n"),
634431Sigor@sysoev.ru     nxt_string("HTTP/1.1 302 Found\r\n"),
635431Sigor@sysoev.ru     nxt_string("HTTP/1.1 303 See Other\r\n"),
636431Sigor@sysoev.ru     nxt_string("HTTP/1.1 304 Not Modified\r\n"),
637431Sigor@sysoev.ru };
638431Sigor@sysoev.ru 
639431Sigor@sysoev.ru 
640431Sigor@sysoev.ru #define NXT_HTTP_LAST_CLIENT_ERROR                                            \
641431Sigor@sysoev.ru     (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1)
642431Sigor@sysoev.ru 
643431Sigor@sysoev.ru static const nxt_str_t  nxt_http_client_error[] = {
644431Sigor@sysoev.ru     nxt_string("HTTP/1.1 400 Bad Request\r\n"),
645431Sigor@sysoev.ru     nxt_string("HTTP/1.1 401 Unauthorized\r\n"),
646431Sigor@sysoev.ru     nxt_string("HTTP/1.1 402 Payment Required\r\n"),
647431Sigor@sysoev.ru     nxt_string("HTTP/1.1 403 Forbidden\r\n"),
648431Sigor@sysoev.ru     nxt_string("HTTP/1.1 404 Not Found\r\n"),
649431Sigor@sysoev.ru     nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"),
650431Sigor@sysoev.ru     nxt_string("HTTP/1.1 406 Not Acceptable\r\n"),
651431Sigor@sysoev.ru     nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"),
652431Sigor@sysoev.ru     nxt_string("HTTP/1.1 408 Request Timeout\r\n"),
653431Sigor@sysoev.ru     nxt_string("HTTP/1.1 409 Conflict\r\n"),
654431Sigor@sysoev.ru     nxt_string("HTTP/1.1 410 Gone\r\n"),
655431Sigor@sysoev.ru     nxt_string("HTTP/1.1 411 Length Required\r\n"),
656431Sigor@sysoev.ru     nxt_string("HTTP/1.1 412 Precondition Failed\r\n"),
657431Sigor@sysoev.ru     nxt_string("HTTP/1.1 413 Payload Too Large\r\n"),
658431Sigor@sysoev.ru     nxt_string("HTTP/1.1 414 URI Too Long\r\n"),
659431Sigor@sysoev.ru     nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"),
660431Sigor@sysoev.ru     nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"),
661431Sigor@sysoev.ru     nxt_string("HTTP/1.1 417 Expectation Failed\r\n"),
662431Sigor@sysoev.ru     nxt_string("HTTP/1.1 418\r\n"),
663431Sigor@sysoev.ru     nxt_string("HTTP/1.1 419\r\n"),
664431Sigor@sysoev.ru     nxt_string("HTTP/1.1 420\r\n"),
665431Sigor@sysoev.ru     nxt_string("HTTP/1.1 421\r\n"),
666431Sigor@sysoev.ru     nxt_string("HTTP/1.1 422\r\n"),
667431Sigor@sysoev.ru     nxt_string("HTTP/1.1 423\r\n"),
668431Sigor@sysoev.ru     nxt_string("HTTP/1.1 424\r\n"),
669431Sigor@sysoev.ru     nxt_string("HTTP/1.1 425\r\n"),
670431Sigor@sysoev.ru     nxt_string("HTTP/1.1 426\r\n"),
671431Sigor@sysoev.ru     nxt_string("HTTP/1.1 427\r\n"),
672431Sigor@sysoev.ru     nxt_string("HTTP/1.1 428\r\n"),
673431Sigor@sysoev.ru     nxt_string("HTTP/1.1 429\r\n"),
674431Sigor@sysoev.ru     nxt_string("HTTP/1.1 430\r\n"),
675431Sigor@sysoev.ru     nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"),
676431Sigor@sysoev.ru };
677431Sigor@sysoev.ru 
678431Sigor@sysoev.ru 
679431Sigor@sysoev.ru #define NXT_HTTP_LAST_SERVER_ERROR                                            \
680431Sigor@sysoev.ru     (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1)
681431Sigor@sysoev.ru 
682431Sigor@sysoev.ru static const nxt_str_t  nxt_http_server_error[] = {
683431Sigor@sysoev.ru     nxt_string("HTTP/1.1 500 Internal Server Error\r\n"),
684431Sigor@sysoev.ru     nxt_string("HTTP/1.1 501 Not Implemented\r\n"),
685431Sigor@sysoev.ru     nxt_string("HTTP/1.1 502 Bad Gateway\r\n"),
686431Sigor@sysoev.ru     nxt_string("HTTP/1.1 503 Service Unavailable\r\n"),
687431Sigor@sysoev.ru     nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"),
688482Svbart@nginx.com     nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"),
689431Sigor@sysoev.ru };
690431Sigor@sysoev.ru 
691431Sigor@sysoev.ru 
692431Sigor@sysoev.ru #define UNKNOWN_STATUS_LENGTH  (sizeof("HTTP/1.1 65536\r\n") - 1)
693431Sigor@sysoev.ru 
694431Sigor@sysoev.ru static void
695431Sigor@sysoev.ru nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
696431Sigor@sysoev.ru {
697431Sigor@sysoev.ru     u_char              *p;
698431Sigor@sysoev.ru     size_t              size;
699431Sigor@sysoev.ru     nxt_buf_t           *header;
700431Sigor@sysoev.ru     nxt_str_t           unknown_status;
701431Sigor@sysoev.ru     nxt_int_t           conn;
702431Sigor@sysoev.ru     nxt_uint_t          n;
703431Sigor@sysoev.ru     nxt_bool_t          http11;
704431Sigor@sysoev.ru     nxt_conn_t          *c;
705431Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
706431Sigor@sysoev.ru     const nxt_str_t     *status;
707431Sigor@sysoev.ru     nxt_http_field_t    *field;
708431Sigor@sysoev.ru     nxt_event_engine_t  *engine;
709431Sigor@sysoev.ru     u_char              buf[UNKNOWN_STATUS_LENGTH];
710431Sigor@sysoev.ru 
711431Sigor@sysoev.ru     static const char   chunked[] = "Transfer-Encoding: chunked\r\n";
712431Sigor@sysoev.ru 
713431Sigor@sysoev.ru     static const nxt_str_t  connection[2] = {
714431Sigor@sysoev.ru         nxt_string("Connection: close\r\n"),
715431Sigor@sysoev.ru         nxt_string("Connection: keep-alive\r\n"),
716431Sigor@sysoev.ru     };
717431Sigor@sysoev.ru 
718431Sigor@sysoev.ru     nxt_debug(task, "h1p request header send");
719431Sigor@sysoev.ru 
720431Sigor@sysoev.ru     r->header_sent = 1;
721431Sigor@sysoev.ru     h1p = r->proto.h1;
722431Sigor@sysoev.ru     n = r->status;
723431Sigor@sysoev.ru 
724431Sigor@sysoev.ru     if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) {
725431Sigor@sysoev.ru         status = &nxt_http_success[n - NXT_HTTP_OK];
726431Sigor@sysoev.ru 
727431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_MULTIPLE_CHOICES
728431Sigor@sysoev.ru                && n <= NXT_HTTP_LAST_REDIRECTION)
729431Sigor@sysoev.ru     {
730431Sigor@sysoev.ru         status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES];
731431Sigor@sysoev.ru 
732431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) {
733431Sigor@sysoev.ru         status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST];
734431Sigor@sysoev.ru 
735431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR
736431Sigor@sysoev.ru                && n <= NXT_HTTP_LAST_SERVER_ERROR)
737431Sigor@sysoev.ru     {
738431Sigor@sysoev.ru         status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR];
739431Sigor@sysoev.ru 
740431Sigor@sysoev.ru     } else {
741431Sigor@sysoev.ru         p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH,
742431Sigor@sysoev.ru                         "HTTP/1.1 %03d\r\n", n);
743431Sigor@sysoev.ru 
744431Sigor@sysoev.ru         unknown_status.length = p - buf;
745431Sigor@sysoev.ru         unknown_status.start = buf;
746431Sigor@sysoev.ru         status = &unknown_status;
747431Sigor@sysoev.ru     }
748431Sigor@sysoev.ru 
749450Sigor@sysoev.ru     size = status->length;
750450Sigor@sysoev.ru     /* Trailing CRLF at the end of header. */
751450Sigor@sysoev.ru     size += sizeof("\r\n") - 1;
752431Sigor@sysoev.ru 
753481Svbart@nginx.com     http11 = (h1p->parser.version.s.minor != '0');
754431Sigor@sysoev.ru 
755431Sigor@sysoev.ru     if (r->resp.content_length == NULL || r->resp.content_length->skip) {
756431Sigor@sysoev.ru         if (http11) {
757431Sigor@sysoev.ru             h1p->chunked = 1;
758431Sigor@sysoev.ru             size += sizeof(chunked) - 1;
759450Sigor@sysoev.ru             /* Trailing CRLF will be added by the first chunk header. */
760450Sigor@sysoev.ru             size -= sizeof("\r\n") - 1;
761431Sigor@sysoev.ru 
762431Sigor@sysoev.ru         } else {
763431Sigor@sysoev.ru             h1p->keepalive = 0;
764431Sigor@sysoev.ru         }
765431Sigor@sysoev.ru     }
766431Sigor@sysoev.ru 
767431Sigor@sysoev.ru     conn = -1;
768431Sigor@sysoev.ru 
769431Sigor@sysoev.ru     if (http11 ^ h1p->keepalive) {
770431Sigor@sysoev.ru         conn = h1p->keepalive;
771431Sigor@sysoev.ru         size += connection[conn].length;
772431Sigor@sysoev.ru     }
773431Sigor@sysoev.ru 
774431Sigor@sysoev.ru     nxt_list_each(field, r->resp.fields) {
775431Sigor@sysoev.ru 
776431Sigor@sysoev.ru         if (!field->skip) {
777431Sigor@sysoev.ru             size += field->name_length + field->value_length;
778431Sigor@sysoev.ru             size += sizeof(": \r\n") - 1;
779431Sigor@sysoev.ru         }
780431Sigor@sysoev.ru 
781431Sigor@sysoev.ru     } nxt_list_loop;
782431Sigor@sysoev.ru 
783608Sigor@sysoev.ru     header = nxt_http_buf_mem(task, r, size);
784431Sigor@sysoev.ru     if (nxt_slow_path(header == NULL)) {
785608Sigor@sysoev.ru         nxt_h1p_request_error(task, r);
786431Sigor@sysoev.ru         return;
787431Sigor@sysoev.ru     }
788431Sigor@sysoev.ru 
789431Sigor@sysoev.ru     p = header->mem.free;
790431Sigor@sysoev.ru 
791431Sigor@sysoev.ru     p = nxt_cpymem(p, status->start, status->length);
792431Sigor@sysoev.ru 
793431Sigor@sysoev.ru     nxt_list_each(field, r->resp.fields) {
794431Sigor@sysoev.ru 
795431Sigor@sysoev.ru         if (!field->skip) {
796431Sigor@sysoev.ru             p = nxt_cpymem(p, field->name, field->name_length);
797431Sigor@sysoev.ru             *p++ = ':'; *p++ = ' ';
798431Sigor@sysoev.ru             p = nxt_cpymem(p, field->value, field->value_length);
799431Sigor@sysoev.ru             *p++ = '\r'; *p++ = '\n';
800431Sigor@sysoev.ru         }
801431Sigor@sysoev.ru 
802431Sigor@sysoev.ru     } nxt_list_loop;
803431Sigor@sysoev.ru 
804431Sigor@sysoev.ru     if (conn >= 0) {
805431Sigor@sysoev.ru         p = nxt_cpymem(p, connection[conn].start, connection[conn].length);
806431Sigor@sysoev.ru     }
807431Sigor@sysoev.ru 
808431Sigor@sysoev.ru     if (h1p->chunked) {
809431Sigor@sysoev.ru         p = nxt_cpymem(p, chunked, sizeof(chunked) - 1);
810450Sigor@sysoev.ru         /* Trailing CRLF will be added by the first chunk header. */
811431Sigor@sysoev.ru 
812431Sigor@sysoev.ru     } else {
813431Sigor@sysoev.ru         *p++ = '\r'; *p++ = '\n';
814431Sigor@sysoev.ru     }
815431Sigor@sysoev.ru 
816431Sigor@sysoev.ru     header->mem.free = p;
817431Sigor@sysoev.ru 
818*630Svbart@nginx.com     h1p->header_size = nxt_buf_mem_used_size(&header->mem);
819*630Svbart@nginx.com 
820431Sigor@sysoev.ru     c = h1p->conn;
821431Sigor@sysoev.ru 
822431Sigor@sysoev.ru     c->write = header;
823431Sigor@sysoev.ru     c->write_state = &nxt_h1p_send_state;
824431Sigor@sysoev.ru 
825431Sigor@sysoev.ru     engine = task->thread->engine;
826431Sigor@sysoev.ru 
827431Sigor@sysoev.ru     nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
828431Sigor@sysoev.ru                        task, r, NULL);
829431Sigor@sysoev.ru 
830431Sigor@sysoev.ru     nxt_conn_write(engine, c);
831431Sigor@sysoev.ru }
832431Sigor@sysoev.ru 
833431Sigor@sysoev.ru 
834431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_send_state
835431Sigor@sysoev.ru     nxt_aligned(64) =
836431Sigor@sysoev.ru {
837624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_request_sent,
838624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
839431Sigor@sysoev.ru 
840626Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_send_timeout,
841624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
842431Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, send_timeout),
843431Sigor@sysoev.ru     .timer_autoreset = 1,
844431Sigor@sysoev.ru };
845431Sigor@sysoev.ru 
846431Sigor@sysoev.ru 
847431Sigor@sysoev.ru static void
848431Sigor@sysoev.ru nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
849431Sigor@sysoev.ru {
850431Sigor@sysoev.ru     nxt_conn_t  *c;
851431Sigor@sysoev.ru 
852431Sigor@sysoev.ru     nxt_debug(task, "h1p request send");
853431Sigor@sysoev.ru 
854431Sigor@sysoev.ru     c = r->proto.h1->conn;
855431Sigor@sysoev.ru 
856431Sigor@sysoev.ru     if (r->proto.h1->chunked) {
857431Sigor@sysoev.ru         out = nxt_h1p_chunk_create(task, r, out);
858431Sigor@sysoev.ru         if (nxt_slow_path(out == NULL)) {
859608Sigor@sysoev.ru             nxt_h1p_request_error(task, r);
860431Sigor@sysoev.ru             return;
861431Sigor@sysoev.ru         }
862431Sigor@sysoev.ru     }
863431Sigor@sysoev.ru 
864431Sigor@sysoev.ru     if (c->write == NULL) {
865431Sigor@sysoev.ru         c->write = out;
866431Sigor@sysoev.ru         c->write_state = &nxt_h1p_send_state;
867431Sigor@sysoev.ru 
868431Sigor@sysoev.ru         nxt_conn_write(task->thread->engine, c);
869431Sigor@sysoev.ru 
870431Sigor@sysoev.ru     } else {
871431Sigor@sysoev.ru         nxt_buf_chain_add(&c->write, out);
872431Sigor@sysoev.ru     }
873431Sigor@sysoev.ru }
874431Sigor@sysoev.ru 
875431Sigor@sysoev.ru 
876431Sigor@sysoev.ru static nxt_buf_t *
877431Sigor@sysoev.ru nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
878431Sigor@sysoev.ru {
879483Sigor@sysoev.ru     nxt_off_t          size;
880431Sigor@sysoev.ru     nxt_buf_t          *b, **prev, *header, *tail;
881431Sigor@sysoev.ru 
882431Sigor@sysoev.ru     const size_t       chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN;
883431Sigor@sysoev.ru     static const char  tail_chunk[] = "\r\n0\r\n\r\n";
884431Sigor@sysoev.ru 
885431Sigor@sysoev.ru     size = 0;
886431Sigor@sysoev.ru     prev = &out;
887431Sigor@sysoev.ru 
888431Sigor@sysoev.ru     for (b = out; b != NULL; b = b->next) {
889431Sigor@sysoev.ru 
890431Sigor@sysoev.ru         if (nxt_buf_is_last(b)) {
891608Sigor@sysoev.ru             tail = nxt_http_buf_mem(task, r, chunk_size);
892431Sigor@sysoev.ru             if (nxt_slow_path(tail == NULL)) {
893431Sigor@sysoev.ru                 return NULL;
894431Sigor@sysoev.ru             }
895431Sigor@sysoev.ru 
896431Sigor@sysoev.ru             *prev = tail;
897431Sigor@sysoev.ru             tail->next = b;
898431Sigor@sysoev.ru             /*
899431Sigor@sysoev.ru              * The tail_chunk size with trailing zero is 8 bytes, so
900431Sigor@sysoev.ru              * memcpy may be inlined with just single 8 byte move operation.
901431Sigor@sysoev.ru              */
902431Sigor@sysoev.ru             nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk));
903431Sigor@sysoev.ru             tail->mem.free += sizeof(tail_chunk) - 1;
904431Sigor@sysoev.ru 
905431Sigor@sysoev.ru             break;
906431Sigor@sysoev.ru         }
907431Sigor@sysoev.ru 
908431Sigor@sysoev.ru         size += nxt_buf_used_size(b);
909431Sigor@sysoev.ru         prev = &b->next;
910431Sigor@sysoev.ru     }
911431Sigor@sysoev.ru 
912431Sigor@sysoev.ru     if (size == 0) {
913431Sigor@sysoev.ru         return out;
914431Sigor@sysoev.ru     }
915431Sigor@sysoev.ru 
916608Sigor@sysoev.ru     header = nxt_http_buf_mem(task, r, chunk_size);
917431Sigor@sysoev.ru     if (nxt_slow_path(header == NULL)) {
918431Sigor@sysoev.ru         return NULL;
919431Sigor@sysoev.ru     }
920431Sigor@sysoev.ru 
921431Sigor@sysoev.ru     header->next = out;
922431Sigor@sysoev.ru     header->mem.free = nxt_sprintf(header->mem.free, header->mem.end,
923431Sigor@sysoev.ru                                    "\r\n%xO\r\n", size);
924431Sigor@sysoev.ru     return header;
925431Sigor@sysoev.ru }
926431Sigor@sysoev.ru 
927431Sigor@sysoev.ru 
928431Sigor@sysoev.ru static void
929624Sigor@sysoev.ru nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data)
930431Sigor@sysoev.ru {
931431Sigor@sysoev.ru     nxt_conn_t          *c;
932431Sigor@sysoev.ru     nxt_event_engine_t  *engine;
933431Sigor@sysoev.ru 
934431Sigor@sysoev.ru     c = obj;
935431Sigor@sysoev.ru 
936624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request sent");
937431Sigor@sysoev.ru 
938431Sigor@sysoev.ru     engine = task->thread->engine;
939431Sigor@sysoev.ru 
940592Sigor@sysoev.ru     c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
941592Sigor@sysoev.ru 
942431Sigor@sysoev.ru     if (c->write != NULL) {
943431Sigor@sysoev.ru         nxt_conn_write(engine, c);
944431Sigor@sysoev.ru     }
945431Sigor@sysoev.ru }
946431Sigor@sysoev.ru 
947431Sigor@sysoev.ru 
948*630Svbart@nginx.com static nxt_off_t
949*630Svbart@nginx.com nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto)
950*630Svbart@nginx.com {
951*630Svbart@nginx.com     nxt_off_t      sent;
952*630Svbart@nginx.com     nxt_h1proto_t  *h1p;
953*630Svbart@nginx.com 
954*630Svbart@nginx.com     h1p = proto.h1;
955*630Svbart@nginx.com 
956*630Svbart@nginx.com     sent = h1p->conn->sent - h1p->header_size;
957*630Svbart@nginx.com 
958*630Svbart@nginx.com     return (sent > 0) ? sent : 0;
959*630Svbart@nginx.com }
960*630Svbart@nginx.com 
961*630Svbart@nginx.com 
962431Sigor@sysoev.ru static void
963608Sigor@sysoev.ru nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
964608Sigor@sysoev.ru     nxt_buf_t *last)
965608Sigor@sysoev.ru {
966608Sigor@sysoev.ru     nxt_buf_t         *b;
967608Sigor@sysoev.ru     nxt_conn_t        *c;
968608Sigor@sysoev.ru     nxt_h1proto_t     *h1p;
969608Sigor@sysoev.ru     nxt_work_queue_t  *wq;
970608Sigor@sysoev.ru 
971608Sigor@sysoev.ru     nxt_debug(task, "h1p request discard");
972608Sigor@sysoev.ru 
973608Sigor@sysoev.ru     h1p = r->proto.h1;
974608Sigor@sysoev.ru     h1p->keepalive = 0;
975608Sigor@sysoev.ru 
976608Sigor@sysoev.ru     c = h1p->conn;
977608Sigor@sysoev.ru     b = c->write;
978608Sigor@sysoev.ru     c->write = NULL;
979608Sigor@sysoev.ru 
980608Sigor@sysoev.ru     wq = &task->thread->engine->fast_work_queue;
981608Sigor@sysoev.ru 
982608Sigor@sysoev.ru     nxt_sendbuf_drain(task, wq, b);
983608Sigor@sysoev.ru     nxt_sendbuf_drain(task, wq, last);
984608Sigor@sysoev.ru }
985608Sigor@sysoev.ru 
986608Sigor@sysoev.ru 
987608Sigor@sysoev.ru static void
988431Sigor@sysoev.ru nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto)
989431Sigor@sysoev.ru {
990431Sigor@sysoev.ru     nxt_conn_t     *c;
991431Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
992431Sigor@sysoev.ru 
993431Sigor@sysoev.ru     nxt_debug(task, "h1p request close");
994431Sigor@sysoev.ru 
995431Sigor@sysoev.ru     h1p = proto.h1;
996431Sigor@sysoev.ru     h1p->request = NULL;
997431Sigor@sysoev.ru 
998431Sigor@sysoev.ru     c = h1p->conn;
999431Sigor@sysoev.ru 
1000431Sigor@sysoev.ru     if (h1p->keepalive) {
1001431Sigor@sysoev.ru         nxt_h1p_keepalive(task, h1p, c);
1002431Sigor@sysoev.ru 
1003431Sigor@sysoev.ru     } else {
1004431Sigor@sysoev.ru         nxt_h1p_close(task, c);
1005431Sigor@sysoev.ru     }
1006431Sigor@sysoev.ru }
1007431Sigor@sysoev.ru 
1008431Sigor@sysoev.ru 
1009431Sigor@sysoev.ru static void
1010431Sigor@sysoev.ru nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c)
1011431Sigor@sysoev.ru {
1012431Sigor@sysoev.ru     size_t     size;
1013431Sigor@sysoev.ru     nxt_buf_t  *in, *b, *next;
1014431Sigor@sysoev.ru 
1015431Sigor@sysoev.ru     nxt_debug(task, "h1p keepalive");
1016431Sigor@sysoev.ru 
1017436Sigor@sysoev.ru     if (!c->tcp_nodelay) {
1018436Sigor@sysoev.ru         nxt_conn_tcp_nodelay_on(task, c);
1019436Sigor@sysoev.ru     }
1020436Sigor@sysoev.ru 
1021431Sigor@sysoev.ru     b = h1p->buffers;
1022431Sigor@sysoev.ru 
1023452Sigor@sysoev.ru     nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn));
1024431Sigor@sysoev.ru 
1025*630Svbart@nginx.com     c->sent = 0;
1026*630Svbart@nginx.com 
1027431Sigor@sysoev.ru     in = c->read;
1028431Sigor@sysoev.ru 
1029459Sigor@sysoev.ru     if (in == NULL) {
1030459Sigor@sysoev.ru         /* A request with large body. */
1031459Sigor@sysoev.ru         in = b;
1032459Sigor@sysoev.ru         c->read = in;
1033459Sigor@sysoev.ru 
1034459Sigor@sysoev.ru         b = in->next;
1035459Sigor@sysoev.ru         in->next = NULL;
1036459Sigor@sysoev.ru     }
1037459Sigor@sysoev.ru 
1038459Sigor@sysoev.ru     while (b != NULL) {
1039459Sigor@sysoev.ru         next = b->next;
1040459Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, b);
1041459Sigor@sysoev.ru         b = next;
1042459Sigor@sysoev.ru     }
1043459Sigor@sysoev.ru 
1044431Sigor@sysoev.ru     size = nxt_buf_mem_used_size(&in->mem);
1045431Sigor@sysoev.ru 
1046431Sigor@sysoev.ru     if (size == 0) {
1047629Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, in);
1048431Sigor@sysoev.ru 
1049629Sigor@sysoev.ru         c->read = NULL;
1050628Sigor@sysoev.ru         c->read_state = &nxt_h1p_keepalive_state;
1051431Sigor@sysoev.ru 
1052628Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
1053431Sigor@sysoev.ru 
1054431Sigor@sysoev.ru     } else {
1055431Sigor@sysoev.ru         nxt_debug(task, "h1p pipelining");
1056431Sigor@sysoev.ru 
1057431Sigor@sysoev.ru         nxt_memmove(in->mem.start, in->mem.pos, size);
1058431Sigor@sysoev.ru 
1059431Sigor@sysoev.ru         in->mem.pos = in->mem.start;
1060431Sigor@sysoev.ru         in->mem.free = in->mem.start + size;
1061431Sigor@sysoev.ru 
1062627Svbart@nginx.com         nxt_h1p_conn_request_init(task, c, c->socket.data);
1063431Sigor@sysoev.ru     }
1064431Sigor@sysoev.ru }
1065431Sigor@sysoev.ru 
1066431Sigor@sysoev.ru 
1067624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_keepalive_state
1068624Sigor@sysoev.ru     nxt_aligned(64) =
1069431Sigor@sysoev.ru {
1070628Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_request_init,
1071624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_error,
1072624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_error,
1073624Sigor@sysoev.ru 
1074629Sigor@sysoev.ru     .io_read_handler = nxt_h1p_conn_io_read_handler,
1075629Sigor@sysoev.ru 
1076624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_timeout,
1077624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
1078624Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
1079624Sigor@sysoev.ru };
1080624Sigor@sysoev.ru 
1081624Sigor@sysoev.ru 
1082624Sigor@sysoev.ru static void
1083431Sigor@sysoev.ru nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data)
1084431Sigor@sysoev.ru {
1085624Sigor@sysoev.ru     nxt_conn_t  *c;
1086431Sigor@sysoev.ru 
1087431Sigor@sysoev.ru     c = obj;
1088431Sigor@sysoev.ru 
1089431Sigor@sysoev.ru     nxt_debug(task, "h1p conn error");
1090431Sigor@sysoev.ru 
1091624Sigor@sysoev.ru     nxt_h1p_close(task, c);
1092431Sigor@sysoev.ru }
1093431Sigor@sysoev.ru 
1094431Sigor@sysoev.ru 
1095431Sigor@sysoev.ru static void
1096431Sigor@sysoev.ru nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data)
1097431Sigor@sysoev.ru {
1098431Sigor@sysoev.ru     nxt_conn_t   *c;
1099431Sigor@sysoev.ru     nxt_timer_t  *timer;
1100431Sigor@sysoev.ru 
1101431Sigor@sysoev.ru     timer = obj;
1102431Sigor@sysoev.ru 
1103431Sigor@sysoev.ru     nxt_debug(task, "h1p conn timeout");
1104431Sigor@sysoev.ru 
1105431Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1106431Sigor@sysoev.ru 
1107624Sigor@sysoev.ru     nxt_h1p_close(task, c);
1108624Sigor@sysoev.ru }
1109624Sigor@sysoev.ru 
1110624Sigor@sysoev.ru 
1111624Sigor@sysoev.ru static void
1112624Sigor@sysoev.ru nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c)
1113624Sigor@sysoev.ru {
1114624Sigor@sysoev.ru     nxt_debug(task, "h1p close");
1115624Sigor@sysoev.ru 
1116624Sigor@sysoev.ru     c->socket.data = NULL;
1117624Sigor@sysoev.ru 
1118624Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
1119624Sigor@sysoev.ru 
1120624Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
1121624Sigor@sysoev.ru }
1122624Sigor@sysoev.ru 
1123624Sigor@sysoev.ru 
1124624Sigor@sysoev.ru static void
1125624Sigor@sysoev.ru nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data)
1126624Sigor@sysoev.ru {
1127624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
1128624Sigor@sysoev.ru     nxt_http_request_t  *r;
1129624Sigor@sysoev.ru 
1130624Sigor@sysoev.ru     h1p = data;
1131624Sigor@sysoev.ru 
1132624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request error");
1133624Sigor@sysoev.ru 
1134624Sigor@sysoev.ru     r = h1p->request;
1135624Sigor@sysoev.ru 
1136624Sigor@sysoev.ru     if (r->fields == NULL) {
1137624Sigor@sysoev.ru         (void) nxt_h1p_header_process(h1p, r);
1138624Sigor@sysoev.ru     }
1139624Sigor@sysoev.ru 
1140624Sigor@sysoev.ru     if (r->status == 0) {
1141624Sigor@sysoev.ru         r->status = NXT_HTTP_BAD_REQUEST;
1142624Sigor@sysoev.ru     }
1143624Sigor@sysoev.ru 
1144624Sigor@sysoev.ru     nxt_h1p_request_error(task, r);
1145624Sigor@sysoev.ru }
1146624Sigor@sysoev.ru 
1147624Sigor@sysoev.ru 
1148624Sigor@sysoev.ru static void
1149624Sigor@sysoev.ru nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data)
1150624Sigor@sysoev.ru {
1151624Sigor@sysoev.ru     nxt_conn_t          *c;
1152624Sigor@sysoev.ru     nxt_timer_t         *timer;
1153624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
1154624Sigor@sysoev.ru     nxt_http_request_t  *r;
1155624Sigor@sysoev.ru 
1156624Sigor@sysoev.ru     timer = obj;
1157624Sigor@sysoev.ru 
1158624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request timeout");
1159624Sigor@sysoev.ru 
1160624Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1161626Sigor@sysoev.ru     /*
1162626Sigor@sysoev.ru      * Disable SO_LINGER off during socket closing
1163626Sigor@sysoev.ru      * to send "408 Request Timeout" error response.
1164626Sigor@sysoev.ru      */
1165626Sigor@sysoev.ru     c->socket.timedout = 0;
1166626Sigor@sysoev.ru 
1167624Sigor@sysoev.ru     h1p = c->socket.data;
1168624Sigor@sysoev.ru     r = h1p->request;
1169624Sigor@sysoev.ru 
1170624Sigor@sysoev.ru     if (r->fields == NULL) {
1171624Sigor@sysoev.ru         (void) nxt_h1p_header_process(h1p, r);
1172624Sigor@sysoev.ru     }
1173624Sigor@sysoev.ru 
1174626Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT);
1175626Sigor@sysoev.ru }
1176626Sigor@sysoev.ru 
1177624Sigor@sysoev.ru 
1178626Sigor@sysoev.ru static void
1179626Sigor@sysoev.ru nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data)
1180626Sigor@sysoev.ru {
1181626Sigor@sysoev.ru     nxt_conn_t     *c;
1182626Sigor@sysoev.ru     nxt_timer_t    *timer;
1183626Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
1184626Sigor@sysoev.ru 
1185626Sigor@sysoev.ru     timer = obj;
1186626Sigor@sysoev.ru 
1187626Sigor@sysoev.ru     nxt_debug(task, "h1p conn request send timeout");
1188626Sigor@sysoev.ru 
1189626Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1190626Sigor@sysoev.ru     h1p = c->socket.data;
1191626Sigor@sysoev.ru 
1192626Sigor@sysoev.ru     nxt_h1p_request_error(task, h1p->request);
1193624Sigor@sysoev.ru }
1194624Sigor@sysoev.ru 
1195624Sigor@sysoev.ru 
1196624Sigor@sysoev.ru nxt_inline void
1197624Sigor@sysoev.ru nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r)
1198624Sigor@sysoev.ru {
1199624Sigor@sysoev.ru     r->state->error_handler(task, r, r->proto.h1);
1200431Sigor@sysoev.ru }
1201431Sigor@sysoev.ru 
1202431Sigor@sysoev.ru 
1203431Sigor@sysoev.ru static nxt_msec_t
1204624Sigor@sysoev.ru nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
1205431Sigor@sysoev.ru {
1206431Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
1207431Sigor@sysoev.ru 
1208431Sigor@sysoev.ru     joint = c->joint;
1209431Sigor@sysoev.ru 
1210431Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
1211431Sigor@sysoev.ru }
1212