Skip to content

Commit

Permalink
feat(proxy-wasm) new 'request.is_subrequest' property
Browse files Browse the repository at this point in the history
Introduce a new request property `request.is_subrequest` to indicate
whether the current request is a subrequest of an existing request
(e.g. in slicing scenarios).

Note: although the property uses the `request.*` prefix, this is not an
Envoy-supported attribute.

See #658.

Co-Authored-By: Thibault Charbonnier <[email protected]>
  • Loading branch information
dev-null-undefined and thibaultcha committed Jan 16, 2025
1 parent 0c9eeed commit 8ae948e
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 29 deletions.
1 change: 1 addition & 0 deletions docs/PROXY_WASM.md
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ implementation state in ngx_wasm_module:
`request.size` | :heavy_check_mark: | :x: | Maps to [ngx.content_length](https://nginx.org/en/docs/http/ngx_http_core_module.html#content_length).
`request.total_size` | :heavy_check_mark: | :x: | Maps to [ngx.request_length](https://nginx.org/en/docs/http/ngx_http_core_module.html#request_length).
`request.headers.*` | :heavy_check_mark: | :x: | Returns the value of any request header, e.g. `request.headers.date`.
`request.is_subrequest` | :heavy_check_mark: | :x: | An ngx_wasm_module extension indicating if the current request is a subrequest as a `"true"/"false"` string.
*Response properties* | |
`response.code` | :heavy_check_mark: | :x: | Maps to [ngx.status](https://nginx.org/en/docs/http/ngx_http_core_module.html#status).
`response.size` | :heavy_check_mark: | :x: | Maps to [ngx.body_bytes_sent](https://nginx.org/en/docs/http/ngx_http_core_module.html#body_bytes_sent).
Expand Down
68 changes: 46 additions & 22 deletions src/common/proxy_wasm/ngx_proxy_wasm_properties.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,22 @@ static const char *ngx_prefix = "ngx.";
static const size_t ngx_prefix_len = 4;


static const char *host_prefix =
NGX_WASM_HOST_PROPERTY_NAMESPACE_STR ".";
static size_t host_prefix_len;


#ifdef NGX_WASM_HTTP
static ngx_str_t str_on = ngx_string("true");
static ngx_str_t str_off = ngx_string("false");
#endif


static ngx_hash_init_t pwm2ngx_init;
static ngx_hash_combined_t pwm2ngx_hash;
static ngx_hash_keys_arrays_t pwm2ngx_keys;


static const char *host_prefix = NGX_WASM_HOST_PROPERTY_NAMESPACE_STR ".";
static size_t host_prefix_len;


typedef struct {
ngx_str_node_t sn;
ngx_str_t value;
Expand Down Expand Up @@ -171,6 +178,37 @@ get_request_time(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
}


static ngx_int_t
get_request_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
ngx_str_t *value)
{
ngx_str_t name;

name.data = (u_char *) (path->data + request_headers_prefix_len);
name.len = path->len - request_headers_prefix_len;

return get_map_value(pwctx, &name, value,
NGX_PROXY_WASM_MAP_HTTP_REQUEST_HEADERS);
}


static ngx_int_t
is_subrequest(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
ngx_str_t *value)
{
ngx_str_t *result;
ngx_http_wasm_req_ctx_t *rctx = pwctx->data;
ngx_http_request_t *r = rctx->r;

result = r != r->main ? &str_on : &str_off;

value->data = result->data;
value->len = result->len;

return NGX_OK;
}


static ngx_int_t
get_upstream_address(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
ngx_str_t *value)
Expand Down Expand Up @@ -243,20 +281,6 @@ get_upstream_port(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
}


static ngx_int_t
get_request_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
ngx_str_t *value)
{
ngx_str_t name;

name.data = (u_char *) (path->data + request_headers_prefix_len);
name.len = path->len - request_headers_prefix_len;

return get_map_value(pwctx, &name, value,
NGX_PROXY_WASM_MAP_HTTP_REQUEST_HEADERS);
}


static ngx_int_t
get_response_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
ngx_str_t *value)
Expand Down Expand Up @@ -313,9 +337,6 @@ get_connection_mtls(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
static ngx_str_t verify_p = ngx_string("ngx.ssl_client_verify");
static ngx_str_t verify_e = ngx_string("SUCCESS");

static ngx_str_t mtls_on = ngx_string("true");
static ngx_str_t mtls_off = ngx_string("false");

if (!pwctx->mtls.len) {
rc = ngx_proxy_wasm_properties_get_ngx(pwctx, &https_p, &https_v);
if (rc != NGX_OK) {
Expand All @@ -331,7 +352,7 @@ get_connection_mtls(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path,
&& ngx_str_eq(verify_v.data, verify_v.len,
verify_e.data, verify_e.len);

result = on ? &mtls_on : &mtls_off;
result = on ? &str_on : &str_off;

pwctx->mtls.data = ngx_pnalloc(pwctx->pool, result->len);
if (pwctx->mtls.data == NULL) {
Expand Down Expand Up @@ -472,6 +493,9 @@ static pwm2ngx_mapping_t pw2ngx[] = {
{ ngx_string("request.headers.*"),
ngx_null_string,
&get_request_header, NULL },
{ ngx_string("request.is_subrequest"),
ngx_null_string,
&is_subrequest, NULL },

/* Response properties */

Expand Down
42 changes: 35 additions & 7 deletions t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ our $request_properties = join(',', qw(
request.duration
request.size
request.total_size
request.is_subrequest
));

plan_tests(5);
Expand Down Expand Up @@ -63,7 +64,8 @@ request\.protocol: HTTP\/1\.1 at RequestHeaders
request\.query: special_arg\=true\&special_arg2\=false at RequestHeaders
request\.duration: \d+\.\d+ at RequestHeaders
request\.size: 5 at RequestHeaders
request\.total_size: 187 at RequestHeaders/
request\.total_size: 187 at RequestHeaders
request\.is_subrequest: false at RequestHeaders/
--- no_error_log
[error]
[crit]
Expand Down Expand Up @@ -151,7 +153,8 @@ request.method: GET at OnHttpCallResponse
request.time: \d+\.\d+ at OnHttpCallResponse
request.protocol: HTTP\/1\.1 at OnHttpCallResponse
request.query: hello\=world at OnHttpCallResponse
request.total_size: [1-9]+[0-9]+ at OnHttpCallResponse/
request.total_size: [1-9]+[0-9]+ at OnHttpCallResponse
request.is_subrequest: false at OnHttpCallResponse/
--- no_error_log
[error]
[crit]
Expand Down Expand Up @@ -667,7 +670,32 @@ qr/"response.code_details" property not supported



=== TEST 15: proxy_wasm - get_property() - unknown property on: request_headers
=== TEST 15: proxy_wasm - get_property() - request.is_subrequest on: request_headers
--- load_nginx_modules: ngx_http_echo_module
--- wasm_modules: hostcalls
--- config
location /t {
echo_subrequest GET '/sub';
}

location /sub {
proxy_wasm hostcalls 'on=request_headers \
test=/t/log/properties \
name=request.is_subrequest';
echo ok;
}
--- response_body
ok
--- grep_error_log eval: qr/request\.is_subrequest: (true|false) at \w+/
--- grep_error_log_out eval
qr/request\.is_subrequest: true at RequestHeaders/
--- no_error_log
[error]
[crit]



=== TEST 16: proxy_wasm - get_property() - unknown property on: request_headers
--- wasm_modules: hostcalls
--- load_nginx_modules: ngx_http_echo_module
--- config
Expand All @@ -686,7 +714,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/



=== TEST 16: proxy_wasm - get_property() request.* - not available on: tick (isolation: global)
=== TEST 17: proxy_wasm - get_property() request.* - not available on: tick (isolation: global)
--- skip_hup
--- wasm_modules: hostcalls
--- load_nginx_modules: ngx_http_echo_module
Expand All @@ -709,7 +737,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/



=== TEST 17: proxy_wasm - get_property() response.* - not available on: tick (isolation: global)
=== TEST 18: proxy_wasm - get_property() response.* - not available on: tick (isolation: global)
--- skip_hup
--- wasm_modules: hostcalls
--- load_nginx_modules: ngx_http_echo_module
Expand All @@ -732,7 +760,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/



=== TEST 18: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global)
=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global)
--- skip_hup
--- wasm_modules: hostcalls
--- load_nginx_modules: ngx_http_echo_module
Expand All @@ -755,7 +783,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/



=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global)
=== TEST 20: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global)
--- skip_hup
--- wasm_modules: hostcalls
--- load_nginx_modules: ngx_http_echo_module
Expand Down
1 change: 1 addition & 0 deletions t/lib/proxy-wasm-tests/hostcalls/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl Context for TestHttp {
"request.protocol",
"request.query",
"request.total_size",
"request.is_subrequest",
];

for property in properties {
Expand Down

0 comments on commit 8ae948e

Please sign in to comment.