# HG changeset patch # User Igor Sysoev # Date 1154635200 -14400 # Node ID 1bf60f8c5c9e6884bb95031dfb9a51b34b930f82 # Parent a346c23fc94ec41b660c85731628ae2008ef8b74 nginx 0.3.56 *) Feature: the "dav_access" directive. *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", "-x", and "!-x" operators. *) Bugfix: a segmentation fault occurred if an request returned an redirect and some sent to client header lines were logged in the access log. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,16 @@ +Changes with nginx 0.3.56 04 Aug 2006 + + *) Feature: the "dav_access" directive. + + *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", + "-x", and "!-x" operators. + + *) Bugfix: a segmentation fault occurred if an request returned an + redirect and some sent to client header lines were logged in the + access log. + + Changes with nginx 0.3.55 28 Jul 2006 *) Feature: the "stub" parameter in the "include" SSI command. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,16 @@ +Изменения в nginx 0.3.56 04.08.2006 + + *) Добавление: директива dav_access. + + *) Добавление: директива if поддерживает операторы "-d", "!-d", "-e", + "!-e", "-x" и "!-x". + + *) Исправление: при записи в access_log некоторых передаваемых клиенту + строк заголовков происходил segmentation fault, если запрос + возвращал редирект. + + Изменения в nginx 0.3.55 28.07.2006 *) Добавление: параметр stub в команде SSI include. @@ -22,7 +34,7 @@ "client_body_in_file_only on" и делался переход к следующему бэкенду. *) Исправление: при некоторых условиях во время переконфигурации коды - символов в внутри директивы charset_map могли считаться неверными; + символов внутри директивы charset_map могли считаться неверными; ошибка появилась в 0.3.50. diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -20,6 +20,8 @@ if test -n "$NGX_PERL_VER"; then fi CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`" + # gcc 4.1/4.2 + CFLAGS=`echo $CFLAGS | sed -e 's/-Wunused-value/-Wno-unused-value/'` ngx_perl_ldopts=`$NGX_PERL -MExtUtils::Embed -e ldopts` if $NGX_PERL -V:usemultiplicity | grep define > /dev/null; then 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_VER "nginx/0.3.55" +#define NGINX_VER "nginx/0.3.56" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -166,7 +166,7 @@ ngx_create_path(ngx_file_t *file, ngx_pa ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, "temp file: \"%s\"", file->name.data); - if (ngx_create_dir(file->name.data) == NGX_FILE_ERROR) { + if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_EEXIST) { ngx_log_error(NGX_LOG_CRIT, file->log, err, @@ -184,7 +184,7 @@ ngx_create_path(ngx_file_t *file, ngx_pa ngx_err_t -ngx_create_full_path(u_char *dir) +ngx_create_full_path(u_char *dir, ngx_uint_t access) { u_char *p, ch; ngx_err_t err; @@ -198,7 +198,7 @@ ngx_create_full_path(u_char *dir) *p = '\0'; - if (ngx_create_dir(dir) == NGX_FILE_ERROR) { + if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_EEXIST) { return err; @@ -370,7 +370,7 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng path = cycle->pathes.elts; for (i = 0; i < cycle->pathes.nelts; i++) { - if (ngx_create_dir(path[i]->name.data) == NGX_FILE_ERROR) { + if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_EEXIST) { ngx_log_error(NGX_LOG_EMERG, cycle->log, err, diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -61,7 +61,7 @@ ngx_int_t ngx_create_temp_file(ngx_file_ ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode); void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path); ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path); -ngx_err_t ngx_create_full_path(u_char *dir); +ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access); ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot); ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -14,6 +14,7 @@ typedef struct { ngx_uint_t methods; ngx_flag_t create_full_put_path; + ngx_uint_t access; } ngx_http_dav_loc_conf_t; @@ -22,6 +23,8 @@ static void ngx_http_dav_put_handler(ngx static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err, ngx_int_t not_found, char *failed, u_char *path); static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); +static char *ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); @@ -53,6 +56,13 @@ static ngx_command_t ngx_http_dav_comma offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), NULL }, + { ngx_string("dav_access"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_dav_access, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -214,7 +224,7 @@ ngx_http_dav_handler(ngx_http_request_t ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http mkcol path: \"%s\"", path.data); - if (ngx_create_dir(path.data) != NGX_FILE_ERROR) { + if (ngx_create_dir(path.data, dlcf->access) != NGX_FILE_ERROR) { if (ngx_http_dav_location(r, path.data) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -233,6 +243,8 @@ ngx_http_dav_handler(ngx_http_request_t static void ngx_http_dav_put_handler(ngx_http_request_t *r) { + char *failed; + u_char *name; ngx_err_t err; ngx_str_t *temp, path; ngx_uint_t status; @@ -267,6 +279,25 @@ ngx_http_dav_put_handler(ngx_http_reques } } + dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); + +#if !(NGX_WIN32) + + if (ngx_change_file_access(temp->data, dlcf->access & ~0111) + == NGX_FILE_ERROR) + { + err = ngx_errno; + failed = ngx_change_file_access_n; + name = temp->data; + + goto failed; + } + +#endif + + failed = ngx_rename_file_n; + name = path.data; + if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { goto ok; } @@ -275,10 +306,8 @@ ngx_http_dav_put_handler(ngx_http_reques if (err == NGX_ENOENT) { - dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - if (dlcf->create_full_put_path) { - err = ngx_create_full_path(path.data); + err = ngx_create_full_path(path.data, dlcf->access); if (err == 0) { if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { @@ -303,6 +332,11 @@ ngx_http_dav_put_handler(ngx_http_reques err = ngx_errno; } + +#else + +failed: + #endif if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { @@ -311,9 +345,9 @@ ngx_http_dav_put_handler(ngx_http_reques temp->data); } - ngx_http_finalize_request(r, ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT, - ngx_rename_file_n, - path.data)); + ngx_http_finalize_request(r, + ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT, failed, name)); + return; ok: @@ -407,6 +441,66 @@ ngx_http_dav_location(ngx_http_request_t } +static char * +ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_dav_loc_conf_t *lcf = conf; + + u_char *p; + ngx_str_t *value; + ngx_uint_t i, right, shift; + + if (lcf->access != NGX_CONF_UNSET_UINT) { + return "is duplicate"; + } + + value = cf->args->elts; + + lcf->access = 0700; + + for (i = 1; i < 3; i++) { + + p = value[i].data; + + if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) { + shift = 6; + p += sizeof("user:") - 1; + + } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) { + shift = 3; + p += sizeof("group:") - 1; + + } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) { + shift = 0; + p += sizeof("all:") - 1; + + } else { + goto invalid; + } + + if (ngx_strcmp(p, "rw") == 0) { + right = 7; + + } else if (ngx_strcmp(p, "r") == 0) { + right = 5; + + } else { + goto invalid; + } + + lcf->access += right << shift; + } + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[i]); + return NGX_CONF_ERROR; +} + + static void * ngx_http_dav_create_loc_conf(ngx_conf_t *cf) { @@ -424,6 +518,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t */ conf->create_full_put_path = NGX_CONF_UNSET; + conf->access = NGX_CONF_UNSET_UINT; return conf; } @@ -441,6 +536,8 @@ ngx_http_dav_merge_loc_conf(ngx_conf_t * ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path, 0); + ngx_conf_merge_uint_value(conf->access, prev->access, 0600); + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -817,11 +817,41 @@ ngx_http_rewrite_if_condition(ngx_conf_t return NGX_CONF_OK; } + if (p[1] == 'd') { + fop->op = ngx_http_script_file_dir; + return NGX_CONF_OK; + } + + if (p[1] == 'e') { + fop->op = ngx_http_script_file_exists; + return NGX_CONF_OK; + } + + if (p[1] == 'x') { + fop->op = ngx_http_script_file_exec; + return NGX_CONF_OK; + } + if (p[0] == '!') { if (p[2] == 'f') { fop->op = ngx_http_script_file_not_plain; return NGX_CONF_OK; } + + if (p[2] == 'd') { + fop->op = ngx_http_script_file_not_dir; + return NGX_CONF_OK; + } + + if (p[2] == 'e') { + fop->op = ngx_http_script_file_not_exists; + return NGX_CONF_OK; + } + + if (p[2] == 'x') { + fop->op = ngx_http_script_file_not_exec; + return NGX_CONF_OK; + } } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,6 +17,7 @@ typedef u_char *(*ngx_ssl_variable_handl #define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" +static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_client_s_dn(ngx_http_request_t *r, @@ -384,7 +385,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } if (conf->verify) { - SSL_CTX_set_verify(conf->ssl.ctx, NGX_SSL_VERIFY, NULL); + SSL_CTX_set_verify(conf->ssl.ctx, NGX_SSL_VERIFY, + ngx_http_ssl_verify_callback); SSL_CTX_set_verify_depth(conf->ssl.ctx, conf->verify_depth); @@ -422,6 +424,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } +static int +ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) +{ + return 1; +} + + #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) static char * diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -460,6 +460,8 @@ ngx_http_header_filter(ngx_http_request_ r->headers_out.location->value.len = b->last - p; r->headers_out.location->value.data = p; + r->headers_out.location->key.len = sizeof("Location: ") - 1; + r->headers_out.location->key.data = (u_char *) "Location: "; *b->last++ = CR; *b->last++ = LF; } 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 @@ -1269,34 +1269,6 @@ ngx_http_process_request_header(ngx_http return NGX_ERROR; } -#if (NGX_HTTP_SSL) - - if (r->connection->ssl) { - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - - if (sscf->verify) { - rc = SSL_get_verify_result(r->connection->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client SSL certificate verify error: %l ", rc); - ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); - return NGX_ERROR; - } - - if (SSL_get_peer_certificate(r->connection->ssl->connection) - == NULL) - { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent no required SSL certificate"); - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return NGX_ERROR; - } - } - } - -#endif - if (r->headers_in.connection) { if (r->headers_in.connection->value.len == 5 && ngx_strcasecmp(r->headers_in.connection->value.data, "close") @@ -1362,6 +1334,35 @@ ngx_http_process_request_header(ngx_http } } +#if (NGX_HTTP_SSL) + + if (r->connection->ssl) { + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); + + if (sscf->verify) { + rc = SSL_get_verify_result(r->connection->ssl->connection); + + if (rc != X509_V_OK) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client SSL certificate verify error: (%l:%s) ", + rc, X509_verify_cert_error_string(rc)); + ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); + return NGX_ERROR; + } + + if (SSL_get_peer_certificate(r->connection->ssl->connection) + == NULL) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no required SSL certificate"); + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return NGX_ERROR; + } + } + } + +#endif + return NGX_OK; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -961,8 +961,13 @@ ngx_http_script_file_code(ngx_http_scrip switch (code->op) { case ngx_http_script_file_plain: + case ngx_http_script_file_dir: + case ngx_http_script_file_exists: + case ngx_http_script_file_exec: goto false; case ngx_http_script_file_not_plain: + case ngx_http_script_file_not_dir: + case ngx_http_script_file_not_exec: goto true; } @@ -981,6 +986,54 @@ ngx_http_script_file_code(ngx_http_scrip goto false; } goto true; + + case ngx_http_script_file_dir: + if (ngx_is_dir(&fi)) { + goto true; + } + goto false; + + case ngx_http_script_file_not_dir: + if (ngx_is_dir(&fi)) { + goto false; + } + goto true; + + case ngx_http_script_file_exists: + if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) { + goto true; + } + goto false; + + case ngx_http_script_file_not_exists: + if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) { + goto false; + } + goto true; + +#if (NGX_WIN32) + + case ngx_http_script_file_exec: + goto false; + + case ngx_http_script_file_not_exec: + goto true; + +#else + + case ngx_http_script_file_exec: + if (ngx_is_exec(&fi)) { + goto true; + } + goto false; + + case ngx_http_script_file_not_exec: + if (ngx_is_exec(&fi)) { + goto false; + } + goto true; + +#endif } false: diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -140,7 +140,13 @@ typedef struct { typedef enum { ngx_http_script_file_plain = 0, - ngx_http_script_file_not_plain + ngx_http_script_file_not_plain, + ngx_http_script_file_dir, + ngx_http_script_file_not_dir, + ngx_http_script_file_exists, + ngx_http_script_file_not_exists, + ngx_http_script_file_exec, + ngx_http_script_file_not_exec } ngx_http_script_file_op_e; diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -61,6 +61,10 @@ ssize_t ngx_write_chain_to_file(ngx_file #define ngx_rename_file_n "rename" +#define ngx_change_file_access(n, a) chmod((const char *) n, a) +#define ngx_change_file_access_n "chmod" + + #define ngx_file_info(file, sb) stat((const char *) file, sb) #define ngx_file_info_n "stat()" @@ -69,6 +73,8 @@ ssize_t ngx_write_chain_to_file(ngx_file #define ngx_is_dir(sb) (S_ISDIR((sb)->st_mode)) #define ngx_is_file(sb) (S_ISREG((sb)->st_mode)) +#define ngx_is_link(sb) (S_ISLNK((sb)->st_mode)) +#define ngx_is_exec(sb) ((sb)->st_mode & S_IXUSR) #define ngx_file_size(sb) (sb)->st_size #define ngx_file_mtime(sb) (sb)->st_mtime #define ngx_file_uniq(sb) (sb)->st_ino @@ -95,7 +101,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_read_dir_n "readdir()" -#define ngx_create_dir(name) mkdir((const char *) name, 0700) +#define ngx_create_dir(name, access) mkdir((const char *) name, access) #define ngx_create_dir_n "mkdir()"