xref: /unit/src/nxt_h1proto.c (revision 636)
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);
38630Svbart@nginx.com static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task,
39630Svbart@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 
92630Svbart@nginx.com const nxt_http_proto_body_bytes_sent_t  nxt_http_proto_body_bytes_sent[3] = {
93630Svbart@nginx.com     nxt_h1p_request_body_bytes_sent,
94630Svbart@nginx.com     NULL,
95630Svbart@nginx.com     NULL,
96630Svbart@nginx.com };
97630Svbart@nginx.com 
98630Svbart@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) },
122630Svbart@nginx.com     { nxt_string("Referer"),           &nxt_http_request_field,
123630Svbart@nginx.com         offsetof(nxt_http_request_t, referer) },
124630Svbart@nginx.com     { nxt_string("User-Agent"),        &nxt_http_request_field,
125630Svbart@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,
181635Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
182*636Sigor@sysoev.ru     .timer_autoreset = 1,
183431Sigor@sysoev.ru };
184431Sigor@sysoev.ru 
185431Sigor@sysoev.ru 
186629Sigor@sysoev.ru static ssize_t
187629Sigor@sysoev.ru nxt_h1p_conn_io_read_handler(nxt_conn_t *c)
188629Sigor@sysoev.ru {
189629Sigor@sysoev.ru     size_t                   size;
190629Sigor@sysoev.ru     ssize_t                  n;
191629Sigor@sysoev.ru     nxt_buf_t                *b;
192629Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
193629Sigor@sysoev.ru 
194629Sigor@sysoev.ru     joint = c->joint;
195629Sigor@sysoev.ru     size = joint->socket_conf->header_buffer_size;
196629Sigor@sysoev.ru 
197629Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
198629Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
199629Sigor@sysoev.ru         c->socket.error = NXT_ENOMEM;
200629Sigor@sysoev.ru         return NXT_ERROR;
201629Sigor@sysoev.ru     }
202629Sigor@sysoev.ru 
203629Sigor@sysoev.ru     n = c->io->recvbuf(c, b);
204629Sigor@sysoev.ru 
205629Sigor@sysoev.ru     if (n > 0) {
206629Sigor@sysoev.ru         c->read = b;
207629Sigor@sysoev.ru 
208629Sigor@sysoev.ru     } else {
209629Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, b);
210629Sigor@sysoev.ru     }
211629Sigor@sysoev.ru 
212629Sigor@sysoev.ru     return n;
213629Sigor@sysoev.ru }
214629Sigor@sysoev.ru 
215629Sigor@sysoev.ru 
216431Sigor@sysoev.ru static void
217624Sigor@sysoev.ru nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data)
218431Sigor@sysoev.ru {
219624Sigor@sysoev.ru     nxt_conn_t     *c;
220624Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
221624Sigor@sysoev.ru 
222624Sigor@sysoev.ru     c = obj;
223624Sigor@sysoev.ru 
224624Sigor@sysoev.ru     nxt_debug(task, "h1p conn proto init");
225624Sigor@sysoev.ru 
226624Sigor@sysoev.ru     h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t));
227624Sigor@sysoev.ru     if (nxt_slow_path(h1p == NULL)) {
228624Sigor@sysoev.ru         nxt_h1p_close(task, c);
229624Sigor@sysoev.ru         return;
230624Sigor@sysoev.ru     }
231624Sigor@sysoev.ru 
232624Sigor@sysoev.ru     c->socket.data = h1p;
233624Sigor@sysoev.ru     h1p->conn = c;
234624Sigor@sysoev.ru 
235624Sigor@sysoev.ru     nxt_h1p_conn_request_init(task, c, h1p);
236624Sigor@sysoev.ru }
237624Sigor@sysoev.ru 
238624Sigor@sysoev.ru 
239624Sigor@sysoev.ru static void
240624Sigor@sysoev.ru nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
241624Sigor@sysoev.ru {
242431Sigor@sysoev.ru     nxt_int_t                ret;
243431Sigor@sysoev.ru     nxt_conn_t               *c;
244431Sigor@sysoev.ru     nxt_h1proto_t            *h1p;
245431Sigor@sysoev.ru     nxt_http_request_t       *r;
246431Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
247431Sigor@sysoev.ru 
248431Sigor@sysoev.ru     c = obj;
249431Sigor@sysoev.ru     h1p = data;
250431Sigor@sysoev.ru 
251624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request init");
252431Sigor@sysoev.ru 
253624Sigor@sysoev.ru     r = nxt_http_request_create(task);
254431Sigor@sysoev.ru 
255624Sigor@sysoev.ru     if (nxt_fast_path(r != NULL)) {
256431Sigor@sysoev.ru         h1p->request = r;
257431Sigor@sysoev.ru         r->proto.h1 = h1p;
258624Sigor@sysoev.ru 
259431Sigor@sysoev.ru         joint = c->joint;
260431Sigor@sysoev.ru         r->socket_conf = joint->socket_conf;
261431Sigor@sysoev.ru 
262431Sigor@sysoev.ru         r->remote = c->remote;
263431Sigor@sysoev.ru 
264431Sigor@sysoev.ru         ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
265624Sigor@sysoev.ru 
266624Sigor@sysoev.ru         if (nxt_fast_path(ret == NXT_OK)) {
267624Sigor@sysoev.ru             nxt_h1p_conn_header_parse(task, c, h1p);
268624Sigor@sysoev.ru             return;
269431Sigor@sysoev.ru         }
270624Sigor@sysoev.ru 
271624Sigor@sysoev.ru         /*
272624Sigor@sysoev.ru          * The request is very incomplete here,
273624Sigor@sysoev.ru          * so "internal server error" useless here.
274624Sigor@sysoev.ru          */
275624Sigor@sysoev.ru         nxt_mp_release(r->mem_pool);
276431Sigor@sysoev.ru     }
277431Sigor@sysoev.ru 
278624Sigor@sysoev.ru     nxt_h1p_close(task, c);
279624Sigor@sysoev.ru }
280624Sigor@sysoev.ru 
281624Sigor@sysoev.ru 
282624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_header_parse_state
283624Sigor@sysoev.ru     nxt_aligned(64) =
284624Sigor@sysoev.ru {
285624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_header_parse,
286624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_request_error,
287624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
288624Sigor@sysoev.ru 
289624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_timeout,
290624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
291624Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
292624Sigor@sysoev.ru };
293624Sigor@sysoev.ru 
294624Sigor@sysoev.ru 
295624Sigor@sysoev.ru static void
296624Sigor@sysoev.ru nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
297624Sigor@sysoev.ru {
298624Sigor@sysoev.ru     nxt_int_t           ret;
299624Sigor@sysoev.ru     nxt_conn_t          *c;
300624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
301624Sigor@sysoev.ru     nxt_http_status_t   status;
302624Sigor@sysoev.ru     nxt_http_request_t  *r;
303624Sigor@sysoev.ru 
304624Sigor@sysoev.ru     c = obj;
305624Sigor@sysoev.ru     h1p = data;
306624Sigor@sysoev.ru 
307624Sigor@sysoev.ru     nxt_debug(task, "h1p conn header parse");
308624Sigor@sysoev.ru 
309431Sigor@sysoev.ru     ret = nxt_http_parse_request(&h1p->parser, &c->read->mem);
310431Sigor@sysoev.ru 
311*636Sigor@sysoev.ru     ret = nxt_expect(NXT_DONE, ret);
312624Sigor@sysoev.ru 
313*636Sigor@sysoev.ru     if (ret != NXT_AGAIN) {
314*636Sigor@sysoev.ru         nxt_timer_disable(task->thread->engine, &c->read_timer);
315*636Sigor@sysoev.ru     }
316*636Sigor@sysoev.ru 
317*636Sigor@sysoev.ru     r = h1p->request;
318625Sigor@sysoev.ru 
319625Sigor@sysoev.ru     switch (ret) {
320625Sigor@sysoev.ru 
321625Sigor@sysoev.ru     case NXT_DONE:
322431Sigor@sysoev.ru         /*
323431Sigor@sysoev.ru          * By default the keepalive mode is disabled in HTTP/1.0 and
324431Sigor@sysoev.ru          * enabled in HTTP/1.1.  The mode can be overridden later by
325431Sigor@sysoev.ru          * the "Connection" field processed in nxt_h1p_connection().
326431Sigor@sysoev.ru          */
327481Svbart@nginx.com         h1p->keepalive = (h1p->parser.version.s.minor != '0');
328431Sigor@sysoev.ru 
329620Svbart@nginx.com         ret = nxt_h1p_header_process(h1p, r);
330431Sigor@sysoev.ru 
331431Sigor@sysoev.ru         if (nxt_fast_path(ret == NXT_OK)) {
332431Sigor@sysoev.ru             r->state->ready_handler(task, r, NULL);
333431Sigor@sysoev.ru             return;
334431Sigor@sysoev.ru         }
335431Sigor@sysoev.ru 
336480Svbart@nginx.com         /* ret == NXT_ERROR */
337625Sigor@sysoev.ru         status = NXT_HTTP_BAD_REQUEST;
338480Svbart@nginx.com 
339625Sigor@sysoev.ru         goto error;
340431Sigor@sysoev.ru 
341625Sigor@sysoev.ru     case NXT_AGAIN:
342625Sigor@sysoev.ru         status = nxt_h1p_header_buffer_test(task, h1p, c, r->socket_conf);
343431Sigor@sysoev.ru 
344625Sigor@sysoev.ru         if (nxt_fast_path(status == NXT_OK)) {
345625Sigor@sysoev.ru             c->read_state = &nxt_h1p_header_parse_state;
346431Sigor@sysoev.ru 
347625Sigor@sysoev.ru             nxt_conn_read(task->thread->engine, c);
348625Sigor@sysoev.ru             return;
349431Sigor@sysoev.ru         }
350431Sigor@sysoev.ru 
351625Sigor@sysoev.ru         break;
352480Svbart@nginx.com 
353480Svbart@nginx.com     case NXT_HTTP_PARSE_INVALID:
354480Svbart@nginx.com         status = NXT_HTTP_BAD_REQUEST;
355480Svbart@nginx.com         break;
356431Sigor@sysoev.ru 
357482Svbart@nginx.com     case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
358482Svbart@nginx.com         status = NXT_HTTP_VERSION_NOT_SUPPORTED;
359482Svbart@nginx.com         break;
360482Svbart@nginx.com 
361480Svbart@nginx.com     case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
362480Svbart@nginx.com         status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
363480Svbart@nginx.com         break;
364480Svbart@nginx.com 
365480Svbart@nginx.com     default:
366480Svbart@nginx.com     case NXT_ERROR:
367480Svbart@nginx.com         status = NXT_HTTP_INTERNAL_SERVER_ERROR;
368480Svbart@nginx.com         break;
369480Svbart@nginx.com     }
370480Svbart@nginx.com 
371620Svbart@nginx.com     (void) nxt_h1p_header_process(h1p, r);
372625Sigor@sysoev.ru 
373625Sigor@sysoev.ru error:
374625Sigor@sysoev.ru 
375480Svbart@nginx.com     nxt_http_request_error(task, r, status);
376431Sigor@sysoev.ru }
377431Sigor@sysoev.ru 
378431Sigor@sysoev.ru 
379431Sigor@sysoev.ru static nxt_int_t
380620Svbart@nginx.com nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r)
381620Svbart@nginx.com {
382620Svbart@nginx.com     r->target.start = h1p->parser.target_start;
383620Svbart@nginx.com     r->target.length = h1p->parser.target_end - h1p->parser.target_start;
384620Svbart@nginx.com 
385620Svbart@nginx.com     if (h1p->parser.version.ui64 != 0) {
386620Svbart@nginx.com         r->version.start = h1p->parser.version.str;
387620Svbart@nginx.com         r->version.length = sizeof(h1p->parser.version.str);
388620Svbart@nginx.com     }
389620Svbart@nginx.com 
390620Svbart@nginx.com     r->method = &h1p->parser.method;
391620Svbart@nginx.com     r->path = &h1p->parser.path;
392620Svbart@nginx.com     r->args = &h1p->parser.args;
393620Svbart@nginx.com 
394620Svbart@nginx.com     r->fields = h1p->parser.fields;
395620Svbart@nginx.com 
396620Svbart@nginx.com     return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r);
397620Svbart@nginx.com }
398620Svbart@nginx.com 
399620Svbart@nginx.com 
400620Svbart@nginx.com static nxt_int_t
401625Sigor@sysoev.ru nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
402625Sigor@sysoev.ru     nxt_socket_conf_t *skcf)
403625Sigor@sysoev.ru {
404625Sigor@sysoev.ru     size_t     size, used;
405625Sigor@sysoev.ru     nxt_buf_t  *in, *b;
406625Sigor@sysoev.ru 
407625Sigor@sysoev.ru     in = c->read;
408625Sigor@sysoev.ru 
409625Sigor@sysoev.ru     if (nxt_buf_mem_free_size(&in->mem) == 0) {
410625Sigor@sysoev.ru         size = skcf->large_header_buffer_size;
411625Sigor@sysoev.ru         used = nxt_buf_mem_used_size(&in->mem);
412625Sigor@sysoev.ru 
413625Sigor@sysoev.ru         if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
414625Sigor@sysoev.ru             return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
415625Sigor@sysoev.ru         }
416625Sigor@sysoev.ru 
417625Sigor@sysoev.ru         b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
418625Sigor@sysoev.ru         if (nxt_slow_path(b == NULL)) {
419625Sigor@sysoev.ru             return NXT_HTTP_INTERNAL_SERVER_ERROR;
420625Sigor@sysoev.ru         }
421625Sigor@sysoev.ru 
422625Sigor@sysoev.ru         b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
423625Sigor@sysoev.ru 
424625Sigor@sysoev.ru         in->next = h1p->buffers;
425625Sigor@sysoev.ru         h1p->buffers = in;
426625Sigor@sysoev.ru         h1p->nbuffers++;
427625Sigor@sysoev.ru 
428625Sigor@sysoev.ru         c->read = b;
429625Sigor@sysoev.ru     }
430625Sigor@sysoev.ru 
431625Sigor@sysoev.ru     return NXT_OK;
432625Sigor@sysoev.ru }
433625Sigor@sysoev.ru 
434625Sigor@sysoev.ru 
435625Sigor@sysoev.ru static nxt_int_t
436431Sigor@sysoev.ru nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
437431Sigor@sysoev.ru {
438431Sigor@sysoev.ru     nxt_http_request_t  *r;
439431Sigor@sysoev.ru 
440431Sigor@sysoev.ru     r = ctx;
441431Sigor@sysoev.ru 
442431Sigor@sysoev.ru     if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) {
443431Sigor@sysoev.ru         r->proto.h1->keepalive = 0;
444431Sigor@sysoev.ru     }
445431Sigor@sysoev.ru 
446431Sigor@sysoev.ru     return NXT_OK;
447431Sigor@sysoev.ru }
448431Sigor@sysoev.ru 
449431Sigor@sysoev.ru 
450431Sigor@sysoev.ru static nxt_int_t
451431Sigor@sysoev.ru nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data)
452431Sigor@sysoev.ru {
453431Sigor@sysoev.ru     nxt_http_te_t       te;
454431Sigor@sysoev.ru     nxt_http_request_t  *r;
455431Sigor@sysoev.ru 
456431Sigor@sysoev.ru     r = ctx;
457431Sigor@sysoev.ru 
458431Sigor@sysoev.ru     if (field->value_length == 7
459431Sigor@sysoev.ru         && nxt_memcmp(field->value, "chunked", 7) == 0)
460431Sigor@sysoev.ru     {
461431Sigor@sysoev.ru         te = NXT_HTTP_TE_CHUNKED;
462431Sigor@sysoev.ru 
463431Sigor@sysoev.ru     } else {
464431Sigor@sysoev.ru         te = NXT_HTTP_TE_UNSUPPORTED;
465431Sigor@sysoev.ru     }
466431Sigor@sysoev.ru 
467431Sigor@sysoev.ru     r->proto.h1->transfer_encoding = te;
468431Sigor@sysoev.ru 
469431Sigor@sysoev.ru     return NXT_OK;
470431Sigor@sysoev.ru }
471431Sigor@sysoev.ru 
472431Sigor@sysoev.ru 
473431Sigor@sysoev.ru static void
474431Sigor@sysoev.ru nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
475431Sigor@sysoev.ru {
476527Svbart@nginx.com     size_t             size, body_length;
477459Sigor@sysoev.ru     nxt_buf_t          *in, *b;
478431Sigor@sysoev.ru     nxt_conn_t         *c;
479459Sigor@sysoev.ru     nxt_h1proto_t      *h1p;
480431Sigor@sysoev.ru     nxt_http_status_t  status;
481431Sigor@sysoev.ru 
482459Sigor@sysoev.ru     h1p = r->proto.h1;
483459Sigor@sysoev.ru 
484624Sigor@sysoev.ru     nxt_debug(task, "h1p request body read %O te:%d",
485459Sigor@sysoev.ru               r->content_length_n, h1p->transfer_encoding);
486431Sigor@sysoev.ru 
487459Sigor@sysoev.ru     switch (h1p->transfer_encoding) {
488431Sigor@sysoev.ru 
489431Sigor@sysoev.ru     case NXT_HTTP_TE_CHUNKED:
490431Sigor@sysoev.ru         status = NXT_HTTP_LENGTH_REQUIRED;
491431Sigor@sysoev.ru         goto error;
492431Sigor@sysoev.ru 
493431Sigor@sysoev.ru     case NXT_HTTP_TE_UNSUPPORTED:
494431Sigor@sysoev.ru         status = NXT_HTTP_NOT_IMPLEMENTED;
495431Sigor@sysoev.ru         goto error;
496431Sigor@sysoev.ru 
497431Sigor@sysoev.ru     default:
498431Sigor@sysoev.ru     case NXT_HTTP_TE_NONE:
499431Sigor@sysoev.ru         break;
500431Sigor@sysoev.ru     }
501431Sigor@sysoev.ru 
502431Sigor@sysoev.ru     if (r->content_length_n == -1 || r->content_length_n == 0) {
503431Sigor@sysoev.ru         goto ready;
504431Sigor@sysoev.ru     }
505431Sigor@sysoev.ru 
506431Sigor@sysoev.ru     if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) {
507431Sigor@sysoev.ru         status = NXT_HTTP_PAYLOAD_TOO_LARGE;
508431Sigor@sysoev.ru         goto error;
509431Sigor@sysoev.ru     }
510431Sigor@sysoev.ru 
511527Svbart@nginx.com     body_length = (size_t) r->content_length_n;
512431Sigor@sysoev.ru 
513431Sigor@sysoev.ru     b = r->body;
514431Sigor@sysoev.ru 
515431Sigor@sysoev.ru     if (b == NULL) {
516527Svbart@nginx.com         b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0);
517431Sigor@sysoev.ru         if (nxt_slow_path(b == NULL)) {
518431Sigor@sysoev.ru             status = NXT_HTTP_INTERNAL_SERVER_ERROR;
519431Sigor@sysoev.ru             goto error;
520431Sigor@sysoev.ru         }
521431Sigor@sysoev.ru 
522431Sigor@sysoev.ru         r->body = b;
523431Sigor@sysoev.ru     }
524431Sigor@sysoev.ru 
525459Sigor@sysoev.ru     in = h1p->conn->read;
526431Sigor@sysoev.ru 
527459Sigor@sysoev.ru     size = nxt_buf_mem_used_size(&in->mem);
528431Sigor@sysoev.ru 
529431Sigor@sysoev.ru     if (size != 0) {
530527Svbart@nginx.com         if (size > body_length) {
531527Svbart@nginx.com             size = body_length;
532431Sigor@sysoev.ru         }
533431Sigor@sysoev.ru 
534459Sigor@sysoev.ru         b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
535459Sigor@sysoev.ru         in->mem.pos += size;
536431Sigor@sysoev.ru     }
537431Sigor@sysoev.ru 
538527Svbart@nginx.com     size = nxt_buf_mem_free_size(&b->mem);
539431Sigor@sysoev.ru 
540527Svbart@nginx.com     nxt_debug(task, "h1p body rest: %uz", size);
541431Sigor@sysoev.ru 
542527Svbart@nginx.com     if (size != 0) {
543459Sigor@sysoev.ru         in->next = h1p->buffers;
544459Sigor@sysoev.ru         h1p->buffers = in;
545459Sigor@sysoev.ru 
546459Sigor@sysoev.ru         c = h1p->conn;
547431Sigor@sysoev.ru         c->read = b;
548431Sigor@sysoev.ru         c->read_state = &nxt_h1p_read_body_state;
549431Sigor@sysoev.ru 
550431Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
551431Sigor@sysoev.ru         return;
552431Sigor@sysoev.ru     }
553431Sigor@sysoev.ru 
554431Sigor@sysoev.ru ready:
555431Sigor@sysoev.ru 
556431Sigor@sysoev.ru     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
557431Sigor@sysoev.ru                        r->state->ready_handler, task, r, NULL);
558431Sigor@sysoev.ru 
559431Sigor@sysoev.ru     return;
560431Sigor@sysoev.ru 
561431Sigor@sysoev.ru error:
562431Sigor@sysoev.ru 
563459Sigor@sysoev.ru     h1p->keepalive = 0;
564431Sigor@sysoev.ru 
565431Sigor@sysoev.ru     nxt_http_request_error(task, r, status);
566431Sigor@sysoev.ru }
567431Sigor@sysoev.ru 
568431Sigor@sysoev.ru 
569431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_read_body_state
570431Sigor@sysoev.ru     nxt_aligned(64) =
571431Sigor@sysoev.ru {
572624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_body_read,
573624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_request_error,
574624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
575431Sigor@sysoev.ru 
576624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_timeout,
577624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
578431Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
579431Sigor@sysoev.ru     .timer_autoreset = 1,
580431Sigor@sysoev.ru };
581431Sigor@sysoev.ru 
582431Sigor@sysoev.ru 
583431Sigor@sysoev.ru static void
584624Sigor@sysoev.ru nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data)
585431Sigor@sysoev.ru {
586431Sigor@sysoev.ru     size_t              size;
587431Sigor@sysoev.ru     nxt_conn_t          *c;
588431Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
589431Sigor@sysoev.ru     nxt_http_request_t  *r;
590431Sigor@sysoev.ru 
591431Sigor@sysoev.ru     c = obj;
592431Sigor@sysoev.ru     h1p = data;
593431Sigor@sysoev.ru 
594624Sigor@sysoev.ru     nxt_debug(task, "h1p conn body read");
595431Sigor@sysoev.ru 
596527Svbart@nginx.com     size = nxt_buf_mem_free_size(&c->read->mem);
597431Sigor@sysoev.ru 
598527Svbart@nginx.com     nxt_debug(task, "h1p body rest: %uz", size);
599431Sigor@sysoev.ru 
600527Svbart@nginx.com     if (size != 0) {
601431Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
602431Sigor@sysoev.ru 
603431Sigor@sysoev.ru     } else {
604527Svbart@nginx.com         r = h1p->request;
605459Sigor@sysoev.ru         c->read = NULL;
606431Sigor@sysoev.ru         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
607431Sigor@sysoev.ru                            r->state->ready_handler, task, r, NULL);
608431Sigor@sysoev.ru     }
609431Sigor@sysoev.ru }
610431Sigor@sysoev.ru 
611431Sigor@sysoev.ru 
612431Sigor@sysoev.ru static void
613431Sigor@sysoev.ru nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
614431Sigor@sysoev.ru {
615431Sigor@sysoev.ru     r->local = nxt_conn_local_addr(task, r->proto.h1->conn);
616431Sigor@sysoev.ru }
617431Sigor@sysoev.ru 
618431Sigor@sysoev.ru 
619431Sigor@sysoev.ru #define NXT_HTTP_LAST_SUCCESS                                                 \
620431Sigor@sysoev.ru     (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
621431Sigor@sysoev.ru 
622431Sigor@sysoev.ru static const nxt_str_t  nxt_http_success[] = {
623431Sigor@sysoev.ru     nxt_string("HTTP/1.1 200 OK\r\n"),
624431Sigor@sysoev.ru     nxt_string("HTTP/1.1 201 Created\r\n"),
625431Sigor@sysoev.ru     nxt_string("HTTP/1.1 202 Accepted\r\n"),
626431Sigor@sysoev.ru     nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"),
627431Sigor@sysoev.ru     nxt_string("HTTP/1.1 204 No Content\r\n"),
628431Sigor@sysoev.ru     nxt_string("HTTP/1.1 205 Reset Content\r\n"),
629431Sigor@sysoev.ru     nxt_string("HTTP/1.1 206 Partial Content\r\n"),
630431Sigor@sysoev.ru };
631431Sigor@sysoev.ru 
632431Sigor@sysoev.ru 
633431Sigor@sysoev.ru #define NXT_HTTP_LAST_REDIRECTION                                             \
634431Sigor@sysoev.ru     (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1)
635431Sigor@sysoev.ru 
636431Sigor@sysoev.ru static const nxt_str_t  nxt_http_redirection[] = {
637431Sigor@sysoev.ru     nxt_string("HTTP/1.1 300 Multiple Choices\r\n"),
638431Sigor@sysoev.ru     nxt_string("HTTP/1.1 301 Moved Permanently\r\n"),
639431Sigor@sysoev.ru     nxt_string("HTTP/1.1 302 Found\r\n"),
640431Sigor@sysoev.ru     nxt_string("HTTP/1.1 303 See Other\r\n"),
641431Sigor@sysoev.ru     nxt_string("HTTP/1.1 304 Not Modified\r\n"),
642431Sigor@sysoev.ru };
643431Sigor@sysoev.ru 
644431Sigor@sysoev.ru 
645431Sigor@sysoev.ru #define NXT_HTTP_LAST_CLIENT_ERROR                                            \
646431Sigor@sysoev.ru     (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1)
647431Sigor@sysoev.ru 
648431Sigor@sysoev.ru static const nxt_str_t  nxt_http_client_error[] = {
649431Sigor@sysoev.ru     nxt_string("HTTP/1.1 400 Bad Request\r\n"),
650431Sigor@sysoev.ru     nxt_string("HTTP/1.1 401 Unauthorized\r\n"),
651431Sigor@sysoev.ru     nxt_string("HTTP/1.1 402 Payment Required\r\n"),
652431Sigor@sysoev.ru     nxt_string("HTTP/1.1 403 Forbidden\r\n"),
653431Sigor@sysoev.ru     nxt_string("HTTP/1.1 404 Not Found\r\n"),
654431Sigor@sysoev.ru     nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"),
655431Sigor@sysoev.ru     nxt_string("HTTP/1.1 406 Not Acceptable\r\n"),
656431Sigor@sysoev.ru     nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"),
657431Sigor@sysoev.ru     nxt_string("HTTP/1.1 408 Request Timeout\r\n"),
658431Sigor@sysoev.ru     nxt_string("HTTP/1.1 409 Conflict\r\n"),
659431Sigor@sysoev.ru     nxt_string("HTTP/1.1 410 Gone\r\n"),
660431Sigor@sysoev.ru     nxt_string("HTTP/1.1 411 Length Required\r\n"),
661431Sigor@sysoev.ru     nxt_string("HTTP/1.1 412 Precondition Failed\r\n"),
662431Sigor@sysoev.ru     nxt_string("HTTP/1.1 413 Payload Too Large\r\n"),
663431Sigor@sysoev.ru     nxt_string("HTTP/1.1 414 URI Too Long\r\n"),
664431Sigor@sysoev.ru     nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"),
665431Sigor@sysoev.ru     nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"),
666431Sigor@sysoev.ru     nxt_string("HTTP/1.1 417 Expectation Failed\r\n"),
667431Sigor@sysoev.ru     nxt_string("HTTP/1.1 418\r\n"),
668431Sigor@sysoev.ru     nxt_string("HTTP/1.1 419\r\n"),
669431Sigor@sysoev.ru     nxt_string("HTTP/1.1 420\r\n"),
670431Sigor@sysoev.ru     nxt_string("HTTP/1.1 421\r\n"),
671431Sigor@sysoev.ru     nxt_string("HTTP/1.1 422\r\n"),
672431Sigor@sysoev.ru     nxt_string("HTTP/1.1 423\r\n"),
673431Sigor@sysoev.ru     nxt_string("HTTP/1.1 424\r\n"),
674431Sigor@sysoev.ru     nxt_string("HTTP/1.1 425\r\n"),
675431Sigor@sysoev.ru     nxt_string("HTTP/1.1 426\r\n"),
676431Sigor@sysoev.ru     nxt_string("HTTP/1.1 427\r\n"),
677431Sigor@sysoev.ru     nxt_string("HTTP/1.1 428\r\n"),
678431Sigor@sysoev.ru     nxt_string("HTTP/1.1 429\r\n"),
679431Sigor@sysoev.ru     nxt_string("HTTP/1.1 430\r\n"),
680431Sigor@sysoev.ru     nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"),
681431Sigor@sysoev.ru };
682431Sigor@sysoev.ru 
683431Sigor@sysoev.ru 
684431Sigor@sysoev.ru #define NXT_HTTP_LAST_SERVER_ERROR                                            \
685431Sigor@sysoev.ru     (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1)
686431Sigor@sysoev.ru 
687431Sigor@sysoev.ru static const nxt_str_t  nxt_http_server_error[] = {
688431Sigor@sysoev.ru     nxt_string("HTTP/1.1 500 Internal Server Error\r\n"),
689431Sigor@sysoev.ru     nxt_string("HTTP/1.1 501 Not Implemented\r\n"),
690431Sigor@sysoev.ru     nxt_string("HTTP/1.1 502 Bad Gateway\r\n"),
691431Sigor@sysoev.ru     nxt_string("HTTP/1.1 503 Service Unavailable\r\n"),
692431Sigor@sysoev.ru     nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"),
693482Svbart@nginx.com     nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"),
694431Sigor@sysoev.ru };
695431Sigor@sysoev.ru 
696431Sigor@sysoev.ru 
697431Sigor@sysoev.ru #define UNKNOWN_STATUS_LENGTH  (sizeof("HTTP/1.1 65536\r\n") - 1)
698431Sigor@sysoev.ru 
699431Sigor@sysoev.ru static void
700431Sigor@sysoev.ru nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
701431Sigor@sysoev.ru {
702431Sigor@sysoev.ru     u_char              *p;
703431Sigor@sysoev.ru     size_t              size;
704431Sigor@sysoev.ru     nxt_buf_t           *header;
705431Sigor@sysoev.ru     nxt_str_t           unknown_status;
706431Sigor@sysoev.ru     nxt_int_t           conn;
707431Sigor@sysoev.ru     nxt_uint_t          n;
708431Sigor@sysoev.ru     nxt_bool_t          http11;
709431Sigor@sysoev.ru     nxt_conn_t          *c;
710431Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
711431Sigor@sysoev.ru     const nxt_str_t     *status;
712431Sigor@sysoev.ru     nxt_http_field_t    *field;
713431Sigor@sysoev.ru     nxt_event_engine_t  *engine;
714431Sigor@sysoev.ru     u_char              buf[UNKNOWN_STATUS_LENGTH];
715431Sigor@sysoev.ru 
716431Sigor@sysoev.ru     static const char   chunked[] = "Transfer-Encoding: chunked\r\n";
717431Sigor@sysoev.ru 
718431Sigor@sysoev.ru     static const nxt_str_t  connection[2] = {
719431Sigor@sysoev.ru         nxt_string("Connection: close\r\n"),
720431Sigor@sysoev.ru         nxt_string("Connection: keep-alive\r\n"),
721431Sigor@sysoev.ru     };
722431Sigor@sysoev.ru 
723431Sigor@sysoev.ru     nxt_debug(task, "h1p request header send");
724431Sigor@sysoev.ru 
725431Sigor@sysoev.ru     r->header_sent = 1;
726431Sigor@sysoev.ru     h1p = r->proto.h1;
727431Sigor@sysoev.ru     n = r->status;
728431Sigor@sysoev.ru 
729431Sigor@sysoev.ru     if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) {
730431Sigor@sysoev.ru         status = &nxt_http_success[n - NXT_HTTP_OK];
731431Sigor@sysoev.ru 
732431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_MULTIPLE_CHOICES
733431Sigor@sysoev.ru                && n <= NXT_HTTP_LAST_REDIRECTION)
734431Sigor@sysoev.ru     {
735431Sigor@sysoev.ru         status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES];
736431Sigor@sysoev.ru 
737431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) {
738431Sigor@sysoev.ru         status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST];
739431Sigor@sysoev.ru 
740431Sigor@sysoev.ru     } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR
741431Sigor@sysoev.ru                && n <= NXT_HTTP_LAST_SERVER_ERROR)
742431Sigor@sysoev.ru     {
743431Sigor@sysoev.ru         status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR];
744431Sigor@sysoev.ru 
745431Sigor@sysoev.ru     } else {
746431Sigor@sysoev.ru         p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH,
747431Sigor@sysoev.ru                         "HTTP/1.1 %03d\r\n", n);
748431Sigor@sysoev.ru 
749431Sigor@sysoev.ru         unknown_status.length = p - buf;
750431Sigor@sysoev.ru         unknown_status.start = buf;
751431Sigor@sysoev.ru         status = &unknown_status;
752431Sigor@sysoev.ru     }
753431Sigor@sysoev.ru 
754450Sigor@sysoev.ru     size = status->length;
755450Sigor@sysoev.ru     /* Trailing CRLF at the end of header. */
756450Sigor@sysoev.ru     size += sizeof("\r\n") - 1;
757431Sigor@sysoev.ru 
758481Svbart@nginx.com     http11 = (h1p->parser.version.s.minor != '0');
759431Sigor@sysoev.ru 
760431Sigor@sysoev.ru     if (r->resp.content_length == NULL || r->resp.content_length->skip) {
761431Sigor@sysoev.ru         if (http11) {
762431Sigor@sysoev.ru             h1p->chunked = 1;
763431Sigor@sysoev.ru             size += sizeof(chunked) - 1;
764450Sigor@sysoev.ru             /* Trailing CRLF will be added by the first chunk header. */
765450Sigor@sysoev.ru             size -= sizeof("\r\n") - 1;
766431Sigor@sysoev.ru 
767431Sigor@sysoev.ru         } else {
768431Sigor@sysoev.ru             h1p->keepalive = 0;
769431Sigor@sysoev.ru         }
770431Sigor@sysoev.ru     }
771431Sigor@sysoev.ru 
772431Sigor@sysoev.ru     conn = -1;
773431Sigor@sysoev.ru 
774431Sigor@sysoev.ru     if (http11 ^ h1p->keepalive) {
775431Sigor@sysoev.ru         conn = h1p->keepalive;
776431Sigor@sysoev.ru         size += connection[conn].length;
777431Sigor@sysoev.ru     }
778431Sigor@sysoev.ru 
779431Sigor@sysoev.ru     nxt_list_each(field, r->resp.fields) {
780431Sigor@sysoev.ru 
781431Sigor@sysoev.ru         if (!field->skip) {
782431Sigor@sysoev.ru             size += field->name_length + field->value_length;
783431Sigor@sysoev.ru             size += sizeof(": \r\n") - 1;
784431Sigor@sysoev.ru         }
785431Sigor@sysoev.ru 
786431Sigor@sysoev.ru     } nxt_list_loop;
787431Sigor@sysoev.ru 
788608Sigor@sysoev.ru     header = nxt_http_buf_mem(task, r, size);
789431Sigor@sysoev.ru     if (nxt_slow_path(header == NULL)) {
790608Sigor@sysoev.ru         nxt_h1p_request_error(task, r);
791431Sigor@sysoev.ru         return;
792431Sigor@sysoev.ru     }
793431Sigor@sysoev.ru 
794431Sigor@sysoev.ru     p = header->mem.free;
795431Sigor@sysoev.ru 
796431Sigor@sysoev.ru     p = nxt_cpymem(p, status->start, status->length);
797431Sigor@sysoev.ru 
798431Sigor@sysoev.ru     nxt_list_each(field, r->resp.fields) {
799431Sigor@sysoev.ru 
800431Sigor@sysoev.ru         if (!field->skip) {
801431Sigor@sysoev.ru             p = nxt_cpymem(p, field->name, field->name_length);
802431Sigor@sysoev.ru             *p++ = ':'; *p++ = ' ';
803431Sigor@sysoev.ru             p = nxt_cpymem(p, field->value, field->value_length);
804431Sigor@sysoev.ru             *p++ = '\r'; *p++ = '\n';
805431Sigor@sysoev.ru         }
806431Sigor@sysoev.ru 
807431Sigor@sysoev.ru     } nxt_list_loop;
808431Sigor@sysoev.ru 
809431Sigor@sysoev.ru     if (conn >= 0) {
810431Sigor@sysoev.ru         p = nxt_cpymem(p, connection[conn].start, connection[conn].length);
811431Sigor@sysoev.ru     }
812431Sigor@sysoev.ru 
813431Sigor@sysoev.ru     if (h1p->chunked) {
814431Sigor@sysoev.ru         p = nxt_cpymem(p, chunked, sizeof(chunked) - 1);
815450Sigor@sysoev.ru         /* Trailing CRLF will be added by the first chunk header. */
816431Sigor@sysoev.ru 
817431Sigor@sysoev.ru     } else {
818431Sigor@sysoev.ru         *p++ = '\r'; *p++ = '\n';
819431Sigor@sysoev.ru     }
820431Sigor@sysoev.ru 
821431Sigor@sysoev.ru     header->mem.free = p;
822431Sigor@sysoev.ru 
823630Svbart@nginx.com     h1p->header_size = nxt_buf_mem_used_size(&header->mem);
824630Svbart@nginx.com 
825431Sigor@sysoev.ru     c = h1p->conn;
826431Sigor@sysoev.ru 
827431Sigor@sysoev.ru     c->write = header;
828431Sigor@sysoev.ru     c->write_state = &nxt_h1p_send_state;
829431Sigor@sysoev.ru 
830431Sigor@sysoev.ru     engine = task->thread->engine;
831431Sigor@sysoev.ru 
832431Sigor@sysoev.ru     nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler,
833431Sigor@sysoev.ru                        task, r, NULL);
834431Sigor@sysoev.ru 
835431Sigor@sysoev.ru     nxt_conn_write(engine, c);
836431Sigor@sysoev.ru }
837431Sigor@sysoev.ru 
838431Sigor@sysoev.ru 
839431Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_send_state
840431Sigor@sysoev.ru     nxt_aligned(64) =
841431Sigor@sysoev.ru {
842624Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_request_sent,
843624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_request_error,
844431Sigor@sysoev.ru 
845626Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_request_send_timeout,
846624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
847431Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, send_timeout),
848431Sigor@sysoev.ru     .timer_autoreset = 1,
849431Sigor@sysoev.ru };
850431Sigor@sysoev.ru 
851431Sigor@sysoev.ru 
852431Sigor@sysoev.ru static void
853431Sigor@sysoev.ru nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
854431Sigor@sysoev.ru {
855431Sigor@sysoev.ru     nxt_conn_t  *c;
856431Sigor@sysoev.ru 
857431Sigor@sysoev.ru     nxt_debug(task, "h1p request send");
858431Sigor@sysoev.ru 
859431Sigor@sysoev.ru     c = r->proto.h1->conn;
860431Sigor@sysoev.ru 
861431Sigor@sysoev.ru     if (r->proto.h1->chunked) {
862431Sigor@sysoev.ru         out = nxt_h1p_chunk_create(task, r, out);
863431Sigor@sysoev.ru         if (nxt_slow_path(out == NULL)) {
864608Sigor@sysoev.ru             nxt_h1p_request_error(task, r);
865431Sigor@sysoev.ru             return;
866431Sigor@sysoev.ru         }
867431Sigor@sysoev.ru     }
868431Sigor@sysoev.ru 
869431Sigor@sysoev.ru     if (c->write == NULL) {
870431Sigor@sysoev.ru         c->write = out;
871431Sigor@sysoev.ru         c->write_state = &nxt_h1p_send_state;
872431Sigor@sysoev.ru 
873431Sigor@sysoev.ru         nxt_conn_write(task->thread->engine, c);
874431Sigor@sysoev.ru 
875431Sigor@sysoev.ru     } else {
876431Sigor@sysoev.ru         nxt_buf_chain_add(&c->write, out);
877431Sigor@sysoev.ru     }
878431Sigor@sysoev.ru }
879431Sigor@sysoev.ru 
880431Sigor@sysoev.ru 
881431Sigor@sysoev.ru static nxt_buf_t *
882431Sigor@sysoev.ru nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
883431Sigor@sysoev.ru {
884483Sigor@sysoev.ru     nxt_off_t          size;
885431Sigor@sysoev.ru     nxt_buf_t          *b, **prev, *header, *tail;
886431Sigor@sysoev.ru 
887431Sigor@sysoev.ru     const size_t       chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN;
888431Sigor@sysoev.ru     static const char  tail_chunk[] = "\r\n0\r\n\r\n";
889431Sigor@sysoev.ru 
890431Sigor@sysoev.ru     size = 0;
891431Sigor@sysoev.ru     prev = &out;
892431Sigor@sysoev.ru 
893431Sigor@sysoev.ru     for (b = out; b != NULL; b = b->next) {
894431Sigor@sysoev.ru 
895431Sigor@sysoev.ru         if (nxt_buf_is_last(b)) {
896608Sigor@sysoev.ru             tail = nxt_http_buf_mem(task, r, chunk_size);
897431Sigor@sysoev.ru             if (nxt_slow_path(tail == NULL)) {
898431Sigor@sysoev.ru                 return NULL;
899431Sigor@sysoev.ru             }
900431Sigor@sysoev.ru 
901431Sigor@sysoev.ru             *prev = tail;
902431Sigor@sysoev.ru             tail->next = b;
903431Sigor@sysoev.ru             /*
904431Sigor@sysoev.ru              * The tail_chunk size with trailing zero is 8 bytes, so
905431Sigor@sysoev.ru              * memcpy may be inlined with just single 8 byte move operation.
906431Sigor@sysoev.ru              */
907431Sigor@sysoev.ru             nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk));
908431Sigor@sysoev.ru             tail->mem.free += sizeof(tail_chunk) - 1;
909431Sigor@sysoev.ru 
910431Sigor@sysoev.ru             break;
911431Sigor@sysoev.ru         }
912431Sigor@sysoev.ru 
913431Sigor@sysoev.ru         size += nxt_buf_used_size(b);
914431Sigor@sysoev.ru         prev = &b->next;
915431Sigor@sysoev.ru     }
916431Sigor@sysoev.ru 
917431Sigor@sysoev.ru     if (size == 0) {
918431Sigor@sysoev.ru         return out;
919431Sigor@sysoev.ru     }
920431Sigor@sysoev.ru 
921608Sigor@sysoev.ru     header = nxt_http_buf_mem(task, r, chunk_size);
922431Sigor@sysoev.ru     if (nxt_slow_path(header == NULL)) {
923431Sigor@sysoev.ru         return NULL;
924431Sigor@sysoev.ru     }
925431Sigor@sysoev.ru 
926431Sigor@sysoev.ru     header->next = out;
927431Sigor@sysoev.ru     header->mem.free = nxt_sprintf(header->mem.free, header->mem.end,
928431Sigor@sysoev.ru                                    "\r\n%xO\r\n", size);
929431Sigor@sysoev.ru     return header;
930431Sigor@sysoev.ru }
931431Sigor@sysoev.ru 
932431Sigor@sysoev.ru 
933431Sigor@sysoev.ru static void
934624Sigor@sysoev.ru nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data)
935431Sigor@sysoev.ru {
936431Sigor@sysoev.ru     nxt_conn_t          *c;
937431Sigor@sysoev.ru     nxt_event_engine_t  *engine;
938431Sigor@sysoev.ru 
939431Sigor@sysoev.ru     c = obj;
940431Sigor@sysoev.ru 
941624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request sent");
942431Sigor@sysoev.ru 
943431Sigor@sysoev.ru     engine = task->thread->engine;
944431Sigor@sysoev.ru 
945592Sigor@sysoev.ru     c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
946592Sigor@sysoev.ru 
947431Sigor@sysoev.ru     if (c->write != NULL) {
948431Sigor@sysoev.ru         nxt_conn_write(engine, c);
949431Sigor@sysoev.ru     }
950431Sigor@sysoev.ru }
951431Sigor@sysoev.ru 
952431Sigor@sysoev.ru 
953630Svbart@nginx.com static nxt_off_t
954630Svbart@nginx.com nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto)
955630Svbart@nginx.com {
956630Svbart@nginx.com     nxt_off_t      sent;
957630Svbart@nginx.com     nxt_h1proto_t  *h1p;
958630Svbart@nginx.com 
959630Svbart@nginx.com     h1p = proto.h1;
960630Svbart@nginx.com 
961630Svbart@nginx.com     sent = h1p->conn->sent - h1p->header_size;
962630Svbart@nginx.com 
963630Svbart@nginx.com     return (sent > 0) ? sent : 0;
964630Svbart@nginx.com }
965630Svbart@nginx.com 
966630Svbart@nginx.com 
967431Sigor@sysoev.ru static void
968608Sigor@sysoev.ru nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
969608Sigor@sysoev.ru     nxt_buf_t *last)
970608Sigor@sysoev.ru {
971608Sigor@sysoev.ru     nxt_buf_t         *b;
972608Sigor@sysoev.ru     nxt_conn_t        *c;
973608Sigor@sysoev.ru     nxt_h1proto_t     *h1p;
974608Sigor@sysoev.ru     nxt_work_queue_t  *wq;
975608Sigor@sysoev.ru 
976608Sigor@sysoev.ru     nxt_debug(task, "h1p request discard");
977608Sigor@sysoev.ru 
978608Sigor@sysoev.ru     h1p = r->proto.h1;
979608Sigor@sysoev.ru     h1p->keepalive = 0;
980608Sigor@sysoev.ru 
981608Sigor@sysoev.ru     c = h1p->conn;
982608Sigor@sysoev.ru     b = c->write;
983608Sigor@sysoev.ru     c->write = NULL;
984608Sigor@sysoev.ru 
985608Sigor@sysoev.ru     wq = &task->thread->engine->fast_work_queue;
986608Sigor@sysoev.ru 
987608Sigor@sysoev.ru     nxt_sendbuf_drain(task, wq, b);
988608Sigor@sysoev.ru     nxt_sendbuf_drain(task, wq, last);
989608Sigor@sysoev.ru }
990608Sigor@sysoev.ru 
991608Sigor@sysoev.ru 
992608Sigor@sysoev.ru static void
993431Sigor@sysoev.ru nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto)
994431Sigor@sysoev.ru {
995431Sigor@sysoev.ru     nxt_conn_t     *c;
996431Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
997431Sigor@sysoev.ru 
998431Sigor@sysoev.ru     nxt_debug(task, "h1p request close");
999431Sigor@sysoev.ru 
1000431Sigor@sysoev.ru     h1p = proto.h1;
1001431Sigor@sysoev.ru     h1p->request = NULL;
1002431Sigor@sysoev.ru 
1003431Sigor@sysoev.ru     c = h1p->conn;
1004431Sigor@sysoev.ru 
1005431Sigor@sysoev.ru     if (h1p->keepalive) {
1006431Sigor@sysoev.ru         nxt_h1p_keepalive(task, h1p, c);
1007431Sigor@sysoev.ru 
1008431Sigor@sysoev.ru     } else {
1009431Sigor@sysoev.ru         nxt_h1p_close(task, c);
1010431Sigor@sysoev.ru     }
1011431Sigor@sysoev.ru }
1012431Sigor@sysoev.ru 
1013431Sigor@sysoev.ru 
1014431Sigor@sysoev.ru static void
1015431Sigor@sysoev.ru nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c)
1016431Sigor@sysoev.ru {
1017431Sigor@sysoev.ru     size_t     size;
1018431Sigor@sysoev.ru     nxt_buf_t  *in, *b, *next;
1019431Sigor@sysoev.ru 
1020431Sigor@sysoev.ru     nxt_debug(task, "h1p keepalive");
1021431Sigor@sysoev.ru 
1022436Sigor@sysoev.ru     if (!c->tcp_nodelay) {
1023436Sigor@sysoev.ru         nxt_conn_tcp_nodelay_on(task, c);
1024436Sigor@sysoev.ru     }
1025436Sigor@sysoev.ru 
1026431Sigor@sysoev.ru     b = h1p->buffers;
1027431Sigor@sysoev.ru 
1028452Sigor@sysoev.ru     nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn));
1029431Sigor@sysoev.ru 
1030630Svbart@nginx.com     c->sent = 0;
1031630Svbart@nginx.com 
1032431Sigor@sysoev.ru     in = c->read;
1033431Sigor@sysoev.ru 
1034459Sigor@sysoev.ru     if (in == NULL) {
1035459Sigor@sysoev.ru         /* A request with large body. */
1036459Sigor@sysoev.ru         in = b;
1037459Sigor@sysoev.ru         c->read = in;
1038459Sigor@sysoev.ru 
1039459Sigor@sysoev.ru         b = in->next;
1040459Sigor@sysoev.ru         in->next = NULL;
1041459Sigor@sysoev.ru     }
1042459Sigor@sysoev.ru 
1043459Sigor@sysoev.ru     while (b != NULL) {
1044459Sigor@sysoev.ru         next = b->next;
1045459Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, b);
1046459Sigor@sysoev.ru         b = next;
1047459Sigor@sysoev.ru     }
1048459Sigor@sysoev.ru 
1049431Sigor@sysoev.ru     size = nxt_buf_mem_used_size(&in->mem);
1050431Sigor@sysoev.ru 
1051431Sigor@sysoev.ru     if (size == 0) {
1052629Sigor@sysoev.ru         nxt_mp_free(c->mem_pool, in);
1053431Sigor@sysoev.ru 
1054629Sigor@sysoev.ru         c->read = NULL;
1055628Sigor@sysoev.ru         c->read_state = &nxt_h1p_keepalive_state;
1056431Sigor@sysoev.ru 
1057628Sigor@sysoev.ru         nxt_conn_read(task->thread->engine, c);
1058431Sigor@sysoev.ru 
1059431Sigor@sysoev.ru     } else {
1060431Sigor@sysoev.ru         nxt_debug(task, "h1p pipelining");
1061431Sigor@sysoev.ru 
1062431Sigor@sysoev.ru         nxt_memmove(in->mem.start, in->mem.pos, size);
1063431Sigor@sysoev.ru 
1064431Sigor@sysoev.ru         in->mem.pos = in->mem.start;
1065431Sigor@sysoev.ru         in->mem.free = in->mem.start + size;
1066431Sigor@sysoev.ru 
1067627Svbart@nginx.com         nxt_h1p_conn_request_init(task, c, c->socket.data);
1068431Sigor@sysoev.ru     }
1069431Sigor@sysoev.ru }
1070431Sigor@sysoev.ru 
1071431Sigor@sysoev.ru 
1072624Sigor@sysoev.ru static const nxt_conn_state_t  nxt_h1p_keepalive_state
1073624Sigor@sysoev.ru     nxt_aligned(64) =
1074431Sigor@sysoev.ru {
1075628Sigor@sysoev.ru     .ready_handler = nxt_h1p_conn_request_init,
1076624Sigor@sysoev.ru     .close_handler = nxt_h1p_conn_error,
1077624Sigor@sysoev.ru     .error_handler = nxt_h1p_conn_error,
1078624Sigor@sysoev.ru 
1079629Sigor@sysoev.ru     .io_read_handler = nxt_h1p_conn_io_read_handler,
1080629Sigor@sysoev.ru 
1081624Sigor@sysoev.ru     .timer_handler = nxt_h1p_conn_timeout,
1082624Sigor@sysoev.ru     .timer_value = nxt_h1p_conn_timeout_value,
1083624Sigor@sysoev.ru     .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
1084*636Sigor@sysoev.ru     .timer_autoreset = 1,
1085624Sigor@sysoev.ru };
1086624Sigor@sysoev.ru 
1087624Sigor@sysoev.ru 
1088624Sigor@sysoev.ru static void
1089431Sigor@sysoev.ru nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data)
1090431Sigor@sysoev.ru {
1091624Sigor@sysoev.ru     nxt_conn_t  *c;
1092431Sigor@sysoev.ru 
1093431Sigor@sysoev.ru     c = obj;
1094431Sigor@sysoev.ru 
1095431Sigor@sysoev.ru     nxt_debug(task, "h1p conn error");
1096431Sigor@sysoev.ru 
1097624Sigor@sysoev.ru     nxt_h1p_close(task, c);
1098431Sigor@sysoev.ru }
1099431Sigor@sysoev.ru 
1100431Sigor@sysoev.ru 
1101431Sigor@sysoev.ru static void
1102431Sigor@sysoev.ru nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data)
1103431Sigor@sysoev.ru {
1104431Sigor@sysoev.ru     nxt_conn_t   *c;
1105431Sigor@sysoev.ru     nxt_timer_t  *timer;
1106431Sigor@sysoev.ru 
1107431Sigor@sysoev.ru     timer = obj;
1108431Sigor@sysoev.ru 
1109431Sigor@sysoev.ru     nxt_debug(task, "h1p conn timeout");
1110431Sigor@sysoev.ru 
1111431Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1112431Sigor@sysoev.ru 
1113624Sigor@sysoev.ru     nxt_h1p_close(task, c);
1114624Sigor@sysoev.ru }
1115624Sigor@sysoev.ru 
1116624Sigor@sysoev.ru 
1117624Sigor@sysoev.ru static void
1118624Sigor@sysoev.ru nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c)
1119624Sigor@sysoev.ru {
1120624Sigor@sysoev.ru     nxt_debug(task, "h1p close");
1121624Sigor@sysoev.ru 
1122624Sigor@sysoev.ru     c->socket.data = NULL;
1123624Sigor@sysoev.ru 
1124624Sigor@sysoev.ru     c->write_state = &nxt_router_conn_close_state;
1125624Sigor@sysoev.ru 
1126624Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
1127624Sigor@sysoev.ru }
1128624Sigor@sysoev.ru 
1129624Sigor@sysoev.ru 
1130624Sigor@sysoev.ru static void
1131624Sigor@sysoev.ru nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data)
1132624Sigor@sysoev.ru {
1133624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
1134624Sigor@sysoev.ru     nxt_http_request_t  *r;
1135624Sigor@sysoev.ru 
1136624Sigor@sysoev.ru     h1p = data;
1137624Sigor@sysoev.ru 
1138624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request error");
1139624Sigor@sysoev.ru 
1140624Sigor@sysoev.ru     r = h1p->request;
1141624Sigor@sysoev.ru 
1142624Sigor@sysoev.ru     if (r->fields == NULL) {
1143624Sigor@sysoev.ru         (void) nxt_h1p_header_process(h1p, r);
1144624Sigor@sysoev.ru     }
1145624Sigor@sysoev.ru 
1146624Sigor@sysoev.ru     if (r->status == 0) {
1147624Sigor@sysoev.ru         r->status = NXT_HTTP_BAD_REQUEST;
1148624Sigor@sysoev.ru     }
1149624Sigor@sysoev.ru 
1150624Sigor@sysoev.ru     nxt_h1p_request_error(task, r);
1151624Sigor@sysoev.ru }
1152624Sigor@sysoev.ru 
1153624Sigor@sysoev.ru 
1154624Sigor@sysoev.ru static void
1155624Sigor@sysoev.ru nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data)
1156624Sigor@sysoev.ru {
1157624Sigor@sysoev.ru     nxt_conn_t          *c;
1158624Sigor@sysoev.ru     nxt_timer_t         *timer;
1159624Sigor@sysoev.ru     nxt_h1proto_t       *h1p;
1160624Sigor@sysoev.ru     nxt_http_request_t  *r;
1161624Sigor@sysoev.ru 
1162624Sigor@sysoev.ru     timer = obj;
1163624Sigor@sysoev.ru 
1164624Sigor@sysoev.ru     nxt_debug(task, "h1p conn request timeout");
1165624Sigor@sysoev.ru 
1166624Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1167626Sigor@sysoev.ru     /*
1168626Sigor@sysoev.ru      * Disable SO_LINGER off during socket closing
1169626Sigor@sysoev.ru      * to send "408 Request Timeout" error response.
1170626Sigor@sysoev.ru      */
1171626Sigor@sysoev.ru     c->socket.timedout = 0;
1172626Sigor@sysoev.ru 
1173624Sigor@sysoev.ru     h1p = c->socket.data;
1174624Sigor@sysoev.ru     r = h1p->request;
1175624Sigor@sysoev.ru 
1176624Sigor@sysoev.ru     if (r->fields == NULL) {
1177624Sigor@sysoev.ru         (void) nxt_h1p_header_process(h1p, r);
1178624Sigor@sysoev.ru     }
1179624Sigor@sysoev.ru 
1180626Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT);
1181626Sigor@sysoev.ru }
1182626Sigor@sysoev.ru 
1183624Sigor@sysoev.ru 
1184626Sigor@sysoev.ru static void
1185626Sigor@sysoev.ru nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data)
1186626Sigor@sysoev.ru {
1187626Sigor@sysoev.ru     nxt_conn_t     *c;
1188626Sigor@sysoev.ru     nxt_timer_t    *timer;
1189626Sigor@sysoev.ru     nxt_h1proto_t  *h1p;
1190626Sigor@sysoev.ru 
1191626Sigor@sysoev.ru     timer = obj;
1192626Sigor@sysoev.ru 
1193626Sigor@sysoev.ru     nxt_debug(task, "h1p conn request send timeout");
1194626Sigor@sysoev.ru 
1195626Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
1196626Sigor@sysoev.ru     h1p = c->socket.data;
1197626Sigor@sysoev.ru 
1198626Sigor@sysoev.ru     nxt_h1p_request_error(task, h1p->request);
1199624Sigor@sysoev.ru }
1200624Sigor@sysoev.ru 
1201624Sigor@sysoev.ru 
1202624Sigor@sysoev.ru nxt_inline void
1203624Sigor@sysoev.ru nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r)
1204624Sigor@sysoev.ru {
1205624Sigor@sysoev.ru     r->state->error_handler(task, r, r->proto.h1);
1206431Sigor@sysoev.ru }
1207431Sigor@sysoev.ru 
1208431Sigor@sysoev.ru 
1209431Sigor@sysoev.ru static nxt_msec_t
1210624Sigor@sysoev.ru nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
1211431Sigor@sysoev.ru {
1212431Sigor@sysoev.ru     nxt_socket_conf_joint_t  *joint;
1213431Sigor@sysoev.ru 
1214431Sigor@sysoev.ru     joint = c->joint;
1215431Sigor@sysoev.ru 
1216431Sigor@sysoev.ru     return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
1217431Sigor@sysoev.ru }
1218