summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorZhidao HONG <z.hong@f5.com>2023-04-20 23:20:41 +0800
committerZhidao HONG <z.hong@f5.com>2023-04-20 23:20:41 +0800
commit14d6d97bacf9b06ba340ebd4211b2f1b6ad417dd (patch)
tree68dd559c475cc0dffdf1254c75971fcae9a89ed5
parent8843e30e8275aa70bf7eec11709cd5d12e32b4ae (diff)
downloadunit-14d6d97bacf9b06ba340ebd4211b2f1b6ad417dd.tar.gz
unit-14d6d97bacf9b06ba340ebd4211b2f1b6ad417dd.tar.bz2
HTTP: added basic URI rewrite.
This commit introduced the basic URI rewrite. It allows users to change request URI. Note the "rewrite" option ignores the contained query if any and the query from the request is preserverd. An example: "routes": [ { "match": { "uri": "/v1/test" }, "action": { "return": 200 } }, { "action": { "rewrite": "/v1$uri", "pass": "routes" } } ] Reviewed-by: Alejandro Colomar <alx@nginx.com>
-rw-r--r--auto/sources1
-rw-r--r--docs/changes.xml6
-rw-r--r--src/nxt_conf_validation.c18
-rw-r--r--src/nxt_http.h7
-rw-r--r--src/nxt_http_parse.c4
-rw-r--r--src/nxt_http_parse.h1
-rw-r--r--src/nxt_http_request.c9
-rw-r--r--src/nxt_http_rewrite.c104
-rw-r--r--src/nxt_http_route.c20
-rw-r--r--src/nxt_tstr.c7
-rw-r--r--src/nxt_tstr.h1
11 files changed, 167 insertions, 11 deletions
diff --git a/auto/sources b/auto/sources
index f74985b9..9a7ff010 100644
--- a/auto/sources
+++ b/auto/sources
@@ -92,6 +92,7 @@ NXT_LIB_SRCS=" \
src/nxt_http_error.c \
src/nxt_http_route.c \
src/nxt_http_route_addr.c \
+ src/nxt_http_rewrite.c \
src/nxt_http_return.c \
src/nxt_http_static.c \
src/nxt_http_proxy.c \
diff --git a/docs/changes.xml b/docs/changes.xml
index 740a51a5..6c89fa15 100644
--- a/docs/changes.xml
+++ b/docs/changes.xml
@@ -34,6 +34,12 @@ NGINX Unit updated to 1.30.0.
<change type="feature">
<para>
+basic URI rewrite support.
+</para>
+</change>
+
+<change type="feature">
+<para>
added conditional logging of route selection for HTTP requests.
</para>
</change>
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 9059b2b3..c9aac790 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -669,6 +669,16 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = {
};
+static nxt_conf_vldt_object_t nxt_conf_vldt_action_common_members[] = {
+ {
+ .name = nxt_string("rewrite"),
+ .type = NXT_CONF_VLDT_STRING,
+ },
+
+ NXT_CONF_VLDT_END
+};
+
+
static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = {
{
.name = nxt_string("pass"),
@@ -677,7 +687,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_pass_action_members[] = {
.flags = NXT_CONF_VLDT_TSTR,
},
- NXT_CONF_VLDT_END
+ NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
@@ -692,7 +702,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_return_action_members[] = {
.flags = NXT_CONF_VLDT_TSTR,
},
- NXT_CONF_VLDT_END
+ NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
@@ -736,7 +746,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_share_action_members[] = {
#endif
},
- NXT_CONF_VLDT_END
+ NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
@@ -747,7 +757,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_proxy_action_members[] = {
.validator = nxt_conf_vldt_proxy,
},
- NXT_CONF_VLDT_END
+ NXT_CONF_VLDT_NEXT(nxt_conf_vldt_action_common_members)
};
diff --git a/src/nxt_http.h b/src/nxt_http.h
index d7bbaf02..08e1fcbe 100644
--- a/src/nxt_http.h
+++ b/src/nxt_http.h
@@ -226,6 +226,7 @@ typedef struct nxt_http_route_addr_rule_s nxt_http_route_addr_rule_t;
typedef struct {
+ nxt_conf_value_t *rewrite;
nxt_conf_value_t *pass;
nxt_conf_value_t *ret;
nxt_conf_value_t *location;
@@ -253,6 +254,7 @@ struct nxt_http_action_s {
nxt_str_t *pass;
} u;
+ nxt_tstr_t *rewrite;
nxt_http_action_t *fallback;
};
@@ -378,6 +380,11 @@ nxt_int_t nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_int_t nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf,
nxt_upstream_t ***upstream_joint);
+nxt_int_t nxt_http_rewrite_init(nxt_router_conf_t *rtcf,
+ nxt_http_action_t *action, nxt_http_action_conf_t *acf);
+nxt_int_t nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_action_t *action);
+
nxt_int_t nxt_http_return_init(nxt_router_conf_t *rtcf,
nxt_http_action_t *action, nxt_http_action_conf_t *acf);
diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c
index 439993df..50cbda2b 100644
--- a/src/nxt_http_parse.c
+++ b/src/nxt_http_parse.c
@@ -19,8 +19,6 @@ static u_char *nxt_http_lookup_field_end(u_char *p, const u_char *end);
static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp,
u_char **pos, const u_char *end);
-static nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp);
-
static nxt_int_t nxt_http_field_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq,
@@ -854,7 +852,7 @@ static const uint8_t nxt_http_normal[32] nxt_aligned(32) = {
};
-static nxt_int_t
+nxt_int_t
nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
{
u_char *p, *u, c, ch, high, *args;
diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h
index 88b10675..fa95e842 100644
--- a/src/nxt_http_parse.h
+++ b/src/nxt_http_parse.h
@@ -127,6 +127,7 @@ nxt_uint_t nxt_http_fields_hash_collisions(nxt_lvlhsh_t *hash,
nxt_int_t nxt_http_fields_process(nxt_list_t *fields, nxt_lvlhsh_t *hash,
void *ctx);
+nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp);
nxt_buf_t *nxt_http_chunk_parse(nxt_task_t *task, nxt_http_chunk_parse_t *hcp,
nxt_buf_t *in);
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index e53b1ec8..48f7dbe3 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -555,9 +555,18 @@ void
nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
+ nxt_int_t ret;
+
if (nxt_fast_path(action != NULL)) {
do {
+ if (action->rewrite != NULL) {
+ ret = nxt_http_rewrite(task, r, action);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ break;
+ }
+ }
+
action = action->handler(task, r, action);
if (action == NULL) {
diff --git a/src/nxt_http_rewrite.c b/src/nxt_http_rewrite.c
new file mode 100644
index 00000000..b800a919
--- /dev/null
+++ b/src/nxt_http_rewrite.c
@@ -0,0 +1,104 @@
+
+/*
+ * Copyright (C) Zhidao HONG
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_router.h>
+#include <nxt_http.h>
+
+
+nxt_int_t
+nxt_http_rewrite_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action,
+ nxt_http_action_conf_t *acf)
+ {
+ nxt_str_t str;
+
+ nxt_conf_get_string(acf->rewrite, &str);
+
+ action->rewrite = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
+ if (nxt_slow_path(action->rewrite == NULL)) {
+ return NXT_ERROR;
+ }
+
+ return NXT_OK;
+}
+
+
+nxt_int_t
+nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_action_t *action)
+{
+ u_char *p;
+ nxt_int_t ret;
+ nxt_str_t str, encoded_path, target;
+ nxt_router_conf_t *rtcf;
+ nxt_http_request_parse_t rp;
+
+ if (nxt_tstr_is_const(action->rewrite)) {
+ nxt_tstr_str(action->rewrite, &str);
+
+ } 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)) {
+ return NXT_ERROR;
+ }
+
+ nxt_tstr_query(task, r->tstr_query, action->rewrite, &str);
+
+ if (nxt_slow_path(nxt_tstr_query_failed(r->tstr_query))) {
+ return NXT_ERROR;
+ }
+ }
+
+ nxt_memzero(&rp, sizeof(nxt_http_request_parse_t));
+
+ rp.mem_pool = r->mem_pool;
+
+ rp.target_start = str.start;
+ rp.target_end = str.start + str.length;
+
+ ret = nxt_http_parse_complex_target(&rp);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
+ p = (rp.args.length > 0) ? rp.args.start - 1 : rp.target_end;
+
+ encoded_path.start = rp.target_start;
+ encoded_path.length = p - encoded_path.start;
+
+ if (r->args->length == 0) {
+ r->target = encoded_path;
+
+ } else {
+ target.length = encoded_path.length + 1 + r->args->length;
+
+ target.start = nxt_mp_alloc(r->mem_pool, target.length);
+ if (target.start == NULL) {
+ return NXT_ERROR;
+ }
+
+ p = nxt_cpymem(target.start, encoded_path.start, encoded_path.length);
+ *p++ = '?';
+ nxt_memcpy(p, r->args->start, r->args->length);
+
+ r->target = target;
+ }
+
+ r->path = nxt_mp_alloc(r->mem_pool, sizeof(nxt_str_t));
+ if (nxt_slow_path(r->path == NULL)) {
+ return NXT_ERROR;
+ }
+
+ *r->path = rp.path;
+
+ if (nxt_slow_path(r->log_route)) {
+ nxt_log(task, NXT_LOG_NOTICE, "URI rewritten to \"%V\"", &r->target);
+ }
+
+ return NXT_OK;
+}
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index f439c957..0935dd4a 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -579,6 +579,11 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
static nxt_conf_map_t nxt_http_route_action_conf[] = {
{
+ nxt_string("rewrite"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_http_action_conf_t, rewrite)
+ },
+ {
nxt_string("pass"),
NXT_CONF_MAP_PTR,
offsetof(nxt_http_action_conf_t, pass)
@@ -659,6 +664,13 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
rtcf = tmcf->router_conf;
mp = rtcf->mem_pool;
+ if (acf.rewrite != NULL) {
+ ret = nxt_http_rewrite_init(rtcf, action, &acf);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+ }
+
if (acf.ret != NULL) {
return nxt_http_return_init(rtcf, action, &acf);
}
@@ -1312,8 +1324,8 @@ nxt_http_pass_var(nxt_task_t *task, nxt_http_request_t *r,
goto fail;
}
- action = nxt_mp_get(r->mem_pool,
- sizeof(nxt_http_action_t) + sizeof(nxt_str_t));
+ action = nxt_mp_zget(r->mem_pool,
+ sizeof(nxt_http_action_t) + sizeof(nxt_str_t));
if (nxt_slow_path(action == NULL)) {
goto fail;
}
@@ -1496,7 +1508,7 @@ nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
rtcf = tmcf->router_conf;
mp = rtcf->mem_pool;
- action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
+ action = nxt_mp_zalloc(mp, sizeof(nxt_http_action_t));
if (nxt_slow_path(action == NULL)) {
return NULL;
}
@@ -1525,7 +1537,7 @@ nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
{
nxt_http_action_t *action;
- action = nxt_mp_alloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
+ action = nxt_mp_zalloc(rtcf->mem_pool, sizeof(nxt_http_action_t));
if (nxt_slow_path(action == NULL)) {
return NULL;
}
diff --git a/src/nxt_tstr.c b/src/nxt_tstr.c
index fda585b8..c439696e 100644
--- a/src/nxt_tstr.c
+++ b/src/nxt_tstr.c
@@ -296,6 +296,13 @@ nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr,
}
+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)
diff --git a/src/nxt_tstr.h b/src/nxt_tstr.h
index ce8e6f3a..afa7f56d 100644
--- a/src/nxt_tstr.h
+++ b/src/nxt_tstr.h
@@ -52,6 +52,7 @@ nxt_int_t nxt_tstr_query_init(nxt_tstr_query_t **query_p,
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,