From 64934e59f9c06f62fe99466b320cd397c8609807 Mon Sep 17 00:00:00 2001 From: Zhidao HONG Date: Wed, 10 Apr 2024 13:45:34 +0800 Subject: [PATCH 1/2] HTTP: Introduce quoted target marker in HTTP parsing The quoted_target field is to indentify URLs containing percent-encoded characters. It can be used in places where you might need to generate new URL, such as in the proxy module. It will be used in the subsequent commit. --- src/nxt_http_parse.c | 15 ++++----------- src/nxt_http_parse.h | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 50cbda2bc..48be5bdb0 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -286,13 +286,11 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, case NXT_HTTP_TARGET_SPACE: rp->target_end = p; goto space_after_target; -#if 0 + case NXT_HTTP_TARGET_QUOTE_MARK: rp->quoted_target = 1; goto rest_of_target; -#else - case NXT_HTTP_TARGET_QUOTE_MARK: -#endif + case NXT_HTTP_TARGET_HASH: rp->complex_target = 1; goto rest_of_target; @@ -434,12 +432,7 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, rp->request_line_end = p; - if (rp->complex_target != 0 -#if 0 - || rp->quoted_target != 0 -#endif - ) - { + if (rp->complex_target || rp->quoted_target) { rc = nxt_http_parse_complex_target(rp); if (nxt_slow_path(rc != NXT_OK)) { @@ -1041,7 +1034,7 @@ nxt_http_parse_complex_target(nxt_http_request_parse_t *rp) break; case sw_quoted: - //rp->quoted_target = 1; + rp->quoted_target = 1; if (ch >= '0' && ch <= '9') { high = (u_char) (ch - '0'); diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h index fa95e8426..9e1265d14 100644 --- a/src/nxt_http_parse.h +++ b/src/nxt_http_parse.h @@ -61,9 +61,9 @@ struct nxt_http_request_parse_s { /* target with "/." */ uint8_t complex_target; /* 1 bit */ -#if 0 /* target with "%" */ uint8_t quoted_target; /* 1 bit */ +#if 0 /* target with " " */ uint8_t space_in_target; /* 1 bit */ #endif From a4dbee147cc13c9eef1f6cb209b4651a1419d17d Mon Sep 17 00:00:00 2001 From: Zhidao HONG Date: Wed, 10 Apr 2024 14:00:39 +0800 Subject: [PATCH 2/2] HTTP: Rewrote url target section in nxt_h1p_peer_header_send() Previously, proxy request was constructed based on the `r->target` field. However, r->target will remain unchanged in the future, even in cases of URL rewriting because of the requirement change for $request_uri that will be changed to constant. To accommodate this, the r->target should be designed to be constant, but Unit needs to pass a changeable URL to the upstream server. Based on the above, the proxy module can't depend on r->target. --- src/nxt_h1proto.c | 74 +++++++++++++++++++++++++++++++++++++++--- src/nxt_http.h | 2 ++ src/nxt_http_rewrite.c | 3 ++ 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index 1dfe4b6e6..c3a656793 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -90,6 +90,8 @@ static void nxt_h1p_peer_connect(nxt_task_t *task, nxt_http_peer_t *peer); static void nxt_h1p_peer_connected(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_peer_refused(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer); +static nxt_int_t nxt_h1p_peer_request_target(nxt_http_request_t *r, + nxt_str_t *target); static void nxt_h1p_peer_header_sent(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_peer_header_read(nxt_task_t *task, nxt_http_peer_t *peer); static ssize_t nxt_h1p_peer_io_read_handler(nxt_task_t *task, nxt_conn_t *c); @@ -654,6 +656,8 @@ nxt_h1p_header_process(nxt_task_t *task, nxt_h1proto_t *h1p, r->target.start = h1p->parser.target_start; r->target.length = h1p->parser.target_end - h1p->parser.target_start; + r->quoted_target = h1p->parser.quoted_target; + if (h1p->parser.version.ui64 != 0) { r->version.start = h1p->parser.version.str; r->version.length = sizeof(h1p->parser.version.str); @@ -2263,6 +2267,8 @@ nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) { u_char *p; size_t size; + nxt_int_t ret; + nxt_str_t target; nxt_buf_t *header, *body; nxt_conn_t *c; nxt_http_field_t *field; @@ -2272,7 +2278,12 @@ nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) r = peer->request; - size = r->method->length + sizeof(" ") + r->target.length + ret = nxt_h1p_peer_request_target(r, &target); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + size = r->method->length + sizeof(" ") + target.length + sizeof(" HTTP/1.1\r\n") + sizeof("Connection: close\r\n") + sizeof("\r\n"); @@ -2288,8 +2299,7 @@ nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) header = nxt_http_buf_mem(task, r, size); if (nxt_slow_path(header == NULL)) { - r->state->error_handler(task, r, peer); - return; + goto fail; } p = header->mem.free; @@ -2328,8 +2338,7 @@ nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) } if (nxt_slow_path(body == NULL)) { - r->state->error_handler(task, r, peer); - return; + goto fail; } header->next = body; @@ -2353,6 +2362,61 @@ nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer) } nxt_conn_write(task->thread->engine, c); + + return; + +fail: + + r->state->error_handler(task, r, peer); +} + + +static nxt_int_t +nxt_h1p_peer_request_target(nxt_http_request_t *r, nxt_str_t *target) +{ + u_char *p; + size_t size, encode; + + if (!r->uri_changed) { + *target = r->target; + return NXT_OK; + } + + if (!r->quoted_target && r->args->length == 0) { + *target = *r->path; + return NXT_OK; + } + + if (r->quoted_target) { + encode = nxt_encode_complex_uri(NULL, r->path->start, + r->path->length); + } else { + encode = 0; + } + + size = r->path->length + encode * 2 + 1 + r->args->length; + + target->start = nxt_mp_nget(r->mem_pool, size); + if (target->start == NULL) { + return NXT_ERROR; + } + + if (r->quoted_target) { + p = (u_char *) nxt_encode_complex_uri(target->start, r->path->start, + r->path->length); + + } else { + p = nxt_cpymem(target->start, r->path->start, r->path->length); + } + + if (r->args->length > 0) { + *p++ = '?'; + p = nxt_cpymem(p, r->args->start, r->args->length); + } + + target->length = p - target->start; + + return NXT_OK; } diff --git a/src/nxt_http.h b/src/nxt_http.h index e812bd0d1..23d86b91f 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -192,6 +192,8 @@ struct nxt_http_request_s { nxt_http_status_t status:16; uint8_t log_route; /* 1 bit */ + uint8_t quoted_target; /* 1 bit */ + uint8_t uri_changed; /* 1 bit */ uint8_t pass_count; /* 8 bits */ uint8_t app_target; diff --git a/src/nxt_http_rewrite.c b/src/nxt_http_rewrite.c index fb216eeb8..ff465ecc6 100644 --- a/src/nxt_http_rewrite.c +++ b/src/nxt_http_rewrite.c @@ -103,6 +103,9 @@ nxt_http_rewrite(nxt_task_t *task, nxt_http_request_t *r) *r->path = rp.path; + r->uri_changed = 1; + r->quoted_target = rp.quoted_target; + if (nxt_slow_path(r->log_route)) { nxt_log(task, NXT_LOG_NOTICE, "URI rewritten to \"%V\"", &r->target); }