diff options
Diffstat (limited to '')
-rw-r--r-- | docs/changes.xml | 6 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 39 | ||||
-rw-r--r-- | src/nxt_http_route.c | 4 | ||||
-rw-r--r-- | src/nxt_http_static.c | 299 | ||||
-rw-r--r-- | src/nxt_var.c | 20 | ||||
-rw-r--r-- | src/nxt_var.h | 2 |
6 files changed, 275 insertions, 95 deletions
diff --git a/docs/changes.xml b/docs/changes.xml index 5855466e..c547633a 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -31,6 +31,12 @@ NGINX Unit updated to 1.26.0. date="" time="" packager="Andrei Belov <defan@nginx.com>"> +<change type="feature"> +<para> +variables support in the "chroot" option. +</para> +</change> + <change type="bugfix"> <para> fixed building with glibc 2.34, notably Fedora 35. diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 18c2d478..7d599938 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -33,7 +33,8 @@ typedef enum { typedef enum { - NXT_CONF_VLDT_REQUIRED = 1, + NXT_CONF_VLDT_REQUIRED = 1 << 0, + NXT_CONF_VLDT_VAR = 1 << 1, } nxt_conf_vldt_flags_t; @@ -73,8 +74,8 @@ static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type); static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...); -static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, - const char *option, nxt_str_t *value); +static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name, + nxt_str_t *value); nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); @@ -354,6 +355,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { .name = nxt_string("pass"), .type = NXT_CONF_VLDT_STRING, .validator = nxt_conf_vldt_pass, + .flags = NXT_CONF_VLDT_VAR, }, { .name = nxt_string("application"), .type = NXT_CONF_VLDT_STRING, @@ -607,6 +609,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = { .name = nxt_string("pass"), .type = NXT_CONF_VLDT_STRING, .validator = nxt_conf_vldt_pass, + .flags = NXT_CONF_VLDT_VAR, }, NXT_CONF_VLDT_END @@ -646,6 +649,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = { .validator = nxt_conf_vldt_unsupported, .u.string = "chroot", #endif + .flags = NXT_CONF_VLDT_VAR, }, { .name = nxt_string("follow_symlinks"), .type = NXT_CONF_VLDT_BOOLEAN, @@ -1163,7 +1167,6 @@ nxt_conf_validate(nxt_conf_validation_t *vldt) nxt_int_t ret; ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); - if (ret != NXT_OK) { return ret; } @@ -1290,14 +1293,14 @@ nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, static nxt_int_t -nxt_conf_vldt_var(nxt_conf_validation_t *vldt, const char *option, +nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_str_t *value) { u_char error[NXT_MAX_ERROR_STR]; if (nxt_var_test(value, error) != NXT_OK) { - return nxt_conf_vldt_error(vldt, "%s in the \"%s\" value.", - error, option); + return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.", + error, name); } return NXT_OK; @@ -1488,10 +1491,6 @@ nxt_conf_vldt_pass(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, nxt_conf_get_string(value, &pass); - if (nxt_is_var(&pass)) { - return nxt_conf_vldt_var(vldt, "pass", &pass); - } - ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3); if (ret != NXT_OK) { @@ -2280,7 +2279,7 @@ nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, { uint32_t index; nxt_int_t ret; - nxt_str_t name; + nxt_str_t name, var; nxt_conf_value_t *member; nxt_conf_vldt_object_t *vals; @@ -2337,8 +2336,22 @@ nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, continue; } - ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); + if (vals->flags & NXT_CONF_VLDT_VAR + && nxt_conf_type(member) == NXT_CONF_STRING) + { + nxt_conf_get_string(member, &var); + if (nxt_is_var(&var)) { + ret = nxt_conf_vldt_var(vldt, &name, &var); + if (ret != NXT_OK) { + return ret; + } + + break; + } + } + + ret = nxt_conf_vldt_type(vldt, &name, member, vals->type); if (ret != NXT_OK) { return ret; } diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 8af22989..328a32c6 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -679,7 +679,7 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_get_string(acf.pass, &pass); - action->u.var = nxt_var_compile(&pass, mp); + action->u.var = nxt_var_compile(&pass, mp, 0); if (nxt_slow_path(action->u.var == NULL)) { return NXT_ERROR; } @@ -1603,7 +1603,7 @@ nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } - action->u.var = nxt_var_compile(pass, mp); + action->u.var = nxt_var_compile(pass, mp, 0); if (nxt_slow_path(action->u.var == NULL)) { return NULL; } diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c index 9b79a666..263ec9db 100644 --- a/src/nxt_http_static.c +++ b/src/nxt_http_static.c @@ -8,19 +8,36 @@ typedef struct { - nxt_str_t share; - nxt_str_t chroot; - nxt_uint_t resolve; - nxt_http_route_rule_t *types; + nxt_str_t share; +#if (NXT_HAVE_OPENAT2) + nxt_var_t *chroot; + nxt_uint_t resolve; +#endif + nxt_http_route_rule_t *types; + uint8_t is_const; /* 1 bit */ } nxt_http_static_conf_t; +typedef struct { + nxt_http_action_t *action; +#if (NXT_HAVE_OPENAT2) + nxt_str_t chroot; +#endif + uint8_t need_body; /* 1 bit */ +} nxt_http_static_ctx_t; + + #define NXT_HTTP_STATIC_BUF_COUNT 2 #define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) static nxt_http_action_t *nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *action); +static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data); +static void nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data); +#if (NXT_HAVE_OPENAT2) +static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr); +#endif static void nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten); static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, @@ -62,32 +79,18 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NXT_ERROR; } + conf->is_const = 1; + #if (NXT_HAVE_OPENAT2) if (acf->chroot.length > 0) { - u_char *p; - nxt_str_t slash; - - if (acf->chroot.start[acf->chroot.length - 1] != '/') { - nxt_str_set(&slash, "/"); - - } else { - nxt_str_set(&slash, ""); + if (nxt_is_var(&acf->chroot)) { + conf->is_const = 0; } - value.length = acf->chroot.length + slash.length; - - value.start = nxt_mp_alloc(mp, value.length + 1); - if (nxt_slow_path(value.start == NULL)) { + conf->chroot = nxt_var_compile(&acf->chroot, mp, 1); + if (nxt_slow_path(conf->chroot == NULL)) { return NXT_ERROR; } - - p = value.start; - p = nxt_cpymem(p, acf->chroot.start, acf->chroot.length); - p = nxt_cpymem(p, slash.start, slash.length); - *p = '\0'; - - conf->chroot = value; - conf->resolve |= RESOLVE_IN_ROOT; } if (acf->follow_symlinks != NULL @@ -128,26 +131,11 @@ static nxt_http_action_t * nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *action) { - size_t length, encode; - u_char *p, *fname; - struct tm tm; - nxt_buf_t *fb; nxt_int_t ret; - nxt_str_t index, exten, *mtype, *chroot; - nxt_uint_t level; nxt_bool_t need_body; - nxt_file_t *f, file; - nxt_file_info_t fi; - nxt_http_field_t *field; - nxt_http_status_t status; - nxt_router_conf_t *rtcf; - nxt_work_handler_t body_handler; + nxt_http_static_ctx_t *ctx; nxt_http_static_conf_t *conf; - conf = action->u.conf; - - nxt_debug(task, "http static: \"%V\"", &conf->share); - if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { if (!nxt_str_eq(r->method, "HEAD", 4)) { @@ -165,6 +153,91 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, need_body = 1; } + conf = action->u.conf; + +#if (NXT_DEBUG && NXT_HAVE_OPENAT2) + nxt_str_t chr; + + if (conf->chroot != NULL) { + nxt_var_raw(conf->chroot, &chr); + + } else { + nxt_str_set(&chr, ""); + } + + nxt_debug(task, "http static: \"%V\" (chroot: \"%V\")", &conf->share, &chr); + +#else + nxt_debug(task, "http static: \"%V\"", &conf->share); +#endif + + ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t)); + if (nxt_slow_path(ctx == NULL)) { + goto fail; + } + + ctx->action = action; + ctx->need_body = need_body; + + if (conf->is_const) { +#if (NXT_HAVE_OPENAT2) + if (conf->chroot != NULL) { + nxt_var_raw(conf->chroot, &ctx->chroot); + } +#endif + + nxt_http_static_send_ready(task, r, ctx); + + } else { + ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + +#if (NXT_HAVE_OPENAT2) + nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot); +#endif + + nxt_var_query_resolve(task, r->var_query, ctx, + nxt_http_static_send_ready, + nxt_http_static_var_error); + } + + return NULL; + +fail: + + nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); + return NULL; +} + + +static void +nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) +{ + size_t length, encode; + u_char *p, *fname; + struct tm tm; + nxt_buf_t *fb; + nxt_int_t ret; + nxt_str_t index, exten, *mtype; + nxt_uint_t level; + nxt_file_t *f, file; + nxt_file_info_t fi; + nxt_http_field_t *field; + nxt_http_status_t status; + nxt_router_conf_t *rtcf; + nxt_http_action_t *action; + nxt_http_request_t *r; + nxt_work_handler_t body_handler; + nxt_http_static_ctx_t *ctx; + nxt_http_static_conf_t *conf; + + r = obj; + ctx = data; + action = ctx->action; + conf = action->u.conf; + if (r->path->start[r->path->length - 1] == '/') { /* TODO: dynamic index setting. */ nxt_str_set(&index, "index.html"); @@ -176,6 +249,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, } f = NULL; + status = NXT_HTTP_INTERNAL_SERVER_ERROR; rtcf = r->conf->socket_conf->router_conf; @@ -192,12 +266,8 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, } if (ret == 0) { - if (action->fallback != NULL) { - return action->fallback; - } - - nxt_http_request_error(task, r, NXT_HTTP_FORBIDDEN); - return NULL; + status = NXT_HTTP_FORBIDDEN; + goto fail; } } @@ -218,18 +288,21 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, file.name = fname; - chroot = &conf->chroot; - #if (NXT_HAVE_OPENAT2) - if (conf->resolve != 0) { + if (conf->resolve != 0 || ctx->chroot.length > 0) { + nxt_str_t *chr; + nxt_uint_t resolve; + + resolve = conf->resolve; + chr = &ctx->chroot; - if (chroot->length > 0) { - file.name = chroot->start; + if (chr->length > 0) { + resolve |= RESOLVE_IN_ROOT; - if (length > chroot->length - && nxt_memcmp(fname, chroot->start, chroot->length) == 0) - { - fname += chroot->length; + fname = nxt_http_static_chroot_match(chr->start, file.name); + + if (fname != NULL) { + file.name = chr->start; ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0); @@ -256,7 +329,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, file.name = fname; ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, - NXT_FILE_OPEN, 0, af.fd, conf->resolve); + NXT_FILE_OPEN, 0, af.fd, resolve); if (af.fd != AT_FDCWD) { nxt_file_close(task, &af); @@ -309,22 +382,28 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, } if (level == NXT_LOG_ERR && action->fallback != NULL) { - return action->fallback; + goto fail; } if (status != NXT_HTTP_NOT_FOUND) { - if (chroot->length > 0) { +#if (NXT_HAVE_OPENAT2) + nxt_str_t *chr = &ctx->chroot; + + if (chr->length > 0) { nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", - fname, chroot, file.error); + fname, chr, file.error); } else { nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); } + +#else + nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); +#endif } - nxt_http_request_error(task, r, status); - return NULL; + goto fail; } f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); @@ -400,7 +479,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, field->value_length = mtype->length; } - if (need_body && nxt_file_size(&fi) > 0) { + if (ctx->need_body && nxt_file_size(&fi) > 0) { fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); if (nxt_slow_path(fb == NULL)) { goto fail; @@ -421,20 +500,17 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, } else { /* Not a file. */ - nxt_file_close(task, f); - if (nxt_slow_path(!nxt_is_dir(&fi))) { - if (action->fallback != NULL) { - return action->fallback; + if (action->fallback == NULL) { + nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", + f->name); } - nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", - f->name); - - nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); - return NULL; + status = NXT_HTTP_NOT_FOUND; + goto fail; } + nxt_file_close(task, f); f = NULL; r->status = NXT_HTTP_MOVED_PERMANENTLY; @@ -482,19 +558,92 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, nxt_http_request_header_send(task, r, body_handler, NULL); r->state = &nxt_http_static_send_state; - return NULL; + return; fail: - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - if (f != NULL) { nxt_file_close(task, f); } - return NULL; + if (status != NXT_HTTP_INTERNAL_SERVER_ERROR + && action->fallback != NULL) + { + nxt_http_request_action(task, r, action->fallback); + return; + } + + nxt_http_request_error(task, r, status); +} + + +static void +nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data) +{ + nxt_http_request_t *r; + + r = obj; + + nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); +} + + +#if (NXT_HAVE_OPENAT2) + +static u_char * +nxt_http_static_chroot_match(u_char *chr, u_char *shr) +{ + if (*chr != *shr) { + return NULL; + } + + chr++; + shr++; + + for ( ;; ) { + if (*shr == '\0') { + return NULL; + } + + if (*chr == *shr) { + chr++; + shr++; + continue; + } + + if (*chr == '\0') { + break; + } + + if (*chr == '/') { + if (chr[-1] == '/') { + chr++; + continue; + } + + } else if (*shr == '/') { + if (shr[-1] == '/') { + shr++; + continue; + } + } + + return NULL; + } + + if (shr[-1] != '/' && *shr != '/') { + return NULL; + } + + while (*shr == '/') { + shr++; + } + + return (*shr != '\0') ? shr : NULL; } +#endif + static void nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) diff --git a/src/nxt_var.c b/src/nxt_var.c index d26d4f15..60650ef4 100644 --- a/src/nxt_var.c +++ b/src/nxt_var.c @@ -9,6 +9,7 @@ struct nxt_var_s { size_t length; nxt_uint_t vars; + uint8_t strz; /* 1 bit */ u_char data[]; /* @@ -229,7 +230,7 @@ nxt_var_index_init(void) nxt_var_t * -nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp) +nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) { u_char *p, *end, *next, *src; size_t size; @@ -258,19 +259,24 @@ nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp) size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length; - var = nxt_mp_get(mp, size); + var = nxt_mp_get(mp, size + strz); if (nxt_slow_path(var == NULL)) { return NULL; } var->length = str->length; var->vars = n; + var->strz = strz; subs = nxt_var_subs(var); src = nxt_var_raw_start(var); nxt_memcpy(src, str->start, str->length); + if (strz) { + src[str->length] = '\0'; + } + n = 0; p = str->start; @@ -585,7 +591,7 @@ nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query) length += str->length - subs[j].length; } - p = nxt_mp_nget(query->values.mem_pool, length); + p = nxt_mp_nget(query->values.mem_pool, length + var->strz); if (nxt_slow_path(p == NULL)) { query->failed = 1; goto done; @@ -612,10 +618,16 @@ nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query) } if (last != var->length) { - nxt_memcpy(p, &src[last], var->length - last); + p = nxt_cpymem(p, &src[last], var->length - last); + } + + if (var->strz) { + *p = '\0'; } nxt_array_reset(&query->parts); + + nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, val[i].value); } done: diff --git a/src/nxt_var.h b/src/nxt_var.h index 6825c262..3b7d0c28 100644 --- a/src/nxt_var.h +++ b/src/nxt_var.h @@ -35,7 +35,7 @@ nxt_bool_t nxt_var_is_const(nxt_var_t *var); nxt_int_t nxt_var_register(nxt_var_decl_t *decl, size_t n); nxt_int_t nxt_var_index_init(void); -nxt_var_t *nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp); +nxt_var_t *nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz); nxt_int_t nxt_var_test(nxt_str_t *str, u_char *error); nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, |