comparison src/http/ngx_http_request.c @ 142:cb77c084acdb

nginx-0.0.1-2003-10-09-11:00:45 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 09 Oct 2003 07:00:45 +0000
parents src/http/ngx_http_event.c@2a615b036870
children 5526213be452
comparison
equal deleted inserted replaced
141:656d468f4ead 142:cb77c084acdb
1
2 #include <ngx_config.h>
3 #include <ngx_core.h>
4 #include <ngx_event.h>
5 #include <ngx_http.h>
6
7
8 static void ngx_http_init_request(ngx_event_t *ev);
9 static void ngx_http_process_request_line(ngx_event_t *rev);
10 static void ngx_http_process_request_headers(ngx_event_t *rev);
11 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
12
13 static void ngx_http_writer(ngx_event_t *ev);
14
15 static void ngx_http_block_read(ngx_event_t *ev);
16 static void ngx_http_read_discarded_body_event(ngx_event_t *rev);
17 static int ngx_http_read_discarded_body(ngx_http_request_t *r);
18
19 static void ngx_http_set_keepalive(ngx_http_request_t *r);
20 static void ngx_http_keepalive_handler(ngx_event_t *ev);
21 static void ngx_http_set_lingering_close(ngx_http_request_t *r);
22 static void ngx_http_lingering_close_handler(ngx_event_t *ev);
23 static void ngx_http_empty_handler(ngx_event_t *wev);
24
25 static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err);
26 static size_t ngx_http_log_error(void *data, char *buf, size_t len);
27
28
29 /* NGX_HTTP_PARSE_ ... errors */
30
31 static char *header_errors[] = {
32 "client %s sent invalid method",
33 "client %s sent invalid request",
34 "client %s sent too long URI",
35 "client %s sent invalid method in HTTP/0.9 request",
36
37 "client %s sent invalid header, URL: %s",
38 "client %s sent too long header line, URL: %s",
39 "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s",
40 "client %s sent invalid \"Content-Length\" header, URL: %s"
41 };
42
43
44
45 static ngx_http_header_t headers_in[] = {
46 { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host) },
47 { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection) },
48 { ngx_string("If-Modified-Since"),
49 offsetof(ngx_http_headers_in_t, if_modified_since) },
50 { ngx_string("Content-Length"),
51 offsetof(ngx_http_headers_in_t, content_length) },
52 { ngx_string("Accept-Encoding"),
53 offsetof(ngx_http_headers_in_t, accept_encoding) },
54
55 { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) },
56 #if 0
57 { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range) },
58 #endif
59
60 { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) },
61
62 { ngx_null_string, 0 }
63 };
64
65
66 void ngx_http_init_connection(ngx_connection_t *c)
67 {
68 int event;
69 ngx_event_t *rev;
70 ngx_http_log_ctx_t *lctx;
71
72 c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len);
73 if (c->addr_text.data == NULL) {
74 ngx_http_close_connection(c);
75 return;
76 }
77
78 c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr,
79 c->addr_text.data,
80 c->listening->addr_text_max_len);
81 if (c->addr_text.len == 0) {
82 ngx_http_close_connection(c);
83 return;
84 }
85
86 lctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t));
87 if (lctx == NULL) {
88 ngx_http_close_connection(c);
89 return;
90 }
91
92 lctx->client = c->addr_text.data;
93 lctx->action = "reading client request line";
94 c->log->data = lctx;
95 c->log->handler = ngx_http_log_error;
96
97 rev = c->read;
98 rev->event_handler = ngx_http_init_request;
99
100 if (rev->ready) {
101 /* deferred accept */
102 ngx_http_init_request(rev);
103 return;
104 }
105
106 ngx_add_timer(rev, c->listening->post_accept_timeout);
107 rev->timer_set = 1;
108
109 if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
110 /* aio, iocp, epoll */
111 ngx_http_init_request(rev);
112 return;
113 }
114
115 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
116 /* kqueue */
117 event = NGX_CLEAR_EVENT;
118
119 } else {
120 /* select, poll, /dev/poll */
121 event = NGX_LEVEL_EVENT;
122 }
123
124 if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) {
125 ngx_http_close_connection(c);
126 }
127 }
128
129
130 static void ngx_http_init_request(ngx_event_t *rev)
131 {
132 int i;
133 socklen_t len;
134 struct sockaddr_in addr_in;
135 ngx_connection_t *c;
136 ngx_http_request_t *r;
137 ngx_http_in_port_t *in_port;
138 ngx_http_in_addr_t *in_addr;
139 ngx_http_server_name_t *server_name;
140 ngx_http_core_srv_conf_t *cscf;
141 ngx_http_core_loc_conf_t *clcf;
142
143 c = rev->data;
144
145 r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t));
146 if (r == NULL) {
147 ngx_http_close_connection(c);
148 return;
149 }
150
151 /* find the server configuration for the address:port */
152
153 /* AF_INET only */
154
155 in_port = c->servers;
156 in_addr = in_port->addrs.elts;
157
158 ngx_log_debug(rev->log, "IN: %08x" _ in_port);
159
160 r->port = in_port->port;
161 r->port_name = &in_port->port_name;
162
163 i = 0;
164
165 if (in_port->addrs.nelts > 1) {
166
167 /*
168 * there're the several addresses on this port and one of them
169 * is "*:port" so getsockname() is needed to determine
170 * the server address.
171 * AcceptEx() already gave this address.
172 */
173
174 #if (WIN32)
175 if (c->local_sockaddr) {
176 r->in_addr =
177 ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
178
179 } else {
180 #endif
181 len = sizeof(struct sockaddr_in);
182 if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
183 ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno,
184 "getsockname() failed");
185 ngx_http_close_connection(c);
186 return;
187 }
188 #if (WIN32)
189 }
190 #endif
191
192 r->in_addr = addr_in.sin_addr.s_addr;
193
194 /* the last in_port->addrs address is "*" */
195
196 for ( /* void */ ; i < in_port->addrs.nelts - 1; i++) {
197 if (in_addr[i].addr == r->in_addr) {
198 break;
199 }
200 }
201
202 } else {
203 r->in_addr = in_addr[0].addr;
204 }
205
206 r->virtual_names = &in_addr[i].names;
207
208 /* the default server configuration for the address:port */
209 cscf = in_addr[i].core_srv_conf;
210
211 r->main_conf = cscf->ctx->main_conf;
212 r->srv_conf = cscf->ctx->srv_conf;
213 r->loc_conf = cscf->ctx->loc_conf;
214
215 server_name = cscf->server_names.elts;
216 r->server_name = &server_name->name;
217
218 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
219 c->log->file = clcf->err_log->file;
220 c->log->log_level = clcf->err_log->log_level;
221
222 if (c->buffer == NULL) {
223 c->buffer = ngx_create_temp_hunk(c->pool,
224 cscf->client_header_buffer_size,
225 0, 0);
226 if (c->buffer == NULL) {
227 ngx_http_close_connection(c);
228 return;
229 }
230 }
231
232 r->pool = ngx_create_pool(cscf->request_pool_size, c->log);
233 if (r->pool == NULL) {
234 ngx_http_close_connection(c);
235 return;
236 }
237
238 r->headers_out.headers = ngx_create_table(r->pool, 10);
239 if (r->headers_out.headers == NULL) {
240 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
241 ngx_http_close_connection(c);
242 return;
243 }
244
245 r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
246 if (r->ctx == NULL) {
247 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
248 ngx_http_close_connection(c);
249 return;
250 }
251
252 c->sent = 0;
253 c->data = r;
254 r->connection = c;
255 r->pipeline = c->pipeline;
256 r->header_in = c->buffer;
257
258 r->file.fd = NGX_INVALID_FILE;
259
260 r->headers_in.content_length_n = -1;
261 r->headers_out.content_length = -1;
262 r->headers_out.last_modified_time = -1;
263
264 rev->event_handler = ngx_http_process_request_line;
265 ngx_http_process_request_line(rev);
266 }
267
268
269 static void ngx_http_process_request_line(ngx_event_t *rev)
270 {
271 int rc, offset;
272 ssize_t n;
273 ngx_connection_t *c;
274 ngx_http_request_t *r;
275 ngx_http_log_ctx_t *lctx;
276 ngx_http_core_srv_conf_t *cscf;
277
278 c = rev->data;
279 r = c->data;
280
281 ngx_log_debug(rev->log, "http process request line");
282
283 if (rev->timedout) {
284 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
285 ngx_http_close_connection(c);
286 return;
287 }
288
289 n = ngx_http_read_request_header(r);
290
291 if (n == NGX_AGAIN || n == NGX_ERROR) {
292 return;
293 }
294
295 rc = ngx_http_parse_request_line(r);
296
297 if (rc == NGX_OK) {
298
299 /* the request line has been parsed successfully */
300
301 /* STUB: we need to handle such URIs */
302 if (r->complex_uri || r->unusual_uri) {
303 r->request_line.len = r->request_end - r->request_start;
304 r->request_line.data = r->request_start;
305 r->request_line.data[r->request_line.len] = '\0';
306
307 ngx_http_header_parse_error(r, NGX_HTTP_PARSE_INVALID_REQUEST);
308 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
309 return;
310 }
311
312 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
313
314 if (r->http_version >= NGX_HTTP_VERSION_10
315 && cscf->large_client_header == 0
316 && r->header_in->pos == r->header_in->end)
317 {
318 /* no space for "\r\n" at the end of the header */
319
320 ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
321 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
322 return;
323 }
324
325 /* copy URI */
326
327 if (r->args_start) {
328 r->uri.len = r->args_start - 1 - r->uri_start;
329 } else {
330 r->uri.len = r->uri_end - r->uri_start;
331 }
332
333 r->uri.data = ngx_palloc(r->pool, r->uri.len + 1);
334 if (r->uri.data == NULL) {
335 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
336 ngx_http_close_connection(c);
337 return;
338 }
339
340 ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
341
342 #if 1 /* THINK: needed to log url on errors in proxy only ? */
343
344 /* copy unparsed URI */
345
346 r->unparsed_uri.len = r->uri_end - r->uri_start;
347 r->unparsed_uri.data = ngx_palloc(r->pool, r->unparsed_uri.len + 1);
348 if (r->unparsed_uri.data == NULL) {
349 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
350 ngx_http_close_connection(c);
351 return;
352 }
353
354 ngx_cpystrn(r->unparsed_uri.data, r->uri_start,
355 r->unparsed_uri.len + 1);
356
357 #endif
358
359 r->request_line.len = r->request_end - r->request_start;
360
361 /* if the large client headers are enabled then
362 we need to copy a request line */
363
364 if (cscf->large_client_header) {
365
366 r->request_line.data = ngx_palloc(r->pool, r->request_line.len + 1);
367 if (r->request_line.data == NULL) {
368 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
369 ngx_http_close_connection(c);
370 return;
371 }
372
373 ngx_cpystrn(r->request_line.data, r->request_start,
374 r->request_line.len + 1);
375
376 } else {
377 r->request_line.data = r->request_start;
378 r->request_line.data[r->request_line.len] = '\0';
379 }
380
381 /* copy URI extention if it exists */
382
383 if (r->uri_ext) {
384 if (r->args_start) {
385 r->exten.len = r->args_start - 1 - r->uri_ext;
386 } else {
387 r->exten.len = r->uri_end - r->uri_ext;
388 }
389
390 r->exten.data = ngx_palloc(r->pool, r->exten.len + 1);
391 if (r->exten.data == NULL) {
392 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
393 ngx_http_close_connection(c);
394 return;
395 }
396
397 ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
398 }
399
400 /* copy URI arguments if they exist */
401
402 if (r->args_start && r->uri_end > r->args_start) {
403 r->args.len = r->uri_end - r->args_start;
404
405 r->args.data = ngx_palloc(r->pool, r->args.len + 1);
406 if (r->args.data == NULL) {
407 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
408 ngx_http_close_connection(c);
409 return;
410 }
411
412 ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
413 }
414
415 #if 1 /* DEBUG */
416 if (r->exten.data == NULL) { r->exten.data = ""; }
417 if (r->args.data == NULL) { r->args.data = ""; }
418 ngx_log_debug(c->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
419 r->method _ r->http_version _
420 r->uri.data _ r->exten.data _ r->args.data);
421 if (r->exten.data[0] == '\0') { r->exten.data = NULL; }
422 if (r->args.data[0] == '\0') { r->args.data = NULL; }
423 #endif
424
425 if (r->http_version < NGX_HTTP_VERSION_10) {
426 rev->event_handler = ngx_http_block_read;
427 ngx_http_handler(r);
428 return;
429 }
430
431 lctx = c->log->data;
432 lctx->action = "reading client request headers";
433 lctx->url = r->unparsed_uri.data;
434 r->headers_in.headers = ngx_create_table(r->pool, 10);
435
436 if (cscf->large_client_header
437 && r->header_in->pos == r->header_in->last)
438 {
439 r->header_in->pos = r->header_in->last = r->header_in->start;
440 }
441
442 rev->event_handler = ngx_http_process_request_headers;
443 ngx_http_process_request_headers(rev);
444
445 return;
446
447 } else if (rc != NGX_AGAIN) {
448
449 /* there was error while a request line parsing */
450
451 ngx_http_header_parse_error(r, rc);
452 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
453
454 return;
455 }
456
457 /* NGX_AGAIN: a request line parsing is still not complete */
458
459 if (r->header_in->last == r->header_in->end) {
460
461 /* If it's a pipelined request and a request line is not complete
462 then we need to copy it to the start of the r->header_in hunk.
463 We need to copy it here only if the large client headers
464 are enabled otherwise a request line had been already copied
465 to the start of the r->header_in hunk in ngx_http_set_keepalive() */
466
467 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
468
469 if (cscf->large_client_header) {
470 offset = r->request_start - r->header_in->start;
471
472 if (offset == 0) {
473 ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
474 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
475
476 return;
477 }
478
479 ngx_memcpy(r->header_in->start, r->request_start,
480 r->header_in->last - r->request_start);
481
482 r->header_in->pos -= offset;
483 r->header_in->last -= offset;
484 r->request_start = r->header_in->start;
485 r->request_end -= offset;
486 r->uri_start -= offset;
487 r->uri_end -= offset;
488 if (r->uri_ext) {
489 r->uri_ext -= offset;
490 }
491 if (r->args_start) {
492 r->args_start -= offset;
493 }
494
495 } else {
496 ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
497 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
498 }
499 }
500
501 return;
502 }
503
504
505 static void ngx_http_process_request_headers(ngx_event_t *rev)
506 {
507 int rc, i, offset;
508 size_t len;
509 ssize_t n;
510 ngx_table_elt_t *h;
511 ngx_connection_t *c;
512 ngx_http_request_t *r;
513 ngx_http_server_name_t *name;
514 ngx_http_core_srv_conf_t *cscf;
515 ngx_http_core_loc_conf_t *clcf;
516
517 c = rev->data;
518 r = c->data;
519
520 ngx_log_debug(rev->log, "http process request header line");
521
522 if (rev->timedout) {
523 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
524 ngx_http_close_connection(c);
525 return;
526 }
527
528 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
529
530 rc = NGX_AGAIN;
531
532 for ( ;; ) {
533 if (rc == NGX_AGAIN) {
534 n = ngx_http_read_request_header(r);
535
536 if (n == NGX_AGAIN || n == NGX_ERROR) {
537 return;
538 }
539 }
540
541 rc = ngx_http_parse_header_line(r, r->header_in);
542
543 if (rc == NGX_OK) {
544
545 /* a header line has been parsed successfully */
546
547 h = ngx_push_table(r->headers_in.headers);
548 if (h == NULL) {
549 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
550 ngx_http_close_connection(c);
551 return;
552 }
553
554 h->key.len = r->header_name_end - r->header_name_start;
555 h->value.len = r->header_end - r->header_start;
556
557 /* if the large client headers are enabled then
558 we need to copy the header name and value */
559
560 if (cscf->large_client_header) {
561 h->key.data = ngx_palloc(r->pool,
562 h->key.len + 1 + h->value.len + 1);
563 if (h->key.data == NULL) {
564 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
565 ngx_http_close_connection(c);
566 return;
567 }
568
569 h->value.data = h->key.data + h->key.len + 1;
570 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
571 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
572
573 } else {
574 h->key.data = r->header_name_start;
575 h->key.data[h->key.len] = '\0';
576 h->value.data = r->header_start;
577 h->value.data[h->value.len] = '\0';
578 }
579
580 for (i = 0; headers_in[i].name.len != 0; i++) {
581 if (headers_in[i].name.len != h->key.len) {
582 continue;
583 }
584
585 if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) {
586 *((ngx_table_elt_t **)
587 ((char *) &r->headers_in + headers_in[i].offset)) = h;
588 }
589 }
590
591 ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
592 h->key.data _ h->value.data);
593
594 if (cscf->large_client_header
595 && r->header_in->pos == r->header_in->last)
596 {
597 r->header_in->pos = r->header_in->last = r->header_in->start;
598 }
599
600 continue;
601
602 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
603
604 /* a whole header has been parsed successfully */
605
606 ngx_log_debug(r->connection->log, "HTTP header done");
607
608 if (r->headers_in.host) {
609 for (len = 0; len < r->headers_in.host->value.len; len++) {
610 if (r->headers_in.host->value.data[len] == ':') {
611 break;
612 }
613 }
614 r->headers_in.host_name_len = len;
615
616 /* find the name based server configuration */
617
618 name = r->virtual_names->elts;
619 for (i = 0; i < r->virtual_names->nelts; i++) {
620 if (r->headers_in.host_name_len != name[i].name.len) {
621 continue;
622 }
623
624 if (ngx_strncasecmp(r->headers_in.host->value.data,
625 name[i].name.data,
626 r->headers_in.host_name_len) == 0)
627 {
628 r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
629 r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
630
631 clcf = ngx_http_get_module_loc_conf(r,
632 ngx_http_core_module);
633 c->log->file = clcf->err_log->file;
634 c->log->log_level = clcf->err_log->log_level;
635
636 break;
637 }
638 }
639
640 } else {
641 if (r->http_version > NGX_HTTP_VERSION_10) {
642 ngx_http_header_parse_error(r,
643 NGX_HTTP_PARSE_NO_HOST_HEADER);
644 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
645 return;
646 }
647 r->headers_in.host_name_len = 0;
648 }
649
650 if (r->headers_in.content_length) {
651 r->headers_in.content_length_n =
652 ngx_atoi(r->headers_in.content_length->value.data,
653 r->headers_in.content_length->value.len);
654 if (r->headers_in.content_length_n == NGX_ERROR) {
655 ngx_http_header_parse_error(r,
656 NGX_HTTP_PARSE_INVALID_CL_HEADER);
657 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
658 return;
659 }
660 }
661
662 rev->event_handler = ngx_http_block_read;
663 ngx_http_handler(r);
664 return;
665
666 } else if (rc != NGX_AGAIN) {
667
668 /* there was error while a header line parsing */
669
670 ngx_http_header_parse_error(r, rc);
671 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
672
673 return;
674 }
675
676 /* NGX_AGAIN: a header line parsing is still not complete */
677
678 if (r->header_in->last == r->header_in->end) {
679
680 /* if the large client headers are enabled then
681 we need to compact r->header_in hunk */
682
683 if (cscf->large_client_header) {
684 offset = r->header_name_start - r->header_in->start;
685
686 if (offset == 0) {
687 ngx_http_header_parse_error(r,
688 NGX_HTTP_PARSE_TOO_LONG_HEADER);
689 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
690 return;
691 }
692
693 ngx_memcpy(r->header_in->start, r->header_name_start,
694 r->header_in->last - r->header_name_start);
695
696 r->header_in->last -= offset;
697 r->header_in->pos -= offset;
698 r->header_name_start = r->header_in->start;
699 r->header_name_end -= offset;
700 r->header_start -= offset;
701 r->header_end -= offset;
702
703 } else {
704 ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER);
705 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
706 return;
707 }
708 }
709 }
710 }
711
712
713 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r)
714 {
715 int event;
716 ssize_t n;
717 ngx_event_t *rev;
718 ngx_http_core_srv_conf_t *cscf;
719
720 rev = r->connection->read;
721
722 n = r->header_in->last - r->header_in->pos;
723
724 if (n > 0) {
725 rev->ready = 0;
726 return n;
727 }
728
729 n = ngx_recv(r->connection, r->header_in->last,
730 r->header_in->end - r->header_in->last);
731
732 if (n == NGX_AGAIN) {
733 if (!r->header_timeout_set) {
734 if (rev->timer_set) {
735 ngx_del_timer(rev);
736 } else {
737 rev->timer_set = 1;
738 }
739
740 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
741
742 ngx_add_timer(rev, cscf->client_header_timeout);
743 r->header_timeout_set = 1;
744 }
745
746 if (!rev->active) {
747 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
748 /* kqueue */
749 event = NGX_CLEAR_EVENT;
750
751 } else {
752 /* select, poll, /dev/poll */
753 event = NGX_LEVEL_EVENT;
754 }
755
756 if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) {
757 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
758 ngx_http_close_connection(r->connection);
759 return NGX_ERROR;
760 }
761 }
762
763 return NGX_AGAIN;
764 }
765
766 if (n == 0) {
767 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
768 "client closed prematurely connection");
769 }
770
771 if (n == 0 || n == NGX_ERROR) {
772 ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
773 ngx_http_close_connection(r->connection);
774 return NGX_ERROR;
775 }
776
777 r->header_in->last += n;
778
779 return n;
780 }
781
782
783 void ngx_http_finalize_request(ngx_http_request_t *r, int error)
784 {
785 int rc;
786 ngx_event_t *rev, *wev;
787
788 if (r->main) {
789 return;
790 }
791
792 rc = error;
793
794 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
795
796 rev = r->connection->read;
797 if (rev->timer_set) {
798 ngx_del_timer(rev);
799 rev->timer_set = 0;
800 }
801
802 wev = r->connection->write;
803 if (wev->timer_set) {
804 ngx_del_timer(wev);
805 wev->timer_set = 0;
806 }
807
808 rc = ngx_http_special_response_handler(r, rc);
809
810 if (rc == NGX_AGAIN) {
811 return;
812 }
813
814 if (rc == NGX_ERROR) {
815 ngx_http_close_request(r, 0);
816 ngx_http_close_connection(r->connection);
817 return;
818 }
819
820 #if 1
821 return;
822 #endif
823
824 } else if (rc == NGX_ERROR) {
825 r->keepalive = 0;
826 r->lingering_close = 0;
827
828 } else {
829 if (ngx_http_send_last(r) == NGX_ERROR) {
830 ngx_http_close_request(r, 0);
831 ngx_http_close_connection(r->connection);
832 return;
833 }
834
835 if (rc == NGX_AGAIN) {
836 ngx_http_set_write_handler(r);
837 return;
838 }
839 }
840
841 rev = r->connection->read;
842 if (rev->timer_set) {
843 ngx_del_timer(rev);
844 rev->timer_set = 0;
845 }
846
847 wev = r->connection->write;
848 if (wev->timer_set) {
849 ngx_del_timer(wev);
850 wev->timer_set = 0;
851 }
852
853 if (r->keepalive != 0) {
854 ngx_http_set_keepalive(r);
855
856 } else if (r->lingering_close) {
857 ngx_http_set_lingering_close(r);
858
859 } else {
860 ngx_http_close_request(r, 0);
861 ngx_http_close_connection(r->connection);
862 }
863
864 return;
865 }
866
867
868 void ngx_http_set_write_handler(ngx_http_request_t *r)
869 {
870 int event;
871 ngx_event_t *wev;
872 ngx_http_core_loc_conf_t *clcf;
873
874 wev = r->connection->write;
875 wev->event_handler = ngx_http_writer;
876
877 if (wev->delayed && wev->ready) {
878 return;
879 }
880
881 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
882 ngx_http_core_module);
883 ngx_add_timer(wev, clcf->send_timeout);
884 wev->timer_set = 1;
885
886 if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
887 /* aio, iocp, epoll */
888 return;
889 }
890
891 #if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
892
893 if (ngx_event_flags & NGX_HAVE_LOWAT_EVENT) {
894 wev->lowat = clcf->send_lowat;
895 }
896
897 #endif
898
899 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
900 /* kqueue */
901 event = NGX_CLEAR_EVENT;
902
903 } else {
904 /* select, poll, /dev/poll */
905 event = NGX_LEVEL_EVENT;
906 }
907
908 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) == NGX_ERROR) {
909 ngx_http_close_request(r, 0);
910 ngx_http_close_connection(r->connection);
911 }
912
913 return;
914 }
915
916
917 static void ngx_http_writer(ngx_event_t *wev)
918 {
919 int rc;
920 ngx_event_t *rev;
921 ngx_connection_t *c;
922 ngx_http_request_t *r;
923 ngx_http_core_loc_conf_t *clcf;
924
925 c = wev->data;
926 r = c->data;
927
928 rc = ngx_http_output_filter(r, NULL);
929
930 ngx_log_debug(c->log, "writer output filter: %d" _ rc);
931
932 if (rc == NGX_AGAIN) {
933
934 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
935 ngx_http_core_module);
936 if (wev->timer_set) {
937 ngx_del_timer(wev);
938 } else {
939 wev->timer_set = 1;
940 }
941
942 ngx_add_timer(wev, clcf->send_timeout);
943
944 return;
945 }
946
947 if (rc == NGX_ERROR) {
948 ngx_http_close_request(r, 0);
949 ngx_http_close_connection(c);
950 return;
951 }
952
953 /* rc == NGX_OK */
954
955 ngx_log_debug(c->log, "http writer done");
956
957 rev = r->connection->read;
958 if (rev->timer_set) {
959 ngx_del_timer(rev);
960 rev->timer_set = 0;
961 }
962
963 if (wev->timer_set) {
964 ngx_del_timer(wev);
965 wev->timer_set = 0;
966 }
967
968 if (r->keepalive != 0) {
969 ngx_http_set_keepalive(r);
970
971 } else if (r->lingering_close) {
972 ngx_http_set_lingering_close(r);
973
974 } else {
975 ngx_http_close_request(r, 0);
976 ngx_http_close_connection(r->connection);
977 }
978
979 return;
980 }
981
982
983 static void ngx_http_block_read(ngx_event_t *rev)
984 {
985 ngx_connection_t *c;
986 ngx_http_request_t *r;
987
988 ngx_log_debug(rev->log, "http read blocked");
989
990 /* aio does not call this handler */
991
992 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
993
994 /* select, poll, /dev/poll */
995
996 rev->blocked = 1;
997
998 if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
999 c = (ngx_connection_t *) rev->data;
1000 r = (ngx_http_request_t *) c->data;
1001 ngx_http_close_request(r, 0);
1002 ngx_http_close_connection(c);
1003 }
1004 }
1005
1006 /* kqueue, epoll */
1007
1008 return;
1009 }
1010
1011
1012 int ngx_http_discard_body(ngx_http_request_t *r)
1013 {
1014 ssize_t size;
1015 ngx_event_t *rev;
1016
1017 rev = r->connection->read;
1018
1019 ngx_log_debug(rev->log, "set discard body");
1020
1021 if (rev->timer_set) {
1022 ngx_del_timer(rev);
1023 rev->timer_set = 0;
1024 }
1025
1026 if (r->headers_in.content_length_n > 0) {
1027
1028 size = r->header_in->last - r->header_in->pos;
1029
1030 if (size) {
1031 if (r->headers_in.content_length_n > size) {
1032 r->headers_in.content_length_n -= size;
1033
1034 } else {
1035 r->header_in->pos += r->headers_in.content_length_n;
1036 r->headers_in.content_length_n = 0;
1037 return NGX_OK;
1038 }
1039 }
1040
1041 rev->event_handler = ngx_http_read_discarded_body_event;
1042
1043 if (rev->blocked) {
1044 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
1045 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT)
1046 == NGX_ERROR) {
1047 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1048 }
1049 }
1050
1051 rev->blocked = 0;
1052 return ngx_http_read_discarded_body(r);
1053 }
1054 }
1055
1056 return NGX_OK;
1057 }
1058
1059
1060 static void ngx_http_read_discarded_body_event(ngx_event_t *rev)
1061 {
1062 int rc;
1063 ngx_connection_t *c;
1064 ngx_http_request_t *r;
1065
1066 c = rev->data;
1067 r = c->data;
1068
1069 rc = ngx_http_read_discarded_body(r);
1070
1071 if (rc != NGX_OK) {
1072 ngx_http_close_request(r, rc);
1073 ngx_http_close_connection(c);
1074 }
1075
1076 return;
1077 }
1078
1079
1080 static int ngx_http_read_discarded_body(ngx_http_request_t *r)
1081 {
1082 ssize_t size, n;
1083 ngx_http_core_loc_conf_t *clcf;
1084
1085 ngx_log_debug(r->connection->log, "http read discarded body");
1086
1087 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1088
1089 if (r->discarded_buffer == NULL) {
1090 r->discarded_buffer = ngx_palloc(r->pool, clcf->discarded_buffer_size);
1091 if (r->discarded_buffer == NULL) {
1092 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1093 }
1094 }
1095
1096 size = r->headers_in.content_length_n;
1097 if (size > clcf->discarded_buffer_size) {
1098 size = clcf->discarded_buffer_size;
1099 }
1100
1101 n = ngx_recv(r->connection, r->discarded_buffer, size);
1102 if (n == NGX_ERROR) {
1103 return NGX_HTTP_BAD_REQUEST;
1104 }
1105
1106 if (n == NGX_AGAIN) {
1107 return NGX_OK;
1108 }
1109
1110 r->headers_in.content_length_n -= n;
1111
1112 return NGX_OK;
1113 }
1114
1115
1116 static void ngx_http_set_keepalive(ngx_http_request_t *r)
1117 {
1118 int len, blocked;
1119 ngx_hunk_t *h;
1120 ngx_event_t *rev, *wev;
1121 ngx_connection_t *c;
1122 ngx_http_log_ctx_t *ctx;
1123 ngx_http_core_srv_conf_t *cscf;
1124 ngx_http_core_loc_conf_t *clcf;
1125
1126 c = r->connection;
1127 rev = c->read;
1128
1129 ngx_log_debug(c->log, "set http keepalive handler");
1130
1131 ctx = (ngx_http_log_ctx_t *) c->log->data;
1132 ctx->action = "closing request";
1133 ngx_http_close_request(r, 0);
1134
1135 if (rev->timer_set) {
1136 ngx_del_timer(rev);
1137 } else {
1138 rev->timer_set = 1;
1139 }
1140
1141 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1142
1143 ngx_add_timer(rev, clcf->keepalive_timeout);
1144
1145 if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
1146 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
1147 ngx_http_close_connection(c);
1148 return;
1149 }
1150
1151 blocked = 1;
1152 rev->blocked = 0;
1153
1154 } else {
1155 blocked = 0;
1156 }
1157
1158 h = c->buffer;
1159
1160 /* pipelined request */
1161 if (h->pos < h->last) {
1162
1163 /* We do not know here whether a pipelined request is complete
1164 so if the large client headers are not enabled
1165 we need to copy the data to the start of c->buffer.
1166 This copy should be rare because clients that support
1167 pipelined requests (Mozilla 1.x, Opera 6.x) are still rare */
1168
1169 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1170
1171 if (!cscf->large_client_header) {
1172 len = h->last - h->pos;
1173 ngx_memcpy(h->start, h->pos, len);
1174 h->pos = h->start;
1175 h->last = h->start + len;
1176 }
1177
1178 ngx_log_debug(c->log, "pipelined request");
1179
1180 c->pipeline = 1;
1181 ctx->action = "reading client pipelined request line";
1182 ngx_http_init_request(rev);
1183 return;
1184 }
1185
1186 c->pipeline = 0;
1187
1188 h->pos = h->last = h->start;
1189 rev->event_handler = ngx_http_keepalive_handler;
1190 wev = c->write;
1191
1192 if (wev->active) {
1193 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
1194 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1195 ngx_http_close_connection(c);
1196 return;
1197 }
1198
1199 } else if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) == 0) {
1200 wev->event_handler = ngx_http_empty_handler;
1201 }
1202 }
1203
1204 ctx->action = "keepalive";
1205
1206 if (c->tcp_nopush) {
1207 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1208 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1209 ngx_tcp_push_n " failed");
1210 ngx_http_close_connection(c);
1211 return;
1212 }
1213 c->tcp_nopush = 0;
1214 }
1215
1216 if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) {
1217 ngx_http_keepalive_handler(rev);
1218 }
1219 }
1220
1221
1222 static void ngx_http_keepalive_handler(ngx_event_t *rev)
1223 {
1224 ssize_t n;
1225 ngx_connection_t *c;
1226 ngx_http_log_ctx_t *lctx;
1227
1228 c = (ngx_connection_t *) rev->data;
1229
1230 ngx_log_debug(c->log, "http keepalive handler");
1231
1232 if (rev->timedout) {
1233 ngx_http_close_connection(c);
1234 return;
1235 }
1236
1237 /* MSIE closes a keepalive connection with RST flag
1238 so we ignore ECONNRESET here */
1239
1240 rev->ignore_econnreset = 1;
1241 ngx_set_socket_errno(0);
1242 n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
1243 rev->ignore_econnreset = 0;
1244
1245 if (n == NGX_AGAIN) {
1246 return;
1247 }
1248
1249 if (n == NGX_ERROR) {
1250 ngx_http_close_connection(c);
1251 return;
1252 }
1253
1254 lctx = (ngx_http_log_ctx_t *) rev->log->data;
1255 rev->log->handler = NULL;
1256
1257 if (n == 0) {
1258 ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno,
1259 "client %s closed keepalive connection", lctx->client);
1260 ngx_http_close_connection(c);
1261 return;
1262 }
1263
1264 c->buffer->last += n;
1265 rev->log->handler = ngx_http_log_error;
1266 lctx->action = "reading client request line";
1267
1268 ngx_http_init_request(rev);
1269 }
1270
1271
1272 static void ngx_http_set_lingering_close(ngx_http_request_t *r)
1273 {
1274 ngx_event_t *rev;
1275 ngx_connection_t *c;
1276 ngx_http_core_loc_conf_t *clcf;
1277
1278 c = r->connection;
1279 rev = c->read;
1280
1281 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1282
1283 r->lingering_time = ngx_time() + clcf->lingering_time / 1000;
1284 rev->event_handler = ngx_http_lingering_close_handler;
1285
1286 if (rev->timer_set) {
1287 ngx_del_timer(rev);
1288 } else {
1289 rev->timer_set = 1;
1290 }
1291
1292 ngx_add_timer(rev, clcf->lingering_timeout);
1293
1294 if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
1295 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
1296 ngx_http_close_request(r, 0);
1297 ngx_http_close_connection(c);
1298 return;
1299 }
1300 rev->blocked = 0;
1301 }
1302
1303 if (c->write->active) {
1304 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
1305 if (ngx_del_event(c->write, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1306 ngx_http_close_request(r, 0);
1307 ngx_http_close_connection(c);
1308 return;
1309 }
1310
1311 } else if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) == 0) {
1312 c->write->event_handler = ngx_http_empty_handler;
1313 }
1314 }
1315
1316 if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
1317 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1318 ngx_shutdown_socket_n " failed");
1319 ngx_http_close_request(r, 0);
1320 ngx_http_close_connection(c);
1321 return;
1322 }
1323
1324 if (rev->ready || (ngx_event_flags & NGX_HAVE_AIO_EVENT)) {
1325 ngx_http_lingering_close_handler(rev);
1326 }
1327 }
1328
1329
1330 static void ngx_http_lingering_close_handler(ngx_event_t *rev)
1331 {
1332 ssize_t n;
1333 ngx_msec_t timer;
1334 ngx_connection_t *c;
1335 ngx_http_request_t *r;
1336 ngx_http_core_loc_conf_t *clcf;
1337
1338 c = rev->data;
1339 r = c->data;
1340
1341 ngx_log_debug(c->log, "http lingering close handler");
1342
1343 if (rev->timedout) {
1344 ngx_http_close_request(r, 0);
1345 ngx_http_close_connection(c);
1346 return;
1347 }
1348
1349 timer = r->lingering_time - ngx_time();
1350 if (timer <= 0) {
1351 ngx_http_close_request(r, 0);
1352 ngx_http_close_connection(c);
1353 return;
1354 }
1355
1356 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1357
1358 if (r->discarded_buffer == NULL) {
1359
1360 /* TODO: r->header_in->start (if large headers are enabled)
1361 or the end of parsed header (otherwise)
1362 instead of r->header_in->last */
1363
1364 if (r->header_in->end - r->header_in->last
1365 >= clcf->discarded_buffer_size) {
1366 r->discarded_buffer = r->header_in->last;
1367
1368 } else {
1369 r->discarded_buffer = ngx_palloc(c->pool,
1370 clcf->discarded_buffer_size);
1371 if (r->discarded_buffer) {
1372 ngx_http_close_request(r, 0);
1373 ngx_http_close_connection(c);
1374 return;
1375 }
1376 }
1377 }
1378
1379 do {
1380 n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
1381
1382 ngx_log_debug(c->log, "lingering read: %d" _ n);
1383
1384 if (n == NGX_ERROR || n == 0) {
1385 ngx_http_close_request(r, 0);
1386 ngx_http_close_connection(c);
1387 return;
1388 }
1389
1390 } while (rev->ready);
1391
1392 timer *= 1000;
1393 if (timer > clcf->lingering_timeout) {
1394 timer = clcf->lingering_timeout;
1395 }
1396
1397 if (rev->timer_set) {
1398 ngx_del_timer(rev);
1399 } else {
1400 rev->timer_set = 1;
1401 }
1402 ngx_add_timer(rev, timer);
1403
1404 return;
1405 }
1406
1407
1408 static void ngx_http_empty_handler(ngx_event_t *wev)
1409 {
1410 ngx_log_debug(wev->log, "http empty handler");
1411
1412 return;
1413 }
1414
1415
1416 int ngx_http_send_last(ngx_http_request_t *r)
1417 {
1418 ngx_hunk_t *h;
1419
1420 ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
1421 h->type = NGX_HUNK_LAST;
1422
1423 return ngx_http_output_filter(r, h);
1424 }
1425
1426
1427 void ngx_http_close_request(ngx_http_request_t *r, int error)
1428 {
1429 ngx_http_log_ctx_t *ctx;
1430
1431 ngx_log_debug(r->connection->log, "close http request");
1432
1433 if (r->pool == NULL) {
1434 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1435 "http request already closed");
1436 return;
1437 }
1438
1439 if (error) {
1440 r->headers_out.status = error;
1441 }
1442
1443 ngx_http_log_handler(r);
1444
1445 if (r->file.fd != NGX_INVALID_FILE) {
1446 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
1447 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
1448 ngx_close_file_n " \"%s\" failed", r->file.name.data);
1449 }
1450 }
1451
1452 /* ctx->url was allocated from r->pool */
1453 ctx = (ngx_http_log_ctx_t *) r->connection->log->data;
1454 ctx->url = NULL;
1455
1456 ngx_destroy_pool(r->pool);
1457 }
1458
1459
1460 void ngx_http_close_connection(ngx_connection_t *c)
1461 {
1462 ngx_log_debug(c->log, "close connection: %d" _ c->fd);
1463
1464 if (c->pool == NULL) {
1465 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
1466 return;
1467 }
1468
1469 if (c->read->timer_set) {
1470 ngx_del_timer(c->read);
1471 c->read->timer_set = 0;
1472 }
1473
1474 if (c->write->timer_set) {
1475 ngx_del_timer(c->write);
1476 c->write->timer_set = 0;
1477 }
1478
1479 if (ngx_del_conn) {
1480 ngx_del_conn(c);
1481
1482 } else {
1483 if (c->read->active) {
1484 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
1485 }
1486
1487 if (c->write->active) {
1488 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
1489 }
1490 }
1491
1492 if (ngx_close_socket(c->fd) == -1) {
1493 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
1494 ngx_close_socket_n " failed");
1495 }
1496
1497 c->fd = -1;
1498
1499 ngx_destroy_pool(c->pool);
1500 }
1501
1502
1503 static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err)
1504 {
1505 ngx_http_log_ctx_t *ctx;
1506
1507 ctx = r->connection->log->data;
1508 r->connection->log->handler = NULL;
1509
1510 if (ctx->url) {
1511 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1512 header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
1513 ctx->client, ctx->url);
1514
1515 } else {
1516 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1517 header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
1518 ctx->client);
1519 }
1520
1521 r->connection->log->handler = ngx_http_log_error;
1522 }
1523
1524
1525 static size_t ngx_http_log_error(void *data, char *buf, size_t len)
1526 {
1527 ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
1528
1529 if (ctx->action && ctx->url) {
1530 return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
1531 ctx->action, ctx->client, ctx->url);
1532
1533 } else if (ctx->action == NULL && ctx->url) {
1534 return ngx_snprintf(buf, len, ", client: %s, URL: %s",
1535 ctx->client, ctx->url);
1536
1537 } else {
1538 return ngx_snprintf(buf, len, " while %s, client: %s",
1539 ctx->action, ctx->client);
1540 }
1541 }