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