summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--docs/changes.xml6
-rw-r--r--src/nxt_conf_validation.c39
-rw-r--r--src/nxt_http_route.c4
-rw-r--r--src/nxt_http_static.c299
-rw-r--r--src/nxt_var.c20
-rw-r--r--src/nxt_var.h2
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,