diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 8f31bd18f..5d7f7c52b 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -696,6 +696,10 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { .type = NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, .validator = nxt_conf_vldt_match_patterns_sets, .u.string = "cookies" + }, { + .name = nxt_string("if"), + .type = NXT_CONF_VLDT_STRING, + .validator = nxt_conf_vldt_if, }, NXT_CONF_VLDT_END diff --git a/src/nxt_http.h b/src/nxt_http.h index fe5e72a87..5369c8e16 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -441,6 +441,9 @@ void nxt_h1p_complete_buffers(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_bool_t all); nxt_msec_t nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data); +int nxt_http_cond_value(nxt_task_t *task, nxt_http_request_t *r, + nxt_tstr_cond_t *cond); + extern const nxt_conn_state_t nxt_h1p_idle_close_state; #endif /* _NXT_HTTP_H_INCLUDED_ */ diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 54d1bd27e..a7e9ff69a 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -24,8 +24,6 @@ static void nxt_http_request_proto_info(nxt_task_t *task, static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); -static nxt_int_t nxt_http_request_access_log(nxt_task_t *task, - nxt_http_request_t *r, nxt_router_conf_t *rtcf); static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, const char *format); @@ -861,12 +859,12 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) void nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) { - nxt_int_t ret; nxt_http_proto_t proto; nxt_router_conf_t *rtcf; nxt_http_request_t *r; nxt_http_protocol_t protocol; nxt_socket_conf_joint_t *conf; + nxt_router_access_log_t *access_log; r = obj; proto.any = data; @@ -878,8 +876,10 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) r->logged = 1; if (rtcf->access_log != NULL) { - ret = nxt_http_request_access_log(task, r, rtcf); - if (ret == NXT_OK) { + access_log = rtcf->access_log; + + if (nxt_http_cond_value(task, r, &rtcf->log_cond)) { + access_log->handler(task, r, access_log, rtcf->log_format); return; } } @@ -911,57 +911,6 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) } -static nxt_int_t -nxt_http_request_access_log(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_conf_t *rtcf) -{ - nxt_int_t ret; - nxt_str_t str; - nxt_bool_t expr; - nxt_router_access_log_t *access_log; - - access_log = rtcf->access_log; - - expr = 1; - - if (rtcf->log_expr != NULL) { - - if (nxt_tstr_is_const(rtcf->log_expr)) { - nxt_tstr_str(rtcf->log_expr, &str); - - } else { - ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, - &r->tstr_cache, r, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_DECLINED; - } - - nxt_tstr_query(task, r->tstr_query, rtcf->log_expr, &str); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { - return NXT_DECLINED; - } - } - - if (str.length == 0 - || nxt_str_eq(&str, "0", 1) - || nxt_str_eq(&str, "false", 5) - || nxt_str_eq(&str, "null", 4) - || nxt_str_eq(&str, "undefined", 9)) - { - expr = 0; - } - } - - if (rtcf->log_negate ^ expr) { - access_log->handler(task, r, access_log, rtcf->log_format); - return NXT_OK; - } - - return NXT_DECLINED; -} - - static u_char * nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, const char *format) @@ -1365,3 +1314,48 @@ nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name) { return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE); } + + +int +nxt_http_cond_value(nxt_task_t *task, nxt_http_request_t *r, + nxt_tstr_cond_t *cond) +{ + nxt_int_t ret; + nxt_str_t str; + nxt_bool_t expr; + nxt_router_conf_t *rtcf; + + rtcf = r->conf->socket_conf->router_conf; + + expr = 1; + + if (cond->expr != NULL) { + + if (nxt_tstr_is_const(cond->expr)) { + nxt_tstr_str(cond->expr, &str); + + } else { + ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, + &r->tstr_cache, r, r->mem_pool); + if (nxt_slow_path(ret != NXT_OK)) { + return -1; + } + + ret = nxt_tstr_query(task, r->tstr_query, cond->expr, &str); + if (nxt_slow_path(ret != NXT_OK)) { + return -1; + } + } + + if (str.length == 0 + || nxt_str_eq(&str, "0", 1) + || nxt_str_eq(&str, "false", 5) + || nxt_str_eq(&str, "null", 4) + || nxt_str_eq(&str, "undefined", 9)) + { + expr = 0; + } + } + + return cond->negate ^ expr; +} diff --git a/src/nxt_http_return.c b/src/nxt_http_return.c index b50e4ad0e..a3551683e 100644 --- a/src/nxt_http_return.c +++ b/src/nxt_http_return.c @@ -24,8 +24,8 @@ static nxt_http_action_t *nxt_http_return(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *action); static nxt_int_t nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded, const nxt_str_t *location); -static void nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_return_send_error(nxt_task_t *task, void *obj, void *data); +static void nxt_http_return_send(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_return_ctx_t *ctx); static const nxt_http_request_state_t nxt_http_return_send_state; @@ -120,8 +120,6 @@ nxt_http_return(nxt_task_t *task, nxt_http_request_t *r, ctx->encoded = conf->encoded; } - nxt_http_return_send_ready(task, r, ctx); - } else { rtcf = r->conf->socket_conf->router_conf; @@ -131,13 +129,15 @@ nxt_http_return(nxt_task_t *task, nxt_http_request_t *r, goto fail; } - nxt_tstr_query(task, r->tstr_query, conf->location, &ctx->location); - - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_http_return_send_ready, - nxt_http_return_send_error); + ret = nxt_tstr_query(task, r->tstr_query, conf->location, + &ctx->location); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } } + nxt_http_return_send(task, r, ctx); + return NULL; fail: @@ -174,15 +174,11 @@ nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded, static void -nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data) +nxt_http_return_send(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_return_ctx_t *ctx) { - nxt_int_t ret; - nxt_http_field_t *field; - nxt_http_request_t *r; - nxt_http_return_ctx_t *ctx; - - r = obj; - ctx = data; + nxt_int_t ret; + nxt_http_field_t *field; if (ctx != NULL) { if (ctx->location.length > 0) { @@ -216,17 +212,6 @@ nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data) } -static void -nxt_http_return_send_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); -} - - static const nxt_http_request_state_t nxt_http_return_send_state nxt_aligned(64) = { diff --git a/src/nxt_http_rewrite.c b/src/nxt_http_rewrite.c index 661200efe..5de15ed7c 100644 --- a/src/nxt_http_rewrite.c +++ b/src/nxt_http_rewrite.c @@ -52,9 +52,8 @@ nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r) return NXT_ERROR; } - nxt_tstr_query(task, r->tstr_query, action->rewrite, &str); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { + ret = nxt_tstr_query(task, r->tstr_query, action->rewrite, &str); + if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } } diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 852f57397..bd0646f3b 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -51,6 +51,7 @@ typedef struct { nxt_conf_value_t *query; nxt_conf_value_t *source; nxt_conf_value_t *destination; + nxt_conf_value_t *condition; } nxt_http_route_match_conf_t; @@ -138,6 +139,7 @@ typedef union { typedef struct { uint32_t items; + nxt_tstr_cond_t condition; nxt_http_action_t action; nxt_http_route_test_t test[]; } nxt_http_route_match_t; @@ -193,8 +195,8 @@ static nxt_int_t nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action); static nxt_http_action_t *nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *action); -static void nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data); -static void nxt_http_pass_query_error(nxt_task_t *task, void *obj, void *data); +static void nxt_http_pass_query(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_action_t *action); static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass, nxt_http_action_t *action); static nxt_int_t nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name, @@ -350,6 +352,12 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = { NXT_CONF_MAP_PTR, offsetof(nxt_http_route_match_conf_t, destination), }, + + { + nxt_string("if"), + NXT_CONF_MAP_PTR, + offsetof(nxt_http_route_match_conf_t, condition), + }, }; @@ -397,7 +405,9 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, uint32_t n; nxt_mp_t *mp; nxt_int_t ret; - nxt_conf_value_t *match_conf, *action_conf; + nxt_str_t str; + nxt_conf_value_t *match_conf, *action_conf, *condition; + nxt_router_conf_t *rtcf; nxt_http_route_test_t *test; nxt_http_route_rule_t *rule; nxt_http_route_table_t *table; @@ -405,6 +415,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_route_addr_rule_t *addr_rule; nxt_http_route_match_conf_t mtcf; + static const nxt_str_t if_path = nxt_string("/if"); static const nxt_str_t match_path = nxt_string("/match"); static const nxt_str_t action_path = nxt_string("/action"); @@ -413,9 +424,21 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_test_t *); - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; + + condition = NULL; + + if (match_conf != NULL) { + condition = nxt_conf_get_path(match_conf, &if_path); - match = nxt_mp_alloc(mp, size); + if (condition != NULL) { + n--; + size -= sizeof(nxt_http_route_test_t *); + } + } + + match = nxt_mp_zalloc(mp, size); if (nxt_slow_path(match == NULL)) { return NULL; } @@ -432,7 +455,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } - if (n == 0) { + if (n == 0 && condition == NULL) { return match; } @@ -445,6 +468,15 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } + if (condition != NULL) { + nxt_conf_get_string(condition, &str); + + ret = nxt_tstr_cond_compile(rtcf->tstr_state, &str, &match->condition); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + test = &match->test[0]; if (mtcf.scheme != NULL) { @@ -1344,10 +1376,13 @@ nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r, action->u.pass = nxt_pointer_to(action, sizeof(nxt_http_action_t)); - nxt_tstr_query(task, r->tstr_query, tstr, action->u.pass); - nxt_tstr_query_resolve(task, r->tstr_query, action, - nxt_http_pass_query_ready, - nxt_http_pass_query_error); + ret = nxt_tstr_query(task, r->tstr_query, tstr, action->u.pass); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + nxt_http_pass_query(task, r, action); + return NULL; fail: @@ -1358,16 +1393,13 @@ nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r, static void -nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data) +nxt_http_pass_query(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_action_t *action) { - nxt_int_t ret; - nxt_router_conf_t *rtcf; - nxt_http_action_t *action; - nxt_http_status_t status; - nxt_http_request_t *r; - - r = obj; - action = data; + nxt_int_t ret; + nxt_router_conf_t *rtcf; + nxt_http_status_t status; + rtcf = r->conf->socket_conf->router_conf; nxt_debug(task, "http pass lookup: %V", action->u.pass); @@ -1386,17 +1418,6 @@ nxt_http_pass_query_ready(nxt_task_t *task, void *obj, void *data) } -static void -nxt_http_pass_query_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); -} - - static nxt_int_t nxt_http_pass_find(nxt_mp_t *mp, nxt_router_conf_t *rtcf, nxt_str_t *pass, nxt_http_action_t *action) @@ -1607,6 +1628,12 @@ nxt_http_route_match(nxt_task_t *task, nxt_http_request_t *r, nxt_int_t ret; nxt_http_route_test_t *test, *end; + ret = nxt_http_cond_value(task, r, &match->condition); + if (ret <= 0) { + /* 0 => NULL, -1 => NXT_HTTP_ACTION_ERROR. */ + return (nxt_http_action_t *) (intptr_t) ret; + } + test = &match->test[0]; end = test + match->items; diff --git a/src/nxt_http_set_headers.c b/src/nxt_http_set_headers.c index 25dd7478f..7fd6aba52 100644 --- a/src/nxt_http_set_headers.c +++ b/src/nxt_http_set_headers.c @@ -139,9 +139,8 @@ nxt_http_set_headers(nxt_http_request_t *r) return NXT_ERROR; } - nxt_tstr_query(&r->task, r->tstr_query, hv->value, &value[i]); - - if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) { + ret = nxt_tstr_query(&r->task, r->tstr_query, hv->value, &value[i]); + if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } } diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c index ee25015e2..67591595a 100644 --- a/src/nxt_http_static.c +++ b/src/nxt_http_static.c @@ -47,8 +47,8 @@ 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_send_error(nxt_task_t *task, void *obj, void *data); +static void nxt_http_static_send(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_static_ctx_t *ctx); 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) @@ -271,35 +271,44 @@ nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, } #endif - nxt_http_static_send_ready(task, r, ctx); - } else { rtcf = r->conf->socket_conf->router_conf; ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, &r->tstr_cache, r, r->mem_pool); if (nxt_slow_path(ret != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return; + goto fail; } - nxt_tstr_query(task, r->tstr_query, share->tstr, &ctx->share); + ret = nxt_tstr_query(task, r->tstr_query, share->tstr, &ctx->share); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } #if (NXT_HAVE_OPENAT2) if (conf->chroot != NULL && ctx->share_idx == 0) { - nxt_tstr_query(task, r->tstr_query, conf->chroot, &ctx->chroot); + ret = nxt_tstr_query(task, r->tstr_query, conf->chroot, + &ctx->chroot); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } } #endif + } + + nxt_http_static_send(task, r, ctx); + + return; + +fail: - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_http_static_send_ready, - nxt_http_static_send_error); - } + nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); } static void -nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) +nxt_http_static_send(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_static_ctx_t *ctx) { size_t length, encode; u_char *p, *fname; @@ -314,13 +323,9 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) 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; rtcf = r->conf->socket_conf->router_conf; @@ -662,17 +667,6 @@ nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) } -static void -nxt_http_static_send_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); -} - - 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) diff --git a/src/nxt_router.h b/src/nxt_router.h index cfc7258c5..06c6bb32a 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -54,8 +54,7 @@ typedef struct { nxt_router_access_log_t *access_log; nxt_tstr_t *log_format; - nxt_tstr_t *log_expr; - uint8_t log_negate; /* 1 bit */ + nxt_tstr_cond_t log_cond; } nxt_router_conf_t; diff --git a/src/nxt_router_access_log.c b/src/nxt_router_access_log.c index ff17b0b68..afecd0b13 100644 --- a/src/nxt_router_access_log.c +++ b/src/nxt_router_access_log.c @@ -26,10 +26,8 @@ typedef struct { static void nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, nxt_router_access_log_t *access_log, nxt_tstr_t *format); -static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj, - void *data); +static void nxt_router_access_log_write(nxt_task_t *task, nxt_http_request_t *r, + nxt_router_access_log_ctx_t *ctx); static void nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); static void nxt_router_access_log_error(nxt_task_t *task, @@ -145,15 +143,8 @@ nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf, if (alcf.expr != NULL) { nxt_conf_get_string(alcf.expr, &str); - if (str.length > 0 && str.start[0] == '!') { - rtcf->log_negate = 1; - - str.start++; - str.length--; - } - - rtcf->log_expr = nxt_tstr_compile(rtcf->tstr_state, &str, 0); - if (nxt_slow_path(rtcf->log_expr == NULL)) { + ret = nxt_tstr_cond_compile(rtcf->tstr_state, &str, &rtcf->log_cond); + if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } } @@ -180,8 +171,6 @@ nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, if (nxt_tstr_is_const(format)) { nxt_tstr_str(format, &ctx->text); - nxt_router_access_log_write_ready(task, r, ctx); - } else { rtcf = r->conf->socket_conf->router_conf; @@ -191,36 +180,26 @@ nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, return; } - nxt_tstr_query(task, r->tstr_query, format, &ctx->text); - nxt_tstr_query_resolve(task, r->tstr_query, ctx, - nxt_router_access_log_write_ready, - nxt_router_access_log_write_error); - } + ret = nxt_tstr_query(task, r->tstr_query, format, &ctx->text); + if (nxt_slow_path(ret != NXT_OK)) { + return; + } + } + + nxt_router_access_log_write(task, r, ctx); } static void -nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data) +nxt_router_access_log_write(nxt_task_t *task, nxt_http_request_t *r, + nxt_router_access_log_ctx_t *ctx) { - nxt_http_request_t *r; - nxt_router_access_log_ctx_t *ctx; - - r = obj; - ctx = data; - nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length); nxt_http_request_close_handler(task, r, r->proto.any); } -static void -nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data) -{ - -} - - void nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) { diff --git a/src/nxt_tstr.c b/src/nxt_tstr.c index 6f39cff28..50df4c475 100644 --- a/src/nxt_tstr.c +++ b/src/nxt_tstr.c @@ -36,14 +36,8 @@ struct nxt_tstr_query_s { nxt_tstr_state_t *state; nxt_tstr_cache_t *cache; - nxt_uint_t waiting; - nxt_uint_t failed; /* 1 bit */ - void *ctx; void *data; - - nxt_work_handler_t ready; - nxt_work_handler_t error; }; @@ -202,6 +196,26 @@ nxt_tstr_state_release(nxt_tstr_state_t *state) } +nxt_int_t +nxt_tstr_cond_compile(nxt_tstr_state_t *state, nxt_str_t *str, + nxt_tstr_cond_t *cond) +{ + if (str->length > 0 && str->start[0] == '!') { + cond->negate = 1; + + str->start++; + str->length--; + } + + cond->expr = nxt_tstr_compile(state, str, 0); + if (nxt_slow_path(cond->expr == NULL)) { + return NXT_ERROR; + } + + return NXT_OK; +} + + nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr) { @@ -246,7 +260,7 @@ nxt_tstr_query_init(nxt_tstr_query_t **query_p, nxt_tstr_state_t *state, } -void +nxt_int_t nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, nxt_str_t *val) { @@ -254,11 +268,7 @@ nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, if (nxt_tstr_is_const(tstr)) { nxt_tstr_str(tstr, val); - return; - } - - if (nxt_slow_path(query->failed)) { - return; + return NXT_OK; } if (tstr->type == NXT_TSTR_VAR) { @@ -267,8 +277,7 @@ nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, tstr->flags & NXT_TSTR_LOGGING); if (nxt_slow_path(ret != NXT_OK)) { - query->failed = 1; - return; + return NXT_ERROR; } } else { @@ -277,8 +286,7 @@ nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, tstr->u.js, val, query->ctx); if (nxt_slow_path(ret != NXT_OK)) { - query->failed = 1; - return; + return NXT_ERROR; } #endif } @@ -294,43 +302,8 @@ nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, nxt_debug(task, "tstr query: \"%V\", result: \"%V\"", &str, val); #endif -} - - -nxt_bool_t -nxt_tstr_query_failed(nxt_tstr_query_t *query) -{ - return query->failed; -} - -void -nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, void *data, - nxt_work_handler_t ready, nxt_work_handler_t error) -{ - query->data = data; - query->ready = ready; - query->error = error; - - if (query->waiting == 0) { - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - query->failed ? query->error : query->ready, - task, query->ctx, query->data); - } -} - - -void -nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, - nxt_bool_t failed) -{ - query->failed |= failed; - - if (--query->waiting == 0) { - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - query->failed ? query->error : query->ready, - task, query->ctx, query->data); - } + return NXT_OK; } diff --git a/src/nxt_tstr.h b/src/nxt_tstr.h index a156732dd..aca74e20c 100644 --- a/src/nxt_tstr.h +++ b/src/nxt_tstr.h @@ -37,12 +37,20 @@ typedef enum { } nxt_tstr_flags_t; +typedef struct { + nxt_tstr_t *expr; + uint8_t negate; /* 1 bit */ +} nxt_tstr_cond_t; + + nxt_tstr_state_t *nxt_tstr_state_new(nxt_mp_t *mp, nxt_bool_t test); nxt_tstr_t *nxt_tstr_compile(nxt_tstr_state_t *state, const nxt_str_t *str, nxt_tstr_flags_t flags); nxt_int_t nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error); nxt_int_t nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error); void nxt_tstr_state_release(nxt_tstr_state_t *state); +nxt_int_t nxt_tstr_cond_compile(nxt_tstr_state_t *state, nxt_str_t *str, + nxt_tstr_cond_t *cond); nxt_bool_t nxt_tstr_is_const(nxt_tstr_t *tstr); void nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str); @@ -50,13 +58,8 @@ void nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str); nxt_int_t nxt_tstr_query_init(nxt_tstr_query_t **query_p, nxt_tstr_state_t *state, nxt_tstr_cache_t *cache, void *ctx, nxt_mp_t *mp); -void nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr, - nxt_str_t *val); -nxt_bool_t nxt_tstr_query_failed(nxt_tstr_query_t *query); -void nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, - void *data, nxt_work_handler_t ready, nxt_work_handler_t error); -void nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query, - nxt_bool_t failed); +nxt_int_t nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, + nxt_tstr_t *tstr, nxt_str_t *val); void nxt_tstr_query_release(nxt_tstr_query_t *query); diff --git a/src/nxt_var.c b/src/nxt_var.c index 94d10cd85..16aa1c7ed 100644 --- a/src/nxt_var.c +++ b/src/nxt_var.c @@ -30,14 +30,8 @@ struct nxt_var_query_s { nxt_var_cache_t cache; - nxt_uint_t waiting; - nxt_uint_t failed; /* 1 bit */ - void *ctx; void *data; - - nxt_work_handler_t ready; - nxt_work_handler_t error; }; diff --git a/test/test_routing.py b/test/test_routing.py index 0b6eced27..c419779a0 100644 --- a/test/test_routing.py +++ b/test/test_routing.py @@ -2009,3 +2009,60 @@ def test_routes_match_destination_proxy(): ), 'proxy configure' assert client.get()['status'] == 200, 'proxy' + + +def test_routes_match_if(): + + def set_if(condition): + assert 'success' in client.conf(f'"{condition}"', 'routes/0/match/if') + + def try_if(condition, status): + set_if(condition) + assert client.get(url=f'/{condition}')['status'] == status + + assert 'success' in client.conf( + { + "listeners": {"*:8080": {"pass": "routes"}}, + "routes": [ + { + "match": {"method": "GET"}, + "action": {"return": 200}, + } + ], + "applications": {}, + } + ), 'routing configure' + + # const + + try_if('', 404) + try_if('0', 404) + try_if('false', 404) + try_if('undefined', 404) + try_if('!', 200) + try_if('!null', 200) + try_if('1', 200) + + # variable + + set_if('$arg_foo') + assert client.get(url='/bar?bar')['status'] == 404 + assert client.get(url='/foo_empty?foo')['status'] == 404 + assert client.get(url='/foo?foo=1')['status'] == 200 + + set_if('!$arg_foo') + assert client.get(url='/bar?bar')['status'] == 200 + assert client.get(url='/foo_empty?foo')['status'] == 200 + assert client.get(url='/foo?foo=1')['status'] == 404 + + # njs + + set_if('`${args.foo == \'1\'}`') + assert client.get(url='/foo_1?foo=1')['status'] == 200 + assert client.get(url='/foo_2?foo=2')['status'] == 404 + + set_if('!`${args.foo == \'1\'}`') + assert client.get(url='/foo_1?foo=1')['status'] == 404 + assert client.get(url='/foo_2?foo=2')['status'] == 200 + + assert 'error' in client.conf('$arg_', 'routes/0/match/if')