summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--docs/changes.xml6
-rw-r--r--src/nxt_conf_validation.c51
-rw-r--r--src/nxt_http_static.c217
3 files changed, 202 insertions, 72 deletions
diff --git a/docs/changes.xml b/docs/changes.xml
index 1e1bff0a..12f5264f 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -46,6 +46,12 @@ variables support in the "share" option.
<change type="feature">
<para>
+multiple paths in the "share" option.
+</para>
+</change>
+
+<change type="feature">
+<para>
variables support in the "chroot" option.
</para>
</change>
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 23e6d823..55107cd6 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -113,6 +113,10 @@ static nxt_int_t nxt_conf_vldt_pass(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_share(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_python(nxt_conf_validation_t *vldt,
@@ -633,8 +637,8 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_return_action_members[] = {
static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = {
{
.name = nxt_string("share"),
- .type = NXT_CONF_VLDT_STRING,
- .flags = NXT_CONF_VLDT_VAR,
+ .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
+ .validator = nxt_conf_vldt_share,
}, {
.name = nxt_string("types"),
.type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
@@ -1617,6 +1621,49 @@ nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
static nxt_int_t
+nxt_conf_vldt_share(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
+ void *data)
+{
+ if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
+ if (nxt_conf_array_elements_count(value) == 0) {
+ return nxt_conf_vldt_error(vldt, "The \"share\" array "
+ "must contain at least one element.");
+ }
+
+ return nxt_conf_vldt_array_iterator(vldt, value,
+ &nxt_conf_vldt_share_element);
+ }
+
+ /* NXT_CONF_STRING */
+
+ return nxt_conf_vldt_share_element(vldt, value);
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_share_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value)
+{
+ nxt_str_t str;
+
+ static nxt_str_t share = nxt_string("share");
+
+ if (nxt_conf_type(value) != NXT_CONF_STRING) {
+ return nxt_conf_vldt_error(vldt, "The \"share\" array must "
+ "contain only string values.");
+ }
+
+ nxt_conf_get_string(value, &str);
+
+ if (nxt_is_var(&str)) {
+ return nxt_conf_vldt_var(vldt, &share, &str);
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
void *data)
{
diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c
index c610bbf7..06e0cab2 100644
--- a/src/nxt_http_static.c
+++ b/src/nxt_http_static.c
@@ -8,14 +8,22 @@
typedef struct {
- nxt_var_t *share;
+ nxt_var_t *var;
+#if (NXT_HAVE_OPENAT2)
+ u_char *fname;
+#endif
+ uint8_t is_const; /* 1 bit */
+} nxt_http_static_share_t;
+
+
+typedef struct {
+ nxt_uint_t nshares;
+ nxt_http_static_share_t *shares;
#if (NXT_HAVE_OPENAT2)
nxt_var_t *chroot;
nxt_uint_t resolve;
- u_char *fname;
#endif
nxt_http_route_rule_t *types;
- uint8_t is_const; /* 1 bit */
} nxt_http_static_conf_t;
@@ -25,6 +33,7 @@ typedef struct {
#if (NXT_HAVE_OPENAT2)
nxt_str_t chroot;
#endif
+ uint32_t index;
uint8_t need_body; /* 1 bit */
} nxt_http_static_ctx_t;
@@ -35,8 +44,12 @@ typedef struct {
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_iterate(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_static_ctx_t *ctx);
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);
+static void nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_static_ctx_t *ctx, nxt_http_status_t status);
#if (NXT_HAVE_OPENAT2)
static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr);
#endif
@@ -60,8 +73,12 @@ nxt_int_t
nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_http_action_t *action, nxt_http_action_conf_t *acf)
{
+ uint32_t i;
nxt_mp_t *mp;
nxt_str_t str;
+ nxt_var_t *var;
+ nxt_bool_t array;
+ nxt_conf_value_t *cv;
nxt_http_static_conf_t *conf;
mp = tmcf->router_conf->mem_pool;
@@ -74,33 +91,63 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
action->handler = nxt_http_static;
action->u.conf = conf;
- nxt_conf_get_string(acf->share, &str);
+ array = (nxt_conf_type(acf->share) == NXT_CONF_ARRAY);
+ conf->nshares = array ? nxt_conf_array_elements_count(acf->share) : 1;
- conf->share = nxt_var_compile(&str, mp, 1);
- if (nxt_slow_path(conf->share == NULL)) {
+ conf->shares = nxt_mp_zget(mp, sizeof(nxt_http_static_share_t)
+ * conf->nshares);
+ if (nxt_slow_path(conf->shares == NULL)) {
return NXT_ERROR;
}
- conf->is_const = nxt_var_is_const(conf->share);
+ if (array) {
+ for (i = 0; i < conf->nshares; i++) {
+ cv = nxt_conf_get_array_element(acf->share, i);
+ nxt_conf_get_string(cv, &str);
-#if (NXT_HAVE_OPENAT2)
- if (acf->chroot.length > 0) {
- nxt_str_t chr, shr;
+ var = nxt_var_compile(&str, mp, 1);
+ if (nxt_slow_path(var == NULL)) {
+ return NXT_ERROR;
+ }
- if (nxt_is_var(&acf->chroot)) {
- conf->is_const = 0;
+ conf->shares[i].var = var;
+ conf->shares[i].is_const = nxt_var_is_const(var);
}
+ } else {
+ nxt_conf_get_string(acf->share, &str);
+
+ var = nxt_var_compile(&str, mp, 1);
+ if (nxt_slow_path(var == NULL)) {
+ return NXT_ERROR;
+ }
+
+ conf->shares[0].var = var;
+ conf->shares[0].is_const = nxt_var_is_const(var);
+ }
+
+#if (NXT_HAVE_OPENAT2)
+ if (acf->chroot.length > 0) {
+ nxt_str_t chr, shr;
+ nxt_bool_t is_const;
+
conf->chroot = nxt_var_compile(&acf->chroot, mp, 1);
if (nxt_slow_path(conf->chroot == NULL)) {
return NXT_ERROR;
}
- if (conf->is_const) {
- nxt_var_raw(conf->chroot, &chr);
- nxt_var_raw(conf->share, &shr);
+ is_const = nxt_var_is_const(conf->chroot);
+
+ for (i = 0; i < conf->nshares; i++) {
+ conf->shares[i].is_const &= is_const;
+
+ if (conf->shares[i].is_const) {
+ nxt_var_raw(conf->chroot, &chr);
+ nxt_var_raw(conf->shares[i].var, &shr);
- conf->fname = nxt_http_static_chroot_match(chr.start, shr.start);
+ conf->shares[i].fname = nxt_http_static_chroot_match(chr.start,
+ shr.start);
+ }
}
}
@@ -142,10 +189,8 @@ static nxt_http_action_t *
nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
- nxt_int_t ret;
- nxt_bool_t need_body;
- nxt_http_static_ctx_t *ctx;
- nxt_http_static_conf_t *conf;
+ nxt_bool_t need_body;
+ nxt_http_static_ctx_t *ctx;
if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
@@ -164,12 +209,37 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
need_body = 1;
}
- conf = action->u.conf;
+ ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t));
+ if (nxt_slow_path(ctx == NULL)) {
+ nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
+ return NULL;
+ }
+
+ ctx->action = action;
+ ctx->need_body = need_body;
+
+ nxt_http_static_iterate(task, r, ctx);
+
+ return NULL;
+}
+
+
+static void
+nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_static_ctx_t *ctx)
+{
+ nxt_int_t ret;
+ nxt_http_static_conf_t *conf;
+ nxt_http_static_share_t *share;
+
+ conf = ctx->action->u.conf;
+
+ share = &conf->shares[ctx->index];
#if (NXT_DEBUG)
nxt_str_t shr;
- nxt_var_raw(conf->share, &shr);
+ nxt_var_raw(share->var, &shr);
#if (NXT_HAVE_OPENAT2)
nxt_str_t chr;
@@ -187,19 +257,11 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
#endif
#endif /* NXT_DEBUG */
- 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) {
- nxt_var_raw(conf->share, &ctx->share);
+ if (share->is_const) {
+ nxt_var_raw(share->var, &ctx->share);
#if (NXT_HAVE_OPENAT2)
- if (conf->chroot != NULL) {
+ if (conf->chroot != NULL && ctx->index == 0) {
nxt_var_raw(conf->chroot, &ctx->chroot);
}
#endif
@@ -209,13 +271,14 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
} else {
ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
if (nxt_slow_path(ret != NXT_OK)) {
- goto fail;
+ nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
+ return;
}
- nxt_var_query(task, r->var_query, conf->share, &ctx->share);
+ nxt_var_query(task, r->var_query, share->var, &ctx->share);
#if (NXT_HAVE_OPENAT2)
- if (conf->chroot != NULL) {
+ if (conf->chroot != NULL && ctx->index == 0) {
nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot);
}
#endif
@@ -223,14 +286,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
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;
+ }
}
@@ -255,7 +311,7 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
nxt_http_static_ctx_t *ctx;
nxt_http_static_conf_t *conf;
- static nxt_str_t index = nxt_string("index.html");
+ static const nxt_str_t index = nxt_string("index.html");
r = obj;
ctx = data;
@@ -300,8 +356,8 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
}
if (ret == 0) {
- status = NXT_HTTP_FORBIDDEN;
- goto fail;
+ nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN);
+ return;
}
}
@@ -314,8 +370,11 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
#if (NXT_HAVE_OPENAT2)
if (conf->resolve != 0 || ctx->chroot.length > 0) {
- nxt_str_t *chr;
- nxt_uint_t resolve;
+ nxt_str_t *chr;
+ nxt_uint_t resolve;
+ nxt_http_static_share_t *share;
+
+ share = &conf->shares[ctx->index];
resolve = conf->resolve;
chr = &ctx->chroot;
@@ -323,8 +382,8 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
if (chr->length > 0) {
resolve |= RESOLVE_IN_ROOT;
- fname = conf->is_const
- ? conf->fname
+ fname = share->is_const
+ ? share->fname
: nxt_http_static_chroot_match(chr->start, file.name);
if (fname != NULL) {
@@ -407,10 +466,6 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
break;
}
- if (level == NXT_LOG_ERR && action->fallback != NULL) {
- goto fail;
- }
-
if (status != NXT_HTTP_NOT_FOUND) {
#if (NXT_HAVE_OPENAT2)
nxt_str_t *chr = &ctx->chroot;
@@ -429,6 +484,11 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
#endif
}
+ if (level == NXT_LOG_ERR) {
+ nxt_http_static_next(task, r, ctx, status);
+ return;
+ }
+
goto fail;
}
@@ -525,18 +585,16 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
} else {
/* Not a file. */
+ nxt_file_close(task, f);
if (nxt_slow_path(!nxt_is_dir(&fi))) {
- 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);
- status = NXT_HTTP_NOT_FOUND;
- goto fail;
+ nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND);
+ return;
}
- nxt_file_close(task, f);
f = NULL;
r->status = NXT_HTTP_MOVED_PERMANENTLY;
@@ -592,14 +650,7 @@ fail:
nxt_file_close(task, f);
}
- 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);
+ nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
}
@@ -614,6 +665,32 @@ nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data)
}
+static void
+nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_static_ctx_t *ctx, nxt_http_status_t status)
+{
+ nxt_http_action_t *action;
+ nxt_http_static_conf_t *conf;
+
+ action = ctx->action;
+ conf = action->u.conf;
+
+ ctx->index++;
+
+ if (ctx->index < conf->nshares) {
+ nxt_http_static_iterate(task, r, ctx);
+ return;
+ }
+
+ if (action->fallback != NULL) {
+ nxt_http_request_action(task, r, action->fallback);
+ return;
+ }
+
+ nxt_http_request_error(task, r, status);
+}
+
+
#if (NXT_HAVE_OPENAT2)
static u_char *