Mercurial > hg > nginx
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 } |