nxt_http_request.c (1007:7435036ed31e) nxt_http_request.c (1009:1c310945f81f)
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 nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
12static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
13static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data);
14static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
15 void *data);
16static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
17static void nxt_http_request_close_handler(nxt_task_t *task, void *obj,
18 void *data);
19
20static u_char *nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
21 size_t size, const char *format);
22
23
24static const nxt_http_request_state_t nxt_http_request_init_state;
25static const nxt_http_request_state_t nxt_http_request_body_state;
26
27
28nxt_time_string_t nxt_http_date_cache = {
29 (nxt_atomic_uint_t) -1,
30 nxt_http_date,
31 "%s, %02d %s %4d %02d:%02d:%02d GMT",
32 nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
33 NXT_THREAD_TIME_GMT,
34 NXT_THREAD_TIME_SEC,
35};
36
37
38nxt_int_t
39nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt)
40{
41 nxt_int_t ret;
42
43 ret = nxt_h1p_init(task, rt);
44
45 if (ret != NXT_OK) {
46 return ret;
47 }
48
49 return nxt_http_response_hash_init(task, rt);
50}
51
52
53nxt_int_t
54nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data)
55{
56 nxt_int_t ret;
57 nxt_str_t host;
58 nxt_http_request_t *r;
59
60 r = ctx;
61
62 if (nxt_slow_path(r->host.start != NULL)) {
63 return NXT_HTTP_BAD_REQUEST;
64 }
65
66 host.length = field->value_length;
67 host.start = field->value;
68
69 ret = nxt_http_validate_host(&host, r->mem_pool);
70
71 if (nxt_fast_path(ret == NXT_OK)) {
72 r->host = host;
73 }
74
75 return ret;
76}
77
78
79static nxt_int_t
80nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp)
81{
82 u_char *h, ch;
83 size_t i, dot_pos, host_length;
84 nxt_bool_t lowcase;
85
86 enum {
87 sw_usual,
88 sw_literal,
89 sw_rest
90 } state;
91
92 dot_pos = host->length;
93 host_length = host->length;
94
95 h = host->start;
96
97 lowcase = 0;
98 state = sw_usual;
99
100 for (i = 0; i < host->length; i++) {
101 ch = h[i];
102
103 if (ch > ']') {
104 /* Short path. */
105 continue;
106 }
107
108 switch (ch) {
109
110 case '.':
111 if (dot_pos == i - 1) {
112 return NXT_HTTP_BAD_REQUEST;
113 }
114
115 dot_pos = i;
116 break;
117
118 case ':':
119 if (state == sw_usual) {
120 host_length = i;
121 state = sw_rest;
122 }
123
124 break;
125
126 case '[':
127 if (i == 0) {
128 state = sw_literal;
129 }
130
131 break;
132
133 case ']':
134 if (state == sw_literal) {
135 host_length = i + 1;
136 state = sw_rest;
137 }
138
139 break;
140
141 case '/':
142 return NXT_HTTP_BAD_REQUEST;
143
144 default:
145 if (ch >= 'A' && ch <= 'Z') {
146 lowcase = 1;
147 }
148
149 break;
150 }
151 }
152
153 if (dot_pos == host_length - 1) {
154 host_length--;
155 }
156
157 host->length = host_length;
158
159 if (lowcase) {
160 host->start = nxt_mp_nget(mp, host_length);
161 if (nxt_slow_path(host->start == NULL)) {
162 return NXT_HTTP_INTERNAL_SERVER_ERROR;
163 }
164
165 nxt_memcpy_lowcase(host->start, h, host_length);
166 }
167
168 return NXT_OK;
169}
170
171
172nxt_int_t
173nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset)
174{
175 nxt_http_request_t *r;
176
177 r = ctx;
178
179 nxt_value_at(nxt_http_field_t *, r, offset) = field;
180
181 return NXT_OK;
182}
183
184
185nxt_int_t
186nxt_http_request_content_length(void *ctx, nxt_http_field_t *field,
187 uintptr_t data)
188{
189 nxt_off_t n;
190 nxt_http_request_t *r;
191
192 r = ctx;
193
194 if (nxt_fast_path(r->content_length == NULL)) {
195 r->content_length = field;
196
197 n = nxt_off_t_parse(field->value, field->value_length);
198
199 if (nxt_fast_path(n >= 0)) {
200 r->content_length_n = n;
201 return NXT_OK;
202 }
203 }
204
205 return NXT_HTTP_BAD_REQUEST;
206}
207
208
209nxt_http_request_t *
210nxt_http_request_create(nxt_task_t *task)
211{
212 nxt_mp_t *mp;
213 nxt_buf_t *last;
214 nxt_http_request_t *r;
215
216 mp = nxt_mp_create(1024, 128, 256, 32);
217 if (nxt_slow_path(mp == NULL)) {
218 return NULL;
219 }
220
221 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t));
222 if (nxt_slow_path(r == NULL)) {
223 goto fail;
224 }
225
226 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
227 if (nxt_slow_path(r->resp.fields == NULL)) {
228 goto fail;
229 }
230
231 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE);
232 if (nxt_slow_path(last == NULL)) {
233 goto fail;
234 }
235
236 nxt_buf_set_sync(last);
237 nxt_buf_set_last(last);
238 last->completion_handler = nxt_http_request_done;
239 last->parent = r;
240 r->last = last;
241
242 r->mem_pool = mp;
243 r->content_length_n = -1;
244 r->resp.content_length_n = -1;
245 r->state = &nxt_http_request_init_state;
246
247 return r;
248
249fail:
250
251 nxt_mp_release(mp);
252
253 return NULL;
254}
255
256
257static const nxt_http_request_state_t nxt_http_request_init_state
258 nxt_aligned(64) =
259{
260 .ready_handler = nxt_http_request_start,
261 .error_handler = nxt_http_request_close_handler,
262};
263
264
265static void
266nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
267{
268 nxt_http_request_t *r;
269
270 r = obj;
271
272 r->state = &nxt_http_request_body_state;
273
274 nxt_http_request_read_body(task, r);
275}
276
277
278static const nxt_http_request_state_t nxt_http_request_body_state
279 nxt_aligned(64) =
280{
281 .ready_handler = nxt_http_request_pass,
282 .error_handler = nxt_http_request_close_handler,
283};
284
285
286static void
287nxt_http_request_pass(nxt_task_t *task, void *obj, void *data)
288{
289 nxt_http_pass_t *pass;
290 nxt_http_request_t *r;
291
292 r = obj;
293
294 pass = r->conf->socket_conf->pass;
295
296 if (nxt_slow_path(pass == NULL)) {
297 goto fail;
298 }
299
300 for ( ;; ) {
301 nxt_debug(task, "http request route: %V", &pass->name);
302
303 pass = pass->handler(task, r, pass);
304 if (pass == NULL) {
305 break;
306 }
307
308 if (nxt_slow_path(r->pass_count++ == 255)) {
309 goto fail;
310 }
311 }
312
313 return;
314
315fail:
316
317 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
318}
319
320
321nxt_http_pass_t *
322nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r,
323 nxt_http_pass_t *pass)
324{
325 nxt_event_engine_t *engine;
326
327 nxt_debug(task, "http request application");
328
329 nxt_mp_retain(r->mem_pool);
330
331 engine = task->thread->engine;
332 r->timer.task = &engine->task;
333 r->timer.work_queue = &engine->fast_work_queue;
334 r->timer.log = engine->task.log;
335 r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
336
337 /*
338 * TODO: need an application flag to get local address
339 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
340 */
341 nxt_http_request_local_addr(task, r);
342
343 if (r->host.length != 0) {
344 r->server_name = r->host;
345
346 } else {
347 nxt_str_set(&r->server_name, "localhost");
348 }
349
350 nxt_router_process_http_request(task, r, pass->u.application);
351
352 return NULL;
353}
354
355
356void
357nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
358{
359 if (r->proto.any != NULL) {
360 nxt_http_proto_body_read[r->protocol](task, r);
361 }
362}
363
364
365void
366nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
367{
368 if (r->proto.any != NULL) {
369 nxt_http_proto_local_addr[r->protocol](task, r);
370 }
371}
372
373
374void
375nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
376{
377 u_char *p, *end;
378 nxt_http_field_t *server, *date, *content_length;
379
380 /*
381 * TODO: "Server", "Date", and "Content-Length" processing should be moved
382 * to the last header filter.
383 */
384
385 server = nxt_list_zero_add(r->resp.fields);
386 if (nxt_slow_path(server == NULL)) {
387 goto fail;
388 }
389
390 nxt_http_field_set(server, "Server", NXT_SERVER);
391
392 if (r->resp.date == NULL) {
393 date = nxt_list_zero_add(r->resp.fields);
394 if (nxt_slow_path(date == NULL)) {
395 goto fail;
396 }
397
398 nxt_http_field_name_set(date, "Date");
399
400 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size);
401 if (nxt_slow_path(p == NULL)) {
402 goto fail;
403 }
404
405 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p);
406
407 date->value = p;
408 date->value_length = nxt_http_date_cache.size;
409
410 r->resp.date = date;
411 }
412
413 if (r->resp.content_length_n != -1
414 && (r->resp.content_length == NULL || r->resp.content_length->skip))
415 {
416 content_length = nxt_list_zero_add(r->resp.fields);
417 if (nxt_slow_path(content_length == NULL)) {
418 goto fail;
419 }
420
421 nxt_http_field_name_set(content_length, "Content-Length");
422
423 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
424 if (nxt_slow_path(p == NULL)) {
425 goto fail;
426 }
427
428 content_length->value = p;
429 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n);
430 content_length->value_length = end - p;
431
432 r->resp.content_length = content_length;
433 }
434
435 if (r->proto.any != NULL) {
436 nxt_http_proto_header_send[r->protocol](task, r);
437 }
438
439 return;
440
441fail:
442
443 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
444}
445
446
447void
448nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
449{
450 if (r->proto.any != NULL) {
451 nxt_http_proto_send[r->protocol](task, r, out);
452 }
453}
454
455
456nxt_buf_t *
457nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size)
458{
459 nxt_buf_t *b;
460
461 b = nxt_buf_mem_alloc(r->mem_pool, size, 0);
462 if (nxt_fast_path(b != NULL)) {
463 b->completion_handler = nxt_http_request_mem_buf_completion;
464 b->parent = r;
465 nxt_mp_retain(r->mem_pool);
466
467 } else {
468 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
469 }
470
471 return b;
472}
473
474
475static void
476nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data)
477{
478 nxt_buf_t *b;
479 nxt_http_request_t *r;
480
481 b = obj;
482 r = data;
483
484 nxt_mp_free(r->mem_pool, b);
485
486 nxt_mp_release(r->mem_pool);
487}
488
489
490nxt_buf_t *
491nxt_http_buf_last(nxt_http_request_t *r)
492{
493 nxt_buf_t *last;
494
495 last = r->last;
496 r->last = NULL;
497
498 return last;
499}
500
501
502static void
503nxt_http_request_done(nxt_task_t *task, void *obj, void *data)
504{
505 nxt_http_request_t *r;
506
507 r = data;
508
509 nxt_debug(task, "http request done");
510
511 nxt_http_request_close_handler(task, r, r->proto.any);
512}
513
514
515void
516nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
517{
518 nxt_http_proto_t proto;
519 nxt_http_request_t *r;
520
521 r = obj;
522 proto.any = data;
523
524 nxt_debug(task, "http request error handler");
525
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 nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
12static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
13static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data);
14static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
15 void *data);
16static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
17static void nxt_http_request_close_handler(nxt_task_t *task, void *obj,
18 void *data);
19
20static u_char *nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
21 size_t size, const char *format);
22
23
24static const nxt_http_request_state_t nxt_http_request_init_state;
25static const nxt_http_request_state_t nxt_http_request_body_state;
26
27
28nxt_time_string_t nxt_http_date_cache = {
29 (nxt_atomic_uint_t) -1,
30 nxt_http_date,
31 "%s, %02d %s %4d %02d:%02d:%02d GMT",
32 nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
33 NXT_THREAD_TIME_GMT,
34 NXT_THREAD_TIME_SEC,
35};
36
37
38nxt_int_t
39nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt)
40{
41 nxt_int_t ret;
42
43 ret = nxt_h1p_init(task, rt);
44
45 if (ret != NXT_OK) {
46 return ret;
47 }
48
49 return nxt_http_response_hash_init(task, rt);
50}
51
52
53nxt_int_t
54nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data)
55{
56 nxt_int_t ret;
57 nxt_str_t host;
58 nxt_http_request_t *r;
59
60 r = ctx;
61
62 if (nxt_slow_path(r->host.start != NULL)) {
63 return NXT_HTTP_BAD_REQUEST;
64 }
65
66 host.length = field->value_length;
67 host.start = field->value;
68
69 ret = nxt_http_validate_host(&host, r->mem_pool);
70
71 if (nxt_fast_path(ret == NXT_OK)) {
72 r->host = host;
73 }
74
75 return ret;
76}
77
78
79static nxt_int_t
80nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp)
81{
82 u_char *h, ch;
83 size_t i, dot_pos, host_length;
84 nxt_bool_t lowcase;
85
86 enum {
87 sw_usual,
88 sw_literal,
89 sw_rest
90 } state;
91
92 dot_pos = host->length;
93 host_length = host->length;
94
95 h = host->start;
96
97 lowcase = 0;
98 state = sw_usual;
99
100 for (i = 0; i < host->length; i++) {
101 ch = h[i];
102
103 if (ch > ']') {
104 /* Short path. */
105 continue;
106 }
107
108 switch (ch) {
109
110 case '.':
111 if (dot_pos == i - 1) {
112 return NXT_HTTP_BAD_REQUEST;
113 }
114
115 dot_pos = i;
116 break;
117
118 case ':':
119 if (state == sw_usual) {
120 host_length = i;
121 state = sw_rest;
122 }
123
124 break;
125
126 case '[':
127 if (i == 0) {
128 state = sw_literal;
129 }
130
131 break;
132
133 case ']':
134 if (state == sw_literal) {
135 host_length = i + 1;
136 state = sw_rest;
137 }
138
139 break;
140
141 case '/':
142 return NXT_HTTP_BAD_REQUEST;
143
144 default:
145 if (ch >= 'A' && ch <= 'Z') {
146 lowcase = 1;
147 }
148
149 break;
150 }
151 }
152
153 if (dot_pos == host_length - 1) {
154 host_length--;
155 }
156
157 host->length = host_length;
158
159 if (lowcase) {
160 host->start = nxt_mp_nget(mp, host_length);
161 if (nxt_slow_path(host->start == NULL)) {
162 return NXT_HTTP_INTERNAL_SERVER_ERROR;
163 }
164
165 nxt_memcpy_lowcase(host->start, h, host_length);
166 }
167
168 return NXT_OK;
169}
170
171
172nxt_int_t
173nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset)
174{
175 nxt_http_request_t *r;
176
177 r = ctx;
178
179 nxt_value_at(nxt_http_field_t *, r, offset) = field;
180
181 return NXT_OK;
182}
183
184
185nxt_int_t
186nxt_http_request_content_length(void *ctx, nxt_http_field_t *field,
187 uintptr_t data)
188{
189 nxt_off_t n;
190 nxt_http_request_t *r;
191
192 r = ctx;
193
194 if (nxt_fast_path(r->content_length == NULL)) {
195 r->content_length = field;
196
197 n = nxt_off_t_parse(field->value, field->value_length);
198
199 if (nxt_fast_path(n >= 0)) {
200 r->content_length_n = n;
201 return NXT_OK;
202 }
203 }
204
205 return NXT_HTTP_BAD_REQUEST;
206}
207
208
209nxt_http_request_t *
210nxt_http_request_create(nxt_task_t *task)
211{
212 nxt_mp_t *mp;
213 nxt_buf_t *last;
214 nxt_http_request_t *r;
215
216 mp = nxt_mp_create(1024, 128, 256, 32);
217 if (nxt_slow_path(mp == NULL)) {
218 return NULL;
219 }
220
221 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t));
222 if (nxt_slow_path(r == NULL)) {
223 goto fail;
224 }
225
226 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
227 if (nxt_slow_path(r->resp.fields == NULL)) {
228 goto fail;
229 }
230
231 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE);
232 if (nxt_slow_path(last == NULL)) {
233 goto fail;
234 }
235
236 nxt_buf_set_sync(last);
237 nxt_buf_set_last(last);
238 last->completion_handler = nxt_http_request_done;
239 last->parent = r;
240 r->last = last;
241
242 r->mem_pool = mp;
243 r->content_length_n = -1;
244 r->resp.content_length_n = -1;
245 r->state = &nxt_http_request_init_state;
246
247 return r;
248
249fail:
250
251 nxt_mp_release(mp);
252
253 return NULL;
254}
255
256
257static const nxt_http_request_state_t nxt_http_request_init_state
258 nxt_aligned(64) =
259{
260 .ready_handler = nxt_http_request_start,
261 .error_handler = nxt_http_request_close_handler,
262};
263
264
265static void
266nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
267{
268 nxt_http_request_t *r;
269
270 r = obj;
271
272 r->state = &nxt_http_request_body_state;
273
274 nxt_http_request_read_body(task, r);
275}
276
277
278static const nxt_http_request_state_t nxt_http_request_body_state
279 nxt_aligned(64) =
280{
281 .ready_handler = nxt_http_request_pass,
282 .error_handler = nxt_http_request_close_handler,
283};
284
285
286static void
287nxt_http_request_pass(nxt_task_t *task, void *obj, void *data)
288{
289 nxt_http_pass_t *pass;
290 nxt_http_request_t *r;
291
292 r = obj;
293
294 pass = r->conf->socket_conf->pass;
295
296 if (nxt_slow_path(pass == NULL)) {
297 goto fail;
298 }
299
300 for ( ;; ) {
301 nxt_debug(task, "http request route: %V", &pass->name);
302
303 pass = pass->handler(task, r, pass);
304 if (pass == NULL) {
305 break;
306 }
307
308 if (nxt_slow_path(r->pass_count++ == 255)) {
309 goto fail;
310 }
311 }
312
313 return;
314
315fail:
316
317 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
318}
319
320
321nxt_http_pass_t *
322nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r,
323 nxt_http_pass_t *pass)
324{
325 nxt_event_engine_t *engine;
326
327 nxt_debug(task, "http request application");
328
329 nxt_mp_retain(r->mem_pool);
330
331 engine = task->thread->engine;
332 r->timer.task = &engine->task;
333 r->timer.work_queue = &engine->fast_work_queue;
334 r->timer.log = engine->task.log;
335 r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
336
337 /*
338 * TODO: need an application flag to get local address
339 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
340 */
341 nxt_http_request_local_addr(task, r);
342
343 if (r->host.length != 0) {
344 r->server_name = r->host;
345
346 } else {
347 nxt_str_set(&r->server_name, "localhost");
348 }
349
350 nxt_router_process_http_request(task, r, pass->u.application);
351
352 return NULL;
353}
354
355
356void
357nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
358{
359 if (r->proto.any != NULL) {
360 nxt_http_proto_body_read[r->protocol](task, r);
361 }
362}
363
364
365void
366nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
367{
368 if (r->proto.any != NULL) {
369 nxt_http_proto_local_addr[r->protocol](task, r);
370 }
371}
372
373
374void
375nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r)
376{
377 u_char *p, *end;
378 nxt_http_field_t *server, *date, *content_length;
379
380 /*
381 * TODO: "Server", "Date", and "Content-Length" processing should be moved
382 * to the last header filter.
383 */
384
385 server = nxt_list_zero_add(r->resp.fields);
386 if (nxt_slow_path(server == NULL)) {
387 goto fail;
388 }
389
390 nxt_http_field_set(server, "Server", NXT_SERVER);
391
392 if (r->resp.date == NULL) {
393 date = nxt_list_zero_add(r->resp.fields);
394 if (nxt_slow_path(date == NULL)) {
395 goto fail;
396 }
397
398 nxt_http_field_name_set(date, "Date");
399
400 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size);
401 if (nxt_slow_path(p == NULL)) {
402 goto fail;
403 }
404
405 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p);
406
407 date->value = p;
408 date->value_length = nxt_http_date_cache.size;
409
410 r->resp.date = date;
411 }
412
413 if (r->resp.content_length_n != -1
414 && (r->resp.content_length == NULL || r->resp.content_length->skip))
415 {
416 content_length = nxt_list_zero_add(r->resp.fields);
417 if (nxt_slow_path(content_length == NULL)) {
418 goto fail;
419 }
420
421 nxt_http_field_name_set(content_length, "Content-Length");
422
423 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN);
424 if (nxt_slow_path(p == NULL)) {
425 goto fail;
426 }
427
428 content_length->value = p;
429 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n);
430 content_length->value_length = end - p;
431
432 r->resp.content_length = content_length;
433 }
434
435 if (r->proto.any != NULL) {
436 nxt_http_proto_header_send[r->protocol](task, r);
437 }
438
439 return;
440
441fail:
442
443 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
444}
445
446
447void
448nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
449{
450 if (r->proto.any != NULL) {
451 nxt_http_proto_send[r->protocol](task, r, out);
452 }
453}
454
455
456nxt_buf_t *
457nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size)
458{
459 nxt_buf_t *b;
460
461 b = nxt_buf_mem_alloc(r->mem_pool, size, 0);
462 if (nxt_fast_path(b != NULL)) {
463 b->completion_handler = nxt_http_request_mem_buf_completion;
464 b->parent = r;
465 nxt_mp_retain(r->mem_pool);
466
467 } else {
468 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
469 }
470
471 return b;
472}
473
474
475static void
476nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data)
477{
478 nxt_buf_t *b;
479 nxt_http_request_t *r;
480
481 b = obj;
482 r = data;
483
484 nxt_mp_free(r->mem_pool, b);
485
486 nxt_mp_release(r->mem_pool);
487}
488
489
490nxt_buf_t *
491nxt_http_buf_last(nxt_http_request_t *r)
492{
493 nxt_buf_t *last;
494
495 last = r->last;
496 r->last = NULL;
497
498 return last;
499}
500
501
502static void
503nxt_http_request_done(nxt_task_t *task, void *obj, void *data)
504{
505 nxt_http_request_t *r;
506
507 r = data;
508
509 nxt_debug(task, "http request done");
510
511 nxt_http_request_close_handler(task, r, r->proto.any);
512}
513
514
515void
516nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
517{
518 nxt_http_proto_t proto;
519 nxt_http_request_t *r;
520
521 r = obj;
522 proto.any = data;
523
524 nxt_debug(task, "http request error handler");
525
526 r->error = 1;
527
526 if (proto.any != NULL) {
527 nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r));
528 }
529}
530
531
532static void
533nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
534{
535 nxt_http_proto_t proto;
536 nxt_http_request_t *r;
537 nxt_http_proto_close_t handler;
538 nxt_socket_conf_joint_t *conf;
539 nxt_router_access_log_t *access_log;
540
541 r = obj;
542 proto.any = data;
543
544 nxt_debug(task, "http request close handler");
545
546 conf = r->conf;
547
548 if (!r->logged) {
549 r->logged = 1;
550
551 access_log = conf->socket_conf->router_conf->access_log;
552
553 if (access_log != NULL) {
554 access_log->handler(task, r, access_log);
555 }
556 }
557
558 handler = nxt_http_proto_close[r->protocol];
559
560 r->proto.any = NULL;
561 nxt_mp_release(r->mem_pool);
562
563 if (proto.any != NULL) {
564 handler(task, proto, conf);
565 }
566}
567
568
569static u_char *
570nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size,
571 const char *format)
572{
573 static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
574 "Sat" };
575
576 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
577 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
578
579 return nxt_sprintf(buf, buf + size, format,
580 week[tm->tm_wday], tm->tm_mday,
581 month[tm->tm_mon], tm->tm_year + 1900,
582 tm->tm_hour, tm->tm_min, tm->tm_sec);
583}
528 if (proto.any != NULL) {
529 nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r));
530 }
531}
532
533
534static void
535nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
536{
537 nxt_http_proto_t proto;
538 nxt_http_request_t *r;
539 nxt_http_proto_close_t handler;
540 nxt_socket_conf_joint_t *conf;
541 nxt_router_access_log_t *access_log;
542
543 r = obj;
544 proto.any = data;
545
546 nxt_debug(task, "http request close handler");
547
548 conf = r->conf;
549
550 if (!r->logged) {
551 r->logged = 1;
552
553 access_log = conf->socket_conf->router_conf->access_log;
554
555 if (access_log != NULL) {
556 access_log->handler(task, r, access_log);
557 }
558 }
559
560 handler = nxt_http_proto_close[r->protocol];
561
562 r->proto.any = NULL;
563 nxt_mp_release(r->mem_pool);
564
565 if (proto.any != NULL) {
566 handler(task, proto, conf);
567 }
568}
569
570
571static u_char *
572nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size,
573 const char *format)
574{
575 static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
576 "Sat" };
577
578 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
579 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
580
581 return nxt_sprintf(buf, buf + size, format,
582 week[tm->tm_wday], tm->tm_mday,
583 month[tm->tm_mon], tm->tm_year + 1900,
584 tm->tm_hour, tm->tm_min, tm->tm_sec);
585}