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) {