Static: variables in the "chroot" option.

This commit is contained in:
Zhidao HONG
2021-09-28 23:08:26 +08:00
parent 2fc64c65bc
commit 37144d6849
6 changed files with 275 additions and 95 deletions

View File

@@ -31,6 +31,12 @@ NGINX Unit updated to 1.26.0.
date="" time="" date="" time=""
packager="Andrei Belov <defan@nginx.com>"> packager="Andrei Belov <defan@nginx.com>">
<change type="feature">
<para>
variables support in the "chroot" option.
</para>
</change>
<change type="bugfix"> <change type="bugfix">
<para> <para>
fixed building with glibc 2.34, notably Fedora 35. fixed building with glibc 2.34, notably Fedora 35.

View File

@@ -33,7 +33,8 @@ typedef enum {
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; } 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); 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, static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
const char *fmt, ...); const char *fmt, ...);
static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, static nxt_int_t nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name,
const char *option, nxt_str_t *value); nxt_str_t *value);
nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_inline nxt_int_t nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data); 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"), .name = nxt_string("pass"),
.type = NXT_CONF_VLDT_STRING, .type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_pass, .validator = nxt_conf_vldt_pass,
.flags = NXT_CONF_VLDT_VAR,
}, { }, {
.name = nxt_string("application"), .name = nxt_string("application"),
.type = NXT_CONF_VLDT_STRING, .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"), .name = nxt_string("pass"),
.type = NXT_CONF_VLDT_STRING, .type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_pass, .validator = nxt_conf_vldt_pass,
.flags = NXT_CONF_VLDT_VAR,
}, },
NXT_CONF_VLDT_END 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, .validator = nxt_conf_vldt_unsupported,
.u.string = "chroot", .u.string = "chroot",
#endif #endif
.flags = NXT_CONF_VLDT_VAR,
}, { }, {
.name = nxt_string("follow_symlinks"), .name = nxt_string("follow_symlinks"),
.type = NXT_CONF_VLDT_BOOLEAN, .type = NXT_CONF_VLDT_BOOLEAN,
@@ -1163,7 +1167,6 @@ nxt_conf_validate(nxt_conf_validation_t *vldt)
nxt_int_t ret; nxt_int_t ret;
ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
if (ret != NXT_OK) { if (ret != NXT_OK) {
return ret; return ret;
} }
@@ -1290,14 +1293,14 @@ nxt_conf_vldt_unsupported(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
static nxt_int_t 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) nxt_str_t *value)
{ {
u_char error[NXT_MAX_ERROR_STR]; u_char error[NXT_MAX_ERROR_STR];
if (nxt_var_test(value, error) != NXT_OK) { if (nxt_var_test(value, error) != NXT_OK) {
return nxt_conf_vldt_error(vldt, "%s in the \"%s\" value.", return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.",
error, option); error, name);
} }
return NXT_OK; 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); 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); ret = nxt_http_pass_segments(vldt->pool, &pass, segments, 3);
if (ret != NXT_OK) { 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; uint32_t index;
nxt_int_t ret; nxt_int_t ret;
nxt_str_t name; nxt_str_t name, var;
nxt_conf_value_t *member; nxt_conf_value_t *member;
nxt_conf_vldt_object_t *vals; 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; 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) { if (ret != NXT_OK) {
return ret; return ret;
} }

View File

@@ -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); 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)) { if (nxt_slow_path(action->u.var == NULL)) {
return NXT_ERROR; return NXT_ERROR;
} }
@@ -1603,7 +1603,7 @@ nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
return NULL; 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)) { if (nxt_slow_path(action->u.var == NULL)) {
return NULL; return NULL;
} }

View File

@@ -9,18 +9,35 @@
typedef struct { typedef struct {
nxt_str_t share; nxt_str_t share;
nxt_str_t chroot; #if (NXT_HAVE_OPENAT2)
nxt_var_t *chroot;
nxt_uint_t resolve; nxt_uint_t resolve;
#endif
nxt_http_route_rule_t *types; nxt_http_route_rule_t *types;
uint8_t is_const; /* 1 bit */
} nxt_http_static_conf_t; } 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_COUNT 2
#define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) #define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024)
static nxt_http_action_t *nxt_http_static(nxt_task_t *task, static nxt_http_action_t *nxt_http_static(nxt_task_t *task,
nxt_http_request_t *r, nxt_http_action_t *action); 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, static void nxt_http_static_extract_extension(nxt_str_t *path,
nxt_str_t *exten); nxt_str_t *exten);
static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 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; return NXT_ERROR;
} }
conf->is_const = 1;
#if (NXT_HAVE_OPENAT2) #if (NXT_HAVE_OPENAT2)
if (acf->chroot.length > 0) { if (acf->chroot.length > 0) {
u_char *p; if (nxt_is_var(&acf->chroot)) {
nxt_str_t slash; conf->is_const = 0;
if (acf->chroot.start[acf->chroot.length - 1] != '/') {
nxt_str_set(&slash, "/");
} else {
nxt_str_set(&slash, "");
} }
value.length = acf->chroot.length + slash.length; conf->chroot = nxt_var_compile(&acf->chroot, mp, 1);
if (nxt_slow_path(conf->chroot == NULL)) {
value.start = nxt_mp_alloc(mp, value.length + 1);
if (nxt_slow_path(value.start == NULL)) {
return NXT_ERROR; 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 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_static(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action) 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_int_t ret;
nxt_str_t index, exten, *mtype, *chroot;
nxt_uint_t level;
nxt_bool_t need_body; nxt_bool_t need_body;
nxt_file_t *f, file; nxt_http_static_ctx_t *ctx;
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_conf_t *conf; 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_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
if (!nxt_str_eq(r->method, "HEAD", 4)) { 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; 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] == '/') { if (r->path->start[r->path->length - 1] == '/') {
/* TODO: dynamic index setting. */ /* TODO: dynamic index setting. */
nxt_str_set(&index, "index.html"); nxt_str_set(&index, "index.html");
@@ -176,6 +249,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
} }
f = NULL; f = NULL;
status = NXT_HTTP_INTERNAL_SERVER_ERROR;
rtcf = r->conf->socket_conf->router_conf; 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 (ret == 0) {
if (action->fallback != NULL) { status = NXT_HTTP_FORBIDDEN;
return action->fallback; goto fail;
}
nxt_http_request_error(task, r, NXT_HTTP_FORBIDDEN);
return NULL;
} }
} }
@@ -218,18 +288,21 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
file.name = fname; file.name = fname;
chroot = &conf->chroot;
#if (NXT_HAVE_OPENAT2) #if (NXT_HAVE_OPENAT2)
if (conf->resolve != 0) { if (conf->resolve != 0 || ctx->chroot.length > 0) {
nxt_str_t *chr;
nxt_uint_t resolve;
if (chroot->length > 0) { resolve = conf->resolve;
file.name = chroot->start; chr = &ctx->chroot;
if (length > chroot->length if (chr->length > 0) {
&& nxt_memcmp(fname, chroot->start, chroot->length) == 0) resolve |= RESOLVE_IN_ROOT;
{
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, ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN,
0); 0);
@@ -256,7 +329,7 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
file.name = fname; file.name = fname;
ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, 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) { if (af.fd != AT_FDCWD) {
nxt_file_close(task, &af); 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) { if (level == NXT_LOG_ERR && action->fallback != NULL) {
return action->fallback; goto fail;
} }
if (status != NXT_HTTP_NOT_FOUND) { 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", nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E",
fname, chroot, file.error); fname, chr, file.error);
} else { } else {
nxt_log(task, level, "opening \"%s\" failed %E", nxt_log(task, level, "opening \"%s\" failed %E",
fname, file.error); fname, file.error);
} }
#else
nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error);
#endif
} }
nxt_http_request_error(task, r, status); goto fail;
return NULL;
} }
f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); 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; 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); fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE);
if (nxt_slow_path(fb == NULL)) { if (nxt_slow_path(fb == NULL)) {
goto fail; goto fail;
@@ -421,20 +500,17 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
} else { } else {
/* Not a file. */ /* Not a file. */
nxt_file_close(task, f);
if (nxt_slow_path(!nxt_is_dir(&fi))) { if (nxt_slow_path(!nxt_is_dir(&fi))) {
if (action->fallback != NULL) { if (action->fallback == NULL) {
return action->fallback;
}
nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file",
f->name); 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; f = NULL;
r->status = NXT_HTTP_MOVED_PERMANENTLY; r->status = NXT_HTTP_MOVED_PERMANENTLY;
@@ -482,20 +558,93 @@ nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_request_header_send(task, r, body_handler, NULL); nxt_http_request_header_send(task, r, body_handler, NULL);
r->state = &nxt_http_static_send_state; r->state = &nxt_http_static_send_state;
return NULL; return;
fail: fail:
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
if (f != NULL) { if (f != NULL) {
nxt_file_close(task, f); 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 static void
nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten)
{ {

View File

@@ -9,6 +9,7 @@
struct nxt_var_s { struct nxt_var_s {
size_t length; size_t length;
nxt_uint_t vars; nxt_uint_t vars;
uint8_t strz; /* 1 bit */
u_char data[]; u_char data[];
/* /*
@@ -229,7 +230,7 @@ nxt_var_index_init(void)
nxt_var_t * 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; u_char *p, *end, *next, *src;
size_t size; 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; 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)) { if (nxt_slow_path(var == NULL)) {
return NULL; return NULL;
} }
var->length = str->length; var->length = str->length;
var->vars = n; var->vars = n;
var->strz = strz;
subs = nxt_var_subs(var); subs = nxt_var_subs(var);
src = nxt_var_raw_start(var); src = nxt_var_raw_start(var);
nxt_memcpy(src, str->start, str->length); nxt_memcpy(src, str->start, str->length);
if (strz) {
src[str->length] = '\0';
}
n = 0; n = 0;
p = str->start; 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; 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)) { if (nxt_slow_path(p == NULL)) {
query->failed = 1; query->failed = 1;
goto done; goto done;
@@ -612,10 +618,16 @@ nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query)
} }
if (last != var->length) { 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_array_reset(&query->parts);
nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, val[i].value);
} }
done: done:

View File

@@ -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_register(nxt_var_decl_t *decl, size_t n);
nxt_int_t nxt_var_index_init(void); 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_test(nxt_str_t *str, u_char *error);
nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx,