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