# HG changeset patch # User Igor Sysoev # Date 1199739600 -10800 # Node ID c60beecc6ab5a860f03746d34605235f6d94db2e # Parent d792b2cd78fe2610764f4d4c024ab04701537043 nginx 0.5.35 *) Change: now the ngx_http_userid_module adds start time microseconds to the cookie field contains a pid value. *) Change: now the uname(2) is used on Linux instead of procfs. Thanks to Ilya Novikov. *) Feature: the "If-Range" request header line support. Thanks to Alexander V. Inyukhin. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error; bug appeared in 0.5.13. *) Bugfix: the STARTTLS in SMTP mode did not work. Thanks to Oleg Motienko. *) Bugfix: large_client_header_buffers did not freed before going to keep-alive state. Thanks to Olexander Shtepa. *) Bugfix: the "limit_rate" directive did not allow to use full throughput, even if limit value was very high. *) Bugfix: the $status variable was equal to 0 if a proxied server returned response in HTTP/0.9 version. *) Bugfix: if the "?" character was in a "error_page" directive, then it was escaped in a proxied request; bug appeared in 0.5.32. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,35 @@ +Changes with nginx 0.5.35 08 Jan 2008 + + *) Change: now the ngx_http_userid_module adds start time microseconds + to the cookie field contains a pid value. + + *) Change: now the uname(2) is used on Linux instead of procfs. + Thanks to Ilya Novikov. + + *) Feature: the "If-Range" request header line support. + Thanks to Alexander V. Inyukhin. + + *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" + error; bug appeared in 0.5.13. + + *) Bugfix: the STARTTLS in SMTP mode did not work. + Thanks to Oleg Motienko. + + *) Bugfix: large_client_header_buffers did not freed before going to + keep-alive state. + Thanks to Olexander Shtepa. + + *) Bugfix: the "limit_rate" directive did not allow to use full + throughput, even if limit value was very high. + + *) Bugfix: the $status variable was equal to 0 if a proxied server + returned response in HTTP/0.9 version. + + *) Bugfix: if the "?" character was in a "error_page" directive, then + it was escaped in a proxied request; bug appeared in 0.5.32. + + Changes with nginx 0.5.34 13 Dec 2007 *) Change: now the full request line instead of URI only is written to diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,36 @@ +Изменения в nginx 0.5.35 08.01.2008 + + *) Изменение: теперь модуль ngx_http_userid_module в поле куки с + номером процесса добавляет микросекунды на время старта. + + *) Изменение: теперь на Linux используется uname(2) вместо procfs. + Спасибо Илье Новикову. + + *) Добавление: поддержка строки "If-Range" в заголовке запроса. + Спасибо Александру Инюхину. + + *) Исправление: при использовании HTTPS запросы могли завершаться с + ошибкой "bad write retry"; ошибка появилась в 0.5.13. + + *) Исправление: STARTTLS в режиме SMTP не работал. + Спасибо Олегу Мотиенко. + + *) Исправление: large_client_header_buffers не освобождались перед + переходом в состояние keep-alive. + Спасибо Олександру Штепе. + + *) Исправление: директива limit_rate не позволяла передавать на полной + скорости, даже если был указан очень большой лимит. + + *) Исправление: если ответ проксированного сервера был версии HTTP/0.9, + то переменная $status была равна 0. + + *) Исправление: если в директиве error_page использовался символ "?", + то он экранировался при проксировании запроса; ошибка появилась в + 0.5.32. + + Изменения в nginx 0.5.34 13.12.2007 *) Изменение: в error_log теперь записывается полная строка запроса diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 Igor Sysoev + * Copyright (C) 2002-2008 Igor Sysoev * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.5.34" +#define NGINX_VERSION "0.5.35" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -111,10 +111,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) p += n * sizeof(ngx_slab_page_t); - /* STUB: possible overflow on 64-bit platform */ - pages = (ngx_uint_t) ((uint64_t) size * ngx_pagesize - / (ngx_pagesize + sizeof(ngx_slab_page_t)) - / ngx_pagesize); + pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); ngx_memzero(p, pages * sizeof(ngx_slab_page_t)); diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -22,6 +22,7 @@ static void ngx_ssl_read_handler(ngx_eve static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text); +static void ngx_ssl_clear_error(ngx_log_t *log); static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); @@ -186,8 +187,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]); } - SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_read_ahead(ssl->ctx, 1); return NGX_OK; @@ -404,6 +403,8 @@ ngx_ssl_handshake(ngx_connection_t *c) int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + n = SSL_do_handshake(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); @@ -602,6 +603,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char bytes = 0; + ngx_ssl_clear_error(c->log); + /* * SSL_read() may return data in parts, so try to read * until SSL_read() would return no data @@ -882,6 +885,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); n = SSL_write(c->ssl->connection, data, size); @@ -965,9 +970,8 @@ ngx_ssl_read_handler(ngx_event_t *rev) ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { - int n, sslerr, mode; - ngx_err_t err; - ngx_uint_t again; + int n, sslerr, mode; + ngx_err_t err; if (c->timedout) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; @@ -986,40 +990,34 @@ ngx_ssl_shutdown(ngx_connection_t *c) SSL_set_shutdown(c->ssl->connection, mode); - again = 0; + ngx_ssl_clear_error(c->log); + + n = SSL_shutdown(c->ssl->connection); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); + sslerr = 0; - for ( ;; ) { - n = SSL_shutdown(c->ssl->connection); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); - - if (n == 1 || (n == 0 && c->timedout)) { - SSL_free(c->ssl->connection); - c->ssl = NULL; - - return NGX_OK; - } - - if (n == 0) { - again = 1; - break; - } - - break; - } - - if (!again) { + /* SSL_shutdown() never return -1, on error it return 0 */ + + if (n != 1) { sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); } - if (again - || sslerr == SSL_ERROR_WANT_READ - || sslerr == SSL_ERROR_WANT_WRITE) + if (n == 1 + || sslerr == SSL_ERROR_ZERO_RETURN + || (sslerr == 0 && c->timedout)) { + SSL_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + + if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { c->read->handler = ngx_ssl_shutdown_handler; c->write->handler = ngx_ssl_shutdown_handler; @@ -1031,7 +1029,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) return NGX_ERROR; } - if (again || sslerr == SSL_ERROR_WANT_READ) { + if (sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 30000); } @@ -1112,6 +1110,15 @@ ngx_ssl_connection_error(ngx_connection_ } +static void +ngx_ssl_clear_error(ngx_log_t *log) +{ + if (ERR_peek_error()) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error"); + } +} + + void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) { diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -70,7 +70,7 @@ ngx_int_t ngx_http_not_modified_header_f * I think that the equality of the dates is correcter */ - if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) { + if (ims == r->headers_out.last_modified_time) { r->headers_out.status = NGX_HTTP_NOT_MODIFIED; r->headers_out.content_type.len = 0; ngx_http_clear_content_length(r); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -860,7 +860,8 @@ ngx_http_proxy_process_status_line(ngx_h #endif r->http_version = NGX_HTTP_VERSION_9; - p->status = NGX_HTTP_OK; + u->headers_in.status_n = NGX_HTTP_OK; + u->state->status = NGX_HTTP_OK; return NGX_OK; } diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -134,6 +134,7 @@ ngx_http_range_header_filter(ngx_http_re u_char *p; size_t len; off_t start, end; + time_t if_range; ngx_int_t rc; ngx_uint_t suffix, i; ngx_atomic_uint_t boundary; @@ -156,18 +157,21 @@ ngx_http_range_header_filter(ngx_http_re (u_char *) "bytes=", 6) != 0) { - r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.accept_ranges == NULL) { - return NGX_ERROR; - } + goto next_filter; + } + + if (r->headers_in.if_range && r->headers_out.last_modified_time != -1) { + + if_range = ngx_http_parse_time(r->headers_in.if_range->value.data, + r->headers_in.if_range->value.len); - r->headers_out.accept_ranges->hash = 1; - r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; - r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; - r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; - r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http ir:%d lm:%d", + if_range, r->headers_out.last_modified_time); - return ngx_http_next_header_filter(r); + if (if_range != r->headers_out.last_modified_time) { + goto next_filter; + } } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); @@ -461,6 +465,21 @@ ngx_http_range_header_filter(ngx_http_re } return ngx_http_next_header_filter(r); + +next_filter: + + r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.accept_ranges == NULL) { + return NGX_ERROR; + } + + r->headers_out.accept_ranges->hash = 1; + r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; + r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; + r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; + r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; + + return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -61,9 +61,11 @@ static char *ngx_http_userid_expires(ngx static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle); +static uint32_t start_value; static uint32_t sequencer_v1 = 1; static uint32_t sequencer_v2 = 0x03030302; @@ -173,7 +175,7 @@ ngx_module_t ngx_http_userid_filter_mod NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ - NULL, /* init process */ + ngx_http_userid_init_worker, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ @@ -319,7 +321,7 @@ ngx_http_userid_set_uid(ngx_http_request ctx->uid_set[0] = conf->service; } ctx->uid_set[1] = ngx_time(); - ctx->uid_set[2] = ngx_pid; + ctx->uid_set[2] = start_value; ctx->uid_set[3] = sequencer_v1; sequencer_v1 += 0x100; @@ -346,7 +348,7 @@ ngx_http_userid_set_uid(ngx_http_request } ctx->uid_set[1] = htonl(ngx_time()); - ctx->uid_set[2] = htonl(ngx_pid); + ctx->uid_set[2] = htonl(start_value); ctx->uid_set[3] = htonl(sequencer_v2); sequencer_v2 += 0x100; if (sequencer_v2 < 0x03030302) { @@ -706,3 +708,18 @@ ngx_http_userid_mark(ngx_conf_t *cf, ngx return NGX_CONF_OK; } + + +static ngx_int_t +ngx_http_userid_init_worker(ngx_cycle_t *cycle) +{ + struct timeval tp; + + ngx_gettimeofday(&tp); + + /* use the most significant usec part that fits to 16 bits */ + start_value = ((tp.tv_usec / 20) << 16) | ngx_pid; + + return NGX_OK; +} + diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.5.34'; +our $VERSION = '0.5.35'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1039,7 +1039,7 @@ ngx_http_parse_complex_uri(ngx_http_requ break; #endif case '/': - if (merge_slashes) { + if (!merge_slashes) { *u++ = ch; } break; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -97,6 +97,10 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), ngx_http_process_header_line }, + { ngx_string("If-Range"), + offsetof(ngx_http_headers_in_t, if_range), + ngx_http_process_unique_header_line }, + { ngx_string("Transfer-Encoding"), offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, @@ -2081,7 +2085,7 @@ ngx_http_set_keepalive(ngx_http_request_ if (hc->free) { for (i = 0; i < hc->nfree; i++) { - ngx_pfree(c->pool, hc->free[i]); + ngx_pfree(c->pool, hc->free[i]->start); hc->free[i] = NULL; } @@ -2093,7 +2097,7 @@ ngx_http_set_keepalive(ngx_http_request_ if (hc->busy) { for (i = 0; i < hc->nbusy; i++) { - ngx_pfree(c->pool, hc->busy[i]); + ngx_pfree(c->pool, hc->busy[i]->start); hc->busy[i] = NULL; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -168,6 +168,7 @@ typedef struct { ngx_table_elt_t *content_type; ngx_table_elt_t *range; + ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -10,14 +10,21 @@ #include -static u_char error_full_tail[] = +static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, + ngx_http_err_page_t *err_page); +static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_uint_t err); +static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r); + + +static u_char ngx_http_error_full_tail[] = "
" NGINX_VER "
" CRLF "" CRLF "" CRLF ; -static u_char error_tail[] = +static u_char ngx_http_error_tail[] = "
nginx
" CRLF "" CRLF "" CRLF @@ -42,7 +49,7 @@ static u_char ngx_http_msie_refresh_tail "\">" CRLF; -static char error_301_page[] = +static char ngx_http_error_301_page[] = "" CRLF "301 Moved Permanently" CRLF "" CRLF @@ -50,7 +57,7 @@ static char error_301_page[] = ; -static char error_302_page[] = +static char ngx_http_error_302_page[] = "" CRLF "302 Found" CRLF "" CRLF @@ -58,7 +65,7 @@ static char error_302_page[] = ; -static char error_400_page[] = +static char ngx_http_error_400_page[] = "" CRLF "400 Bad Request" CRLF "" CRLF @@ -66,7 +73,7 @@ static char error_400_page[] = ; -static char error_401_page[] = +static char ngx_http_error_401_page[] = "" CRLF "401 Authorization Required" CRLF "" CRLF @@ -74,7 +81,7 @@ static char error_401_page[] = ; -static char error_402_page[] = +static char ngx_http_error_402_page[] = "" CRLF "402 Payment Required" CRLF "" CRLF @@ -82,7 +89,7 @@ static char error_402_page[] = ; -static char error_403_page[] = +static char ngx_http_error_403_page[] = "" CRLF "403 Forbidden" CRLF "" CRLF @@ -90,7 +97,7 @@ static char error_403_page[] = ; -static char error_404_page[] = +static char ngx_http_error_404_page[] = "" CRLF "404 Not Found" CRLF "" CRLF @@ -98,7 +105,7 @@ static char error_404_page[] = ; -static char error_405_page[] = +static char ngx_http_error_405_page[] = "" CRLF "405 Not Allowed" CRLF "" CRLF @@ -106,7 +113,7 @@ static char error_405_page[] = ; -static char error_406_page[] = +static char ngx_http_error_406_page[] = "" CRLF "406 Not Acceptable" CRLF "" CRLF @@ -114,7 +121,7 @@ static char error_406_page[] = ; -static char error_408_page[] = +static char ngx_http_error_408_page[] = "" CRLF "408 Request Time-out" CRLF "" CRLF @@ -122,7 +129,7 @@ static char error_408_page[] = ; -static char error_409_page[] = +static char ngx_http_error_409_page[] = "" CRLF "409 Conflict" CRLF "" CRLF @@ -130,7 +137,7 @@ static char error_409_page[] = ; -static char error_410_page[] = +static char ngx_http_error_410_page[] = "" CRLF "410 Gone" CRLF "" CRLF @@ -138,7 +145,7 @@ static char error_410_page[] = ; -static char error_411_page[] = +static char ngx_http_error_411_page[] = "" CRLF "411 Length Required" CRLF "" CRLF @@ -146,7 +153,7 @@ static char error_411_page[] = ; -static char error_412_page[] = +static char ngx_http_error_412_page[] = "" CRLF "412 Precondition Failed" CRLF "" CRLF @@ -154,7 +161,7 @@ static char error_412_page[] = ; -static char error_413_page[] = +static char ngx_http_error_413_page[] = "" CRLF "413 Request Entity Too Large" CRLF "" CRLF @@ -162,7 +169,7 @@ static char error_413_page[] = ; -static char error_414_page[] = +static char ngx_http_error_414_page[] = "" CRLF "414 Request-URI Too Large" CRLF "" CRLF @@ -170,7 +177,7 @@ static char error_414_page[] = ; -static char error_415_page[] = +static char ngx_http_error_415_page[] = "" CRLF "415 Unsupported Media Type" CRLF "" CRLF @@ -178,7 +185,7 @@ static char error_415_page[] = ; -static char error_416_page[] = +static char ngx_http_error_416_page[] = "" CRLF "416 Requested Range Not Satisfiable" CRLF "" CRLF @@ -186,7 +193,7 @@ static char error_416_page[] = ; -static char error_495_page[] = +static char ngx_http_error_495_page[] = "" CRLF "400 The SSL certificate error" CRLF @@ -196,7 +203,7 @@ CRLF ; -static char error_496_page[] = +static char ngx_http_error_496_page[] = "" CRLF "400 No required SSL certificate was sent" CRLF @@ -206,7 +213,7 @@ CRLF ; -static char error_497_page[] = +static char ngx_http_error_497_page[] = "" CRLF "400 The plain HTTP request was sent to HTTPS port" CRLF @@ -216,7 +223,7 @@ CRLF ; -static char error_500_page[] = +static char ngx_http_error_500_page[] = "" CRLF "500 Internal Server Error" CRLF "" CRLF @@ -224,7 +231,7 @@ static char error_500_page[] = ; -static char error_501_page[] = +static char ngx_http_error_501_page[] = "" CRLF "501 Method Not Implemented" CRLF "" CRLF @@ -232,7 +239,7 @@ static char error_501_page[] = ; -static char error_502_page[] = +static char ngx_http_error_502_page[] = "" CRLF "502 Bad Gateway" CRLF "" CRLF @@ -240,7 +247,7 @@ static char error_502_page[] = ; -static char error_503_page[] = +static char ngx_http_error_503_page[] = "" CRLF "503 Service Temporarily Unavailable" CRLF "" CRLF @@ -248,7 +255,7 @@ static char error_503_page[] = ; -static char error_504_page[] = +static char ngx_http_error_504_page[] = "" CRLF "504 Gateway Time-out" CRLF "" CRLF @@ -256,7 +263,7 @@ static char error_504_page[] = ; -static char error_507_page[] = +static char ngx_http_error_507_page[] = "" CRLF "507 Insufficient Storage" CRLF "" CRLF @@ -264,53 +271,53 @@ static char error_507_page[] = ; -static ngx_str_t error_pages[] = { +static ngx_str_t ngx_http_error_pages[] = { - ngx_null_string, /* 201, 204 */ + ngx_null_string, /* 201, 204 */ #define NGX_HTTP_LEVEL_200 1 - /* ngx_null_string, */ /* 300 */ - ngx_string(error_301_page), - ngx_string(error_302_page), - ngx_null_string, /* 303 */ + /* ngx_null_string, */ /* 300 */ + ngx_string(ngx_http_error_301_page), + ngx_string(ngx_http_error_302_page), + ngx_null_string, /* 303 */ #define NGX_HTTP_LEVEL_300 3 - ngx_string(error_400_page), - ngx_string(error_401_page), - ngx_string(error_402_page), - ngx_string(error_403_page), - ngx_string(error_404_page), - ngx_string(error_405_page), - ngx_string(error_406_page), - ngx_null_string, /* 407 */ - ngx_string(error_408_page), - ngx_string(error_409_page), - ngx_string(error_410_page), - ngx_string(error_411_page), - ngx_string(error_412_page), - ngx_string(error_413_page), - ngx_string(error_414_page), - ngx_string(error_415_page), - ngx_string(error_416_page), + ngx_string(ngx_http_error_400_page), + ngx_string(ngx_http_error_401_page), + ngx_string(ngx_http_error_402_page), + ngx_string(ngx_http_error_403_page), + ngx_string(ngx_http_error_404_page), + ngx_string(ngx_http_error_405_page), + ngx_string(ngx_http_error_406_page), + ngx_null_string, /* 407 */ + ngx_string(ngx_http_error_408_page), + ngx_string(ngx_http_error_409_page), + ngx_string(ngx_http_error_410_page), + ngx_string(ngx_http_error_411_page), + ngx_string(ngx_http_error_412_page), + ngx_string(ngx_http_error_413_page), + ngx_string(ngx_http_error_414_page), + ngx_string(ngx_http_error_415_page), + ngx_string(ngx_http_error_416_page), #define NGX_HTTP_LEVEL_400 17 - ngx_string(error_495_page), /* 495, https certificate error */ - ngx_string(error_496_page), /* 496, https no certificate */ - ngx_string(error_497_page), /* 497, http to https */ - ngx_string(error_404_page), /* 498, invalid host name */ - ngx_null_string, /* 499, client had closed connection */ + ngx_string(ngx_http_error_495_page), /* 495, https certificate error */ + ngx_string(ngx_http_error_496_page), /* 496, https no certificate */ + ngx_string(ngx_http_error_497_page), /* 497, http to https */ + ngx_string(ngx_http_error_404_page), /* 498, canceled */ + ngx_null_string, /* 499, client has closed connection */ - ngx_string(error_500_page), - ngx_string(error_501_page), - ngx_string(error_502_page), - ngx_string(error_503_page), - ngx_string(error_504_page), - ngx_null_string, /* 505 */ - ngx_null_string, /* 506 */ - ngx_string(error_507_page) + ngx_string(ngx_http_error_500_page), + ngx_string(ngx_http_error_501_page), + ngx_string(ngx_http_error_502_page), + ngx_string(ngx_http_error_503_page), + ngx_string(ngx_http_error_504_page), + ngx_null_string, /* 505 */ + ngx_null_string, /* 506 */ + ngx_string(ngx_http_error_507_page) }; @@ -320,14 +327,8 @@ static ngx_str_t ngx_http_get_name = { ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) { - u_char *p; - size_t msie_refresh; - uintptr_t escape; ngx_int_t rc; - ngx_buf_t *b; - ngx_str_t *uri, *location; - ngx_uint_t i, n, err, msie_padding; - ngx_chain_t *out, *cl; + ngx_uint_t i, err; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; @@ -378,68 +379,20 @@ ngx_http_special_response_handler(ngx_ht err_page = clcf->error_pages->elts; for (i = 0; i < clcf->error_pages->nelts; i++) { - if (err_page[i].status == error) { - r->err_status = err_page[i].overwrite; - - r->method = NGX_HTTP_GET; - r->method_name = ngx_http_get_name; - - uri = &err_page[i].uri; - - if (err_page[i].uri_lengths) { - if (ngx_http_script_run(r, uri, - err_page[i].uri_lengths->elts, 0, - err_page[i].uri_values->elts) - == NULL) - { - return NGX_ERROR; - } - - if (r->zero_in_uri) { - for (n = 0; n < uri->len; n++) { - if (uri->data[n] == '\0') { - goto zero; - } - } - - r->zero_in_uri = 0; - } - - } else { - r->zero_in_uri = 0; - } - - zero: - - if (uri->data[0] == '/') { - return ngx_http_internal_redirect(r, uri, NULL); - } - - if (uri->data[0] == '@') { - return ngx_http_named_location(r, uri); - } - - r->headers_out.location = - ngx_list_push(&r->headers_out.headers); - - if (r->headers_out.location) { - error = NGX_HTTP_MOVED_TEMPORARILY; - - r->err_status = NGX_HTTP_MOVED_TEMPORARILY; - - r->headers_out.location->hash = 1; - r->headers_out.location->key.len = sizeof("Location") - 1; - r->headers_out.location->key.data = (u_char *) "Location"; - r->headers_out.location->value = *uri; - - } else { - return NGX_ERROR; - } + return ngx_http_send_error_page(r, &err_page[i]); } } } + if (clcf->msie_refresh + && r->headers_in.msie + && (error == NGX_HTTP_MOVED_PERMANENTLY + || error == NGX_HTTP_MOVED_TEMPORARILY)) + { + return ngx_http_send_refresh(r); + } + if (error == NGX_HTTP_CREATED) { /* 201 */ err = 0; @@ -468,30 +421,150 @@ ngx_http_special_response_handler(ngx_ht case NGX_HTTPS_CERT_ERROR: case NGX_HTTPS_NO_CERT: r->err_status = NGX_HTTP_BAD_REQUEST; - error = NGX_HTTP_BAD_REQUEST; break; } } + return ngx_http_send_special_response(r, clcf, err); +} + + +static ngx_int_t +ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) +{ + u_char ch, *p, *last; + ngx_str_t *uri, *args, u, a; + ngx_table_elt_t *location; + ngx_http_core_loc_conf_t *clcf; + + r->err_status = err_page->overwrite; + + r->method = NGX_HTTP_GET; + r->method_name = ngx_http_get_name; + + r->zero_in_uri = 0; + + args = NULL; + + if (err_page->uri_lengths) { + if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, + err_page->uri_values->elts) + == NULL) + { + return NGX_ERROR; + } + + p = u.data; + uri = &u; + + if (*p == '/') { + + last = p + uri->len; + + while (p < last) { + + ch = *p++; + + if (ch == '?') { + a.len = last - p; + a.data = p; + args = &a; + + u.len = p - 1 - u.data; + + while (p < last) { + if (*p++ == '\0') { + r->zero_in_uri = 1; + break; + } + } + + break; + } + + if (ch == '\0') { + r->zero_in_uri = 1; + continue; + } + } + } + + } else { + uri = &err_page->uri; + } + + if (uri->data[0] == '/') { + return ngx_http_internal_redirect(r, uri, args); + } + + if (uri->data[0] == '@') { + return ngx_http_named_location(r, uri); + } + + location = ngx_list_push(&r->headers_out.headers); + + if (location == NULL) { + return NGX_ERROR; + } + + r->err_status = NGX_HTTP_MOVED_TEMPORARILY; + + location->hash = 1; + location->key.len = sizeof("Location") - 1; + location->key.data = (u_char *) "Location"; + location->value = *uri; + + r->headers_out.location = location; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->msie_refresh && r->headers_in.msie) { + return ngx_http_send_refresh(r); + } + + return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY + - NGX_HTTP_MOVED_PERMANENTLY + + NGX_HTTP_LEVEL_200); +} + + +static ngx_int_t +ngx_http_send_special_response(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_uint_t err) +{ + u_char *tail; + size_t len; + ngx_int_t rc; + ngx_buf_t *b; + ngx_uint_t msie_padding; + ngx_chain_t out[3]; + + if (clcf->server_tokens) { + len = sizeof(ngx_http_error_full_tail) - 1; + tail = ngx_http_error_full_tail; + + } else { + len = sizeof(ngx_http_error_tail) - 1; + tail = ngx_http_error_tail; + } + msie_padding = 0; if (!r->zero_body) { - if (error_pages[err].len) { - r->headers_out.content_length_n = error_pages[err].len - + (clcf->server_tokens ? sizeof(error_full_tail) - 1: - sizeof(error_tail) - 1); - + if (ngx_http_error_pages[err].len) { + r->headers_out.content_length_n = ngx_http_error_pages[err].len + + len; if (clcf->msie_padding && r->headers_in.msie && r->http_version >= NGX_HTTP_VERSION_10 - && error >= NGX_HTTP_BAD_REQUEST - && error != NGX_HTTP_REQUEST_URI_TOO_LARGE) + && err >= NGX_HTTP_LEVEL_300) { r->headers_out.content_length_n += sizeof(ngx_http_msie_stub) - 1; msie_padding = 1; } + r->headers_out.content_type_len = sizeof("text/html") - 1; r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; @@ -509,31 +582,102 @@ ngx_http_special_response_handler(ngx_ht r->headers_out.content_length = NULL; } - if (clcf->msie_refresh - && r->headers_in.msie - && (error == NGX_HTTP_MOVED_PERMANENTLY - || error == NGX_HTTP_MOVED_TEMPORARILY)) - { + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || r->header_only) { + return rc; + } + + if (ngx_http_error_pages[err].len == 0) { + return NGX_OK; + } + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ngx_http_error_pages[err].data; + b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len; - location = &r->headers_out.location->value; + out[0].buf = b; + out[0].next = &out[1]; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + + b->pos = tail; + b->last = tail + len; - escape = 2 * ngx_escape_uri(NULL, location->data, location->len, - NGX_ESCAPE_REFRESH); + out[1].buf = b; + out[1].next = NULL;; + + if (msie_padding) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ngx_http_msie_stub; + b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; - msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1 - + escape + location->len - + sizeof(ngx_http_msie_refresh_tail) - 1; + out[1].next = &out[2]; + out[2].buf = b; + out[2].next = NULL;; + } + + if (r == r->main) { + b->last_buf = 1; + } + + b->last_in_chain = 1; + + return ngx_http_output_filter(r, &out[0]); +} + - r->err_status = NGX_HTTP_OK; - r->headers_out.content_type_len = sizeof("text/html") - 1; - r->headers_out.content_length_n = msie_refresh; - r->headers_out.location->hash = 0; - r->headers_out.location = NULL; +static ngx_int_t +ngx_http_send_refresh(ngx_http_request_t *r) +{ + u_char *p, *location; + size_t len, size; + uintptr_t escape; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + + len = r->headers_out.location->value.len; + location = r->headers_out.location->value.data; + + escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH); - } else { - location = NULL; - escape = 0; - msie_refresh = 0; + size = sizeof(ngx_http_msie_refresh_head) - 1 + + escape + len + + sizeof(ngx_http_msie_refresh_tail) - 1; + + r->err_status = NGX_HTTP_OK; + + r->headers_out.content_type_len = sizeof("text/html") - 1; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; + + r->headers_out.location->hash = 0; + r->headers_out.location = NULL; + + r->headers_out.content_length_n = size; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; } ngx_http_clear_accept_ranges(r); @@ -545,109 +689,29 @@ ngx_http_special_response_handler(ngx_ht return rc; } - - if (msie_refresh == 0) { - - if (error_pages[err].len == 0) { - return NGX_OK; - } - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = error_pages[err].data; - b->last = error_pages[err].data + error_pages[err].len; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - out = cl; - - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_ERROR; + } - if (clcf->server_tokens) { - b->pos = error_full_tail; - b->last = error_full_tail + sizeof(error_full_tail) - 1; - } else { - b->pos = error_tail; - b->last = error_tail + sizeof(error_tail) - 1; - } - - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; + p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, + sizeof(ngx_http_msie_refresh_head) - 1); - if (msie_padding) { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = ngx_http_msie_stub; - b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; - - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; - } + if (escape == 0) { + p = ngx_cpymem(p, location, len); } else { - b = ngx_create_temp_buf(r->pool, msie_refresh); - if (b == NULL) { - return NGX_ERROR; - } - - p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, - sizeof(ngx_http_msie_refresh_head) - 1); - - if (escape == 0) { - p = ngx_cpymem(p, location->data, location->len); - - } else { - p = (u_char *) ngx_escape_uri(p, location->data, location->len, - NGX_ESCAPE_REFRESH); - } - - b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, - sizeof(ngx_http_msie_refresh_tail) - 1); - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - out = cl; + p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH); } - if (r == r->main) { - b->last_buf = 1; - } + b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, + sizeof(ngx_http_msie_refresh_tail) - 1); + b->last_buf = 1; b->last_in_chain = 1; - cl->next = NULL; + out.buf = b; + out.next = NULL; - return ngx_http_output_filter(r, out); + return ngx_http_output_filter(r, &out); } diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -49,6 +49,7 @@ ngx_http_write_filter(ngx_http_request_t { off_t size, sent, limit; ngx_uint_t last, flush; + ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; @@ -245,14 +246,17 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - sent = c->sent - sent; - c->write->delayed = 1; - ngx_add_timer(c->write, (ngx_msec_t) (sent * 1000 / r->limit_rate + 1)); + delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1); + + if (delay > 0) { + c->write->delayed = 1; + ngx_add_timer(c->write, delay); + } } else if (c->write->ready && clcf->sendfile_max_chunk && (size_t) (c->sent - sent) - >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) + >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) { c->write->delayed = 1; ngx_add_timer(c->write, 1); diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -29,6 +29,7 @@ static void ngx_mail_smtp_log_rejected_c static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; +static u_char smtp_starttls[] = "220 2.0.0 Start TLS" CRLF; static u_char smtp_next[] = "334 " CRLF; static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; @@ -250,6 +251,8 @@ ngx_mail_smtp_auth_state(ngx_event_t *re case NGX_SMTP_STARTTLS: rc = ngx_mail_smtp_starttls(s, c); + s->out.len = sizeof(smtp_starttls) - 1; + s->out.data = smtp_starttls; break; default: diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -50,6 +50,7 @@ #include #include #include +#include /* uname() */ #include diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -8,12 +8,8 @@ #include -static ngx_int_t ngx_linux_procfs(char *name, char *buf, size_t len, - ngx_log_t *log); - - -char ngx_linux_kern_ostype[50]; -char ngx_linux_kern_osrelease[50]; +u_char ngx_linux_kern_ostype[50]; +u_char ngx_linux_kern_osrelease[50]; int ngx_linux_rtsig_max; @@ -35,26 +31,21 @@ static ngx_os_io_t ngx_linux_io = { ngx_int_t ngx_os_specific_init(ngx_log_t *log) { - int name[2]; - size_t len; - ngx_err_t err; + int name[2]; + size_t len; + ngx_err_t err; + struct utsname u; - if (ngx_linux_procfs("/proc/sys/kernel/ostype", - ngx_linux_kern_ostype, - sizeof(ngx_linux_kern_ostype), log) - == -1) - { + if (uname(&u) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "uname() failed"); return NGX_ERROR; } - if (ngx_linux_procfs("/proc/sys/kernel/osrelease", - ngx_linux_kern_osrelease, - sizeof(ngx_linux_kern_osrelease), log) - == -1) - { - return NGX_ERROR; - } + (void) ngx_cpystrn(ngx_linux_kern_ostype, (u_char *) u.sysname, + sizeof(ngx_linux_kern_ostype)); + (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release, + sizeof(ngx_linux_kern_osrelease)); name[0] = CTL_KERN; name[1] = KERN_RTSIGMAX; @@ -89,36 +80,3 @@ ngx_os_specific_status(ngx_log_t *log) ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d", ngx_linux_rtsig_max); } - - -static ngx_int_t -ngx_linux_procfs(char *name, char *buf, size_t len, ngx_log_t *log) -{ - int n; - ngx_fd_t fd; - - fd = open(name, O_RDONLY); - - if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "open(\"%s\") failed", name); - - return NGX_ERROR; - } - - n = read(fd, buf, len); - - if (n == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "read(\"%s\") failed", name); - - } else { - if (buf[n - 1] == '\n') { - buf[--n] = '\0'; - } - } - - ngx_close_file(fd); - - return n; -}