Mercurial > hg > nginx
comparison src/http/ngx_http_request.c @ 5101:d346adac0462
Create request object only after the first byte was received.
Previously, we always created an object and logged 400 (Bad Request)
in access log if a client closed connection without sending any data.
Such a connection was counted as "reading".
Since it's common for modern browsers to behave like this, it's no
longer considered an error if a client closes connection without
sending any data, and such a connection will be counted as "waiting".
Now, we do not log 400 (Bad Request) and keep memory footprint as
small as possible.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Thu, 07 Mar 2013 17:21:50 +0000 |
parents | 63014d919fec |
children | f597c9be5c92 |
comparison
equal
deleted
inserted
replaced
5100:2f61ee18dbfd | 5101:d346adac0462 |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | 11 |
12 | 12 |
13 static void ngx_http_wait_request_handler(ngx_event_t *ev); | |
13 static void ngx_http_init_request(ngx_event_t *ev); | 14 static void ngx_http_init_request(ngx_event_t *ev); |
14 static void ngx_http_process_request_line(ngx_event_t *rev); | 15 static void ngx_http_process_request_line(ngx_event_t *rev); |
15 static void ngx_http_process_request_headers(ngx_event_t *rev); | 16 static void ngx_http_process_request_headers(ngx_event_t *rev); |
16 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); | 17 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); |
17 static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, | 18 static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, |
306 ctx->current_request = NULL; | 307 ctx->current_request = NULL; |
307 | 308 |
308 c->log->connection = c->number; | 309 c->log->connection = c->number; |
309 c->log->handler = ngx_http_log_error; | 310 c->log->handler = ngx_http_log_error; |
310 c->log->data = ctx; | 311 c->log->data = ctx; |
311 c->log->action = "reading client request line"; | 312 c->log->action = "waiting for request"; |
312 | 313 |
313 c->log_error = NGX_ERROR_INFO; | 314 c->log_error = NGX_ERROR_INFO; |
314 | 315 |
315 rev = c->read; | 316 rev = c->read; |
316 rev->handler = ngx_http_init_request; | 317 rev->handler = ngx_http_wait_request_handler; |
317 c->write->handler = ngx_http_empty_handler; | 318 c->write->handler = ngx_http_empty_handler; |
318 | 319 |
319 #if (NGX_HTTP_SSL) | 320 #if (NGX_HTTP_SSL) |
320 { | 321 { |
321 ngx_http_ssl_srv_conf_t *sscf; | 322 ngx_http_ssl_srv_conf_t *sscf; |
357 | 358 |
358 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | 359 if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
359 ngx_http_close_connection(c); | 360 ngx_http_close_connection(c); |
360 return; | 361 return; |
361 } | 362 } |
363 } | |
364 | |
365 | |
366 static void | |
367 ngx_http_wait_request_handler(ngx_event_t *rev) | |
368 { | |
369 size_t size; | |
370 ssize_t n; | |
371 ngx_buf_t *b; | |
372 ngx_connection_t *c; | |
373 ngx_http_connection_t *hc; | |
374 ngx_http_core_srv_conf_t *cscf; | |
375 | |
376 c = rev->data; | |
377 | |
378 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wait request handler"); | |
379 | |
380 if (rev->timedout) { | |
381 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
382 ngx_http_close_connection(c); | |
383 return; | |
384 } | |
385 | |
386 hc = c->data; | |
387 cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); | |
388 | |
389 size = cscf->client_header_buffer_size; | |
390 | |
391 b = c->buffer; | |
392 | |
393 if (b == NULL) { | |
394 b = ngx_create_temp_buf(c->pool, size); | |
395 if (b == NULL) { | |
396 ngx_http_close_connection(c); | |
397 return; | |
398 } | |
399 | |
400 c->buffer = b; | |
401 | |
402 } else if (b->start == NULL) { | |
403 | |
404 b->start = ngx_palloc(c->pool, size); | |
405 if (b->start == NULL) { | |
406 ngx_http_close_connection(c); | |
407 return; | |
408 } | |
409 | |
410 b->pos = b->start; | |
411 b->last = b->start; | |
412 b->end = b->last + size; | |
413 } | |
414 | |
415 n = c->recv(c, b->last, size); | |
416 | |
417 if (n == NGX_AGAIN) { | |
418 | |
419 if (!rev->timer_set) { | |
420 ngx_add_timer(rev, c->listening->post_accept_timeout); | |
421 } | |
422 | |
423 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | |
424 ngx_http_close_connection(c); | |
425 return; | |
426 } | |
427 | |
428 /* | |
429 * We are trying to not hold c->buffer's memory for an idle connection. | |
430 */ | |
431 | |
432 if (ngx_pfree(c->pool, b->start) == NGX_OK) { | |
433 b->start = NULL; | |
434 } | |
435 | |
436 return; | |
437 } | |
438 | |
439 if (n == NGX_ERROR) { | |
440 ngx_http_close_connection(c); | |
441 return; | |
442 } | |
443 | |
444 if (n == 0) { | |
445 ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno, | |
446 "client closed connection"); | |
447 ngx_http_close_connection(c); | |
448 return; | |
449 } | |
450 | |
451 b->last += n; | |
452 | |
453 c->log->action = "reading client request line"; | |
454 | |
455 ngx_http_init_request(rev); | |
362 } | 456 } |
363 | 457 |
364 | 458 |
365 static void | 459 static void |
366 ngx_http_init_request(ngx_event_t *rev) | 460 ngx_http_init_request(ngx_event_t *rev) |
375 ngx_http_core_loc_conf_t *clcf; | 469 ngx_http_core_loc_conf_t *clcf; |
376 ngx_http_core_main_conf_t *cmcf; | 470 ngx_http_core_main_conf_t *cmcf; |
377 | 471 |
378 c = rev->data; | 472 c = rev->data; |
379 | 473 |
380 if (rev->timedout) { | |
381 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); | |
382 | |
383 ngx_http_close_connection(c); | |
384 return; | |
385 } | |
386 | |
387 c->requests++; | 474 c->requests++; |
388 | 475 |
389 hc = c->data; | 476 hc = c->data; |
390 | 477 |
391 cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); | 478 cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); |
422 r->read_event_handler = ngx_http_block_reading; | 509 r->read_event_handler = ngx_http_block_reading; |
423 | 510 |
424 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 511 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
425 | 512 |
426 ngx_http_set_connection_log(r->connection, clcf->error_log); | 513 ngx_http_set_connection_log(r->connection, clcf->error_log); |
427 | |
428 if (c->buffer == NULL) { | |
429 c->buffer = ngx_create_temp_buf(c->pool, | |
430 cscf->client_header_buffer_size); | |
431 if (c->buffer == NULL) { | |
432 ngx_destroy_pool(r->pool); | |
433 ngx_http_close_connection(c); | |
434 return; | |
435 } | |
436 } | |
437 | 514 |
438 r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; | 515 r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; |
439 | 516 |
440 if (ngx_list_init(&r->headers_out.headers, r->pool, 20, | 517 if (ngx_list_init(&r->headers_out.headers, r->pool, 20, |
441 sizeof(ngx_table_elt_t)) | 518 sizeof(ngx_table_elt_t)) |
590 return; | 667 return; |
591 } | 668 } |
592 | 669 |
593 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http"); | 670 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http"); |
594 | 671 |
595 c->log->action = "reading client request line"; | 672 c->log->action = "waiting for request"; |
596 | 673 |
597 rev->handler = ngx_http_init_request; | 674 rev->handler = ngx_http_wait_request_handler; |
598 ngx_http_init_request(rev); | 675 ngx_http_wait_request_handler(rev); |
599 | 676 |
600 return; | 677 return; |
601 } | 678 } |
602 | 679 |
603 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); | 680 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); |
618 * Opera and recent Mozilla send the alert. | 695 * Opera and recent Mozilla send the alert. |
619 */ | 696 */ |
620 | 697 |
621 c->ssl->no_wait_shutdown = 1; | 698 c->ssl->no_wait_shutdown = 1; |
622 | 699 |
623 c->log->action = "reading client request line"; | 700 c->log->action = "waiting for request"; |
624 | 701 |
625 c->read->handler = ngx_http_init_request; | 702 c->read->handler = ngx_http_wait_request_handler; |
626 /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; | 703 /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; |
627 | 704 |
628 ngx_http_init_request(c->read); | 705 ngx_http_wait_request_handler(c->read); |
629 | 706 |
630 return; | 707 return; |
631 } | 708 } |
632 | 709 |
633 if (c->read->timedout) { | 710 if (c->read->timedout) { |