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