# HG changeset patch # User Igor Sysoev # Date 1193605200 -10800 # Node ID eae74a780a84a4f89a835e17a840657cb6b1c556 # Parent 81bf600d64d530b46b48e762a4e2a18cf1fe138b nginx 0.6.16 *) Change: now the uname(2) is used on Linux instead of procfs. Thanks to Ilya Novikov. *) Bugfix: if the "?" character was in a "error_page" directive, then it was escaped in a proxied request; bug appeared in 0.6.11. *) Bugfix: compatibility with mget. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,18 @@ +Changes with nginx 0.6.16 29 Oct 2007 + + *) Change: now the uname(2) is used on Linux instead of procfs. + Thanks to Ilya Novikov. + + *) Bugfix: if the "?" character was in a "error_page" directive, then + it was escaped in a proxied request; bug appeared in 0.6.11. + + *) Bugfix: compatibility with mget. + + Changes with nginx 0.6.15 22 Oct 2007 - *) Feature: cygwin compatibility. + *) Feature: Cygwin compatibility. Thanks to Vladimir Kutakov. *) Feature: the "merge_slashes" directive. @@ -180,7 +191,7 @@ Changes with nginx 0.6.7 *) Feature: the "add_header Last-Modified ..." directive changes the "Last-Modified" response header line. - *) Bugfix: if an response different than 200 was returned to an request + *) Bugfix: if a response different than 200 was returned to a request with body and connection went to the keep-alive state after the request, then nginx returned 400 for the next request. @@ -191,7 +202,7 @@ Changes with nginx 0.6.7 platforms except FreeBSD. Thanks to Jiang Hong. - *) Bugfix: a worker process may got caught in an endless loop, if an + *) Bugfix: a worker process may got caught in an endless loop, if a "server" inside "upstream" block was marked as "down"; bug appeared in 0.6.6. @@ -451,7 +462,7 @@ Changes with nginx 0.5.16 trailing ";"; bug appeared in 0.3.50. *) Bugfix: the "[alert] zero size buf" error when FastCGI server was - used and an request body written in a temporary file was multiple of + used and a request body written in a temporary file was multiple of 32K. *) Bugfix: nginx could not be built on Solaris without the --with-debug @@ -755,7 +766,7 @@ Changes with nginx 0.4.14 *) Bugfix: ngx_http_perl_module did not work if perl was called recursively. - *) Bugfix: nginx ignored a host name in an request line. + *) Bugfix: nginx ignored a host name in a request line. *) Bugfix: a worker process may got caught in an endless loop, if a FastCGI server sent too many data to the stderr. @@ -778,7 +789,7 @@ Changes with nginx 0.4.13 *) Feature: the "limit_except" directive supports all WebDAV methods. *) Bugfix: if the "add_before_body" directive was used without the - "add_after_body" directive, then an response did not transferred + "add_after_body" directive, then a response did not transferred complete. *) Bugfix: a large request body did not receive if the epoll method and @@ -847,8 +858,8 @@ Changes with nginx 0.4.9 Changes with nginx 0.4.8 11 Oct 2006 *) Bugfix: if an "include" SSI command were before another "include" - SSI command with an "wait" parameter, then the "wait" parameter - might not work. + SSI command with a "wait" parameter, then the "wait" parameter might + not work. *) Bugfix: the ngx_http_flv_module added the FLV header to the full responses. @@ -865,8 +876,8 @@ Changes with nginx 0.4.7 variables. *) Bugfix: if an "include" SSI command were before another "include" - SSI command with an "wait" parameter, then the "wait" parameter - might not work. + SSI command with a "wait" parameter, then the "wait" parameter might + not work. *) Bugfix: if the "proxy_buffering off" directive was used or while working with memcached the connections might not be closed on @@ -925,10 +936,10 @@ Changes with nginx 0.4.3 *) Feature: the ngx_http_browser_module. *) Bugfix: a segmentation fault may occur while redirecting the 400 - error to the proxied server using an "proxy_pass" directive. + error to the proxied server using a "proxy_pass" directive. *) Bugfix: a segmentation fault occurred if an unix domain socket was - used in an "proxy_pass" directive; bug appeared in 0.3.47. + used in a "proxy_pass" directive; bug appeared in 0.3.47. *) Bugfix: SSI did work with memcached and nonbuffered responses. @@ -1043,7 +1054,7 @@ Changes with nginx 0.3.56 *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", "-x", and "!-x" operators. - *) Bugfix: a segmentation fault occurred if an request returned an + *) Bugfix: a segmentation fault occurred if a request returned a redirect and some sent to client header lines were logged in the access log. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,7 +1,19 @@ +Изменения в nginx 0.6.16 29.10.2007 + + *) Изменение: теперь на Linux используется uname(2) вместо procfs. + Спасибо Илье Новикову. + + *) Исправление: если в директиве error_page использовался символ "?", + то он экранировался при проксировании запроса; ошибка появилась в + 0.6.11. + + *) Исправление: совместимость с mget. + + Изменения в nginx 0.6.15 22.10.2007 - *) Добавление: совместимость с cygwin. + *) Добавление: совместимость с Cygwin. Спасибо Владимиру Кутакову. *) Добавление: директива merge_slashes. 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.6.15" +#define NGINX_VERSION "0.6.16" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_md5.h b/src/core/ngx_md5.h --- a/src/core/ngx_md5.h +++ b/src/core/ngx_md5.h @@ -24,15 +24,15 @@ typedef MD5_CTX ngx_md5_t; #if (NGX_OPENSSL_MD5) -#define ngx_md5_init MD5_Init -#define ngx_md5_update MD5_Update -#define ngx_md5_final MD5_Final +#define ngx_md5_init MD5_Init +#define ngx_md5_update MD5_Update +#define ngx_md5_final MD5_Final #else -#define ngx_md5_init MD5Init -#define ngx_md5_update MD5Update -#define ngx_md5_final MD5Final +#define ngx_md5_init MD5Init +#define ngx_md5_update MD5Update +#define ngx_md5_final MD5Final #endif diff --git a/src/core/ngx_sha1.h b/src/core/ngx_sha1.h --- a/src/core/ngx_sha1.h +++ b/src/core/ngx_sha1.h @@ -22,9 +22,9 @@ typedef SHA_CTX ngx_sha1_t; -#define ngx_sha1_init SHA1_Init -#define ngx_sha1_update SHA1_Update -#define ngx_sha1_final SHA1_Final +#define ngx_sha1_init SHA1_Init +#define ngx_sha1_update SHA1_Update +#define ngx_sha1_final SHA1_Final #endif /* _NGX_SHA1_H_INCLUDED_ */ diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -21,7 +21,7 @@ static ngx_int_t ngx_event_pipe_drain_ch ngx_int_t -ngx_event_pipe(ngx_event_pipe_t *p, int do_write) +ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { u_int flags; ngx_event_t *rev, *wev; diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h --- a/src/event/ngx_event_pipe.h +++ b/src/event/ngx_event_pipe.h @@ -86,7 +86,7 @@ struct ngx_event_pipe_s { }; -ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, int do_write); +ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write); ngx_int_t ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf); ngx_int_t ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b); diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -22,25 +22,13 @@ typedef struct { } ngx_http_index_loc_conf_t; -typedef struct { - ngx_uint_t current; - - ngx_str_t path; - ngx_str_t index; - - size_t root; - - ngx_uint_t tested; /* unsigned tested:1 */ -} ngx_http_index_ctx_t; - - #define NGX_HTTP_DEFAULT_INDEX "index.html" static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_core_loc_conf_t *clcf, ngx_http_index_ctx_t *ctx); -static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err); + ngx_http_core_loc_conf_t *clcf, u_char *path, u_char *last); +static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, u_char *file, + ngx_err_t err); static ngx_int_t ngx_http_index_init(ngx_conf_t *cf); static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); @@ -107,14 +95,13 @@ ngx_module_t ngx_http_index_module = { static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { - u_char *last; - size_t len; + u_char *p, *name; + size_t len, nlen, root, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_log_t *log; - ngx_uint_t i; + ngx_uint_t i, dir_tested; ngx_http_index_t *index; - ngx_http_index_ctx_t *ctx; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; @@ -140,24 +127,14 @@ ngx_http_index_handler(ngx_http_request_ ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - /* - * we use context because the handler supports an async file opening, - * and may be called several times - */ - - ctx = ngx_http_get_module_ctx(r, ngx_http_index_module); - if (ctx == NULL) { - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_index_ctx_t)); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_index_module); - } + allocated = 0; + root = 0; + dir_tested = 0; + name = NULL; + path.data = NULL; index = ilcf->indices->elts; - for (i = ctx->current; i < ilcf->indices->nelts; i++) { + for (i = 0; i < ilcf->indices->nelts; i++) { if (index[i].lengths == NULL) { @@ -166,7 +143,7 @@ ngx_http_index_handler(ngx_http_request_ } len = ilcf->max_index_len; - ctx->index.len = index[i].name.len; + nlen = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); @@ -184,45 +161,44 @@ ngx_http_index_handler(ngx_http_request_ len += lcode(&e); } - ctx->index.len = len; + nlen = len; /* 16 bytes are preallocation */ len += 16; } - if (len > (size_t) (ctx->path.data + ctx->path.len - ctx->index.data)) { + if (len > (size_t) (path.data + allocated - name)) { - last = ngx_http_map_uri_to_path(r, &ctx->path, &ctx->root, len); - if (last == NULL) { + name = ngx_http_map_uri_to_path(r, &path, &root, len); + if (name == NULL) { return NGX_ERROR; } - ctx->index.data = last; + allocated = path.len; } - path.data = ctx->path.data; - if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ - ngx_memcpy(ctx->index.data, index[i].name.data, index[i].name.len); + ngx_memcpy(name, index[i].name.data, index[i].name.len); - path.len = (ctx->index.data + index[i].name.len - 1) - path.data; + path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; - e.pos = ctx->index.data; + e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } - if (*ctx->index.data == '/') { - ctx->index.len--; - return ngx_http_internal_redirect(r, &ctx->index, &r->args); + if (*name == '/') { + uri.len = nlen - 1; + uri.data = name; + return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; @@ -230,8 +206,7 @@ ngx_http_index_handler(ngx_http_request_ *e.pos++ = '\0'; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "open index \"%V\"", &path); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path); of.test_dir = 0; of.retest = clcf->open_file_cache_retest; @@ -240,37 +215,27 @@ ngx_http_index_handler(ngx_http_request_ rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); -#if 0 - if (rc == NGX_AGAIN) { - ctx->current = i; - return NGX_AGAIN; - } -#endif - if (rc == NGX_ERROR) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err, - ngx_open_file_n " \"%s\" failed", ctx->path.data); + ngx_open_file_n " \"%s\" failed", path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (of.err == NGX_ENOTDIR) { - return ngx_http_index_error(r, ctx, of.err); - - } else if (of.err == NGX_EACCES) { - return ngx_http_index_error(r, ctx, of.err); + if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) { + return ngx_http_index_error(r, path.data, of.err); } - if (!ctx->tested) { - rc = ngx_http_index_test_dir(r, clcf, ctx); + if (!dir_tested) { + rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } - ctx->tested = 1; + dir_tested = 1; } if (of.err == NGX_ENOENT) { @@ -278,15 +243,15 @@ ngx_http_index_handler(ngx_http_request_ } ngx_log_error(NGX_LOG_ERR, log, of.err, - ngx_open_file_n " \"%s\" failed", ctx->path.data); + ngx_open_file_n " \"%s\" failed", path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } - uri.len = r->uri.len + ctx->index.len - 1; + uri.len = r->uri.len + nlen - 1; if (!clcf->alias) { - uri.data = ctx->path.data + ctx->root; + uri.data = path.data + root; } else { uri.data = ngx_palloc(r->pool, uri.len); @@ -294,8 +259,8 @@ ngx_http_index_handler(ngx_http_request_ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(uri.data, r->uri.data, r->uri.len); - ngx_memcpy(last, ctx->index.data, ctx->index.len - 1); + p = ngx_copy(uri.data, r->uri.data, r->uri.len); + ngx_memcpy(p, name, nlen - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); @@ -307,70 +272,71 @@ ngx_http_index_handler(ngx_http_request_ static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, - ngx_http_index_ctx_t *ctx) + u_char *path, u_char *last) { u_char c; - ngx_str_t path; - ngx_uint_t i; + ngx_str_t dir; ngx_open_file_info_t of; - c = *(ctx->index.data - 1); - i = (c == '/') ? 1 : 0; - *(ctx->index.data - i) = '\0'; + c = *last; + if (c != '/') { + /* "alias" without trailing slash */ + c = *(++last); + } + *last = '\0'; - path.len = (ctx->index.data - i) - ctx->path.data; - path.data = ctx->path.data; + dir.len = last - path; + dir.data = path; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http index check dir: \"%V\"", &path); + "http index check dir: \"%V\"", &dir); of.test_dir = 1; of.retest = clcf->open_file_cache_retest; of.errors = clcf->open_file_cache_errors; - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) != NGX_OK) { if (of.err) { if (of.err == NGX_ENOENT) { - *(ctx->index.data - i) = c; - return ngx_http_index_error(r, ctx, of.err); + *last = c; + return ngx_http_index_error(r, dir.data, NGX_ENOENT); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", path.data); + ngx_open_file_n " \"%s\" failed", dir.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; } - *(ctx->index.data - i) = c; + *last = c; if (of.is_dir) { return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "\"%s\" is not a directory", path.data); + "\"%s\" is not a directory", dir.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } static ngx_int_t -ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx, - ngx_err_t err) +ngx_http_index_error(ngx_http_request_t *r, u_char *file, ngx_err_t err) { if (err == NGX_EACCES) { ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is forbidden", ctx->path.data); + "\"%s\" is forbidden", file); return NGX_HTTP_FORBIDDEN; } ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is not found", ctx->path.data); + "\"%s\" is not found", file); return NGX_HTTP_NOT_FOUND; } @@ -472,11 +438,11 @@ ngx_http_index_set_index(ngx_conf_t *cf, value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { + if (value[i].data[0] == '/' && i != cf->args->nelts - 1) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "only the last index in \"index\" directive " - "may be absolute"); - return NGX_CONF_ERROR; + "should be absolute"); } if (value[i].len == 0) { @@ -503,6 +469,10 @@ ngx_http_index_set_index(ngx_conf_t *cf, ilcf->max_index_len = index->name.len; } + if (index->name.data[0] == '/') { + continue; + } + /* include the terminating '\0' to the length to use ngx_copy() */ index->name.len++; 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.6.15'; +our $VERSION = '0.6.16'; 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 @@ -124,6 +124,7 @@ ngx_http_parse_request_line(ngx_http_req sw_major_digit, sw_first_minor_digit, sw_minor_digit, + sw_spaces_after_digit, sw_almost_done } state; @@ -636,6 +637,11 @@ ngx_http_parse_request_line(ngx_http_req goto done; } + if (ch == ' ') { + state = sw_spaces_after_digit; + break; + } + if (ch < '0' || ch > '9') { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -643,6 +649,20 @@ ngx_http_parse_request_line(ngx_http_req r->http_minor = r->http_minor * 10 + ch - '0'; break; + case sw_spaces_after_digit: + switch (ch) { + case ' ': + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + default: + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; + /* end of request line */ case sw_almost_done: r->request_end = p - 1; 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, invalid host name */ + 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/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; -}