Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(proxy-wasm) set querystring when setting ":path" #627

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/common/proxy_wasm/ngx_proxy_wasm_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,15 +511,17 @@ ngx_proxy_wasm_maps_set_path(ngx_wavm_instance_t *instance, ngx_str_t *value,
ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent;
ngx_http_wasm_req_ctx_t *rctx = ngx_http_proxy_wasm_get_rctx(instance);
ngx_http_request_t *r = rctx->r;
u_char *query;
size_t len = value->len;

if (ngx_strchr(value->data, '?')) {
ngx_wavm_instance_trap_printf(instance,
"NYI - cannot set request path "
"with querystring");
return NGX_ERROR;
query = (u_char *) ngx_strchr(value->data, '?');
if (query) {
len = query - value->data;
r->args.len = value->len - len - 1;
r->args.data = query + 1;
}

r->uri.len = value->len;
r->uri.len = len;
r->uri.data = value->data;

if (pwctx->path.len) {
Expand Down
10 changes: 5 additions & 5 deletions src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec,
call->method.data = elt->value.data;

} else if (ngx_str_eq(elt->key.data, elt->key.len, ":path", -1)) {
call->uri.len = elt->value.len;
call->uri.data = elt->value.data;
call->path.len = elt->value.len;
call->path.data = elt->value.data;

} else if (ngx_str_eq(elt->key.data, elt->key.len,
":authority", -1))
Expand Down Expand Up @@ -330,7 +330,7 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec,
call->error = NGX_HTTP_PROXY_WASM_DISPATCH_ERR_BAD_METHOD;
goto error;

} else if (!call->uri.len) {
} else if (!call->path.len) {
call->error = NGX_HTTP_PROXY_WASM_DISPATCH_ERR_BAD_PATH;
goto error;
}
Expand Down Expand Up @@ -577,7 +577,7 @@ ngx_http_proxy_wasm_dispatch_request(ngx_http_proxy_wasm_dispatch_t *call)
* Connection:
* Content-Length:
*/
len += call->method.len + 1 + call->uri.len + 1
len += call->method.len + 1 + call->path.len + 1
+ sizeof(ngx_http_header_version11) - 1;

len += sizeof(ngx_http_host_header) - 1 + sizeof(": ") - 1
Expand Down Expand Up @@ -638,7 +638,7 @@ ngx_http_proxy_wasm_dispatch_request(ngx_http_proxy_wasm_dispatch_t *call)
b->last = ngx_cpymem(b->last, call->method.data, call->method.len);
*b->last++ = ' ';

b->last = ngx_cpymem(b->last, call->uri.data, call->uri.len);
b->last = ngx_cpymem(b->last, call->path.data, call->path.len);
*b->last++ = ' ';

b->last = ngx_cpymem(b->last, ngx_http_header_version11,
Expand Down
2 changes: 1 addition & 1 deletion src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct ngx_http_proxy_wasm_dispatch_s {

ngx_str_t host;
ngx_str_t method;
ngx_str_t uri;
ngx_str_t path; /* ":path" (including query) */
ngx_str_t authority;
ngx_array_t headers;
ngx_array_t trailers;
Expand Down
202 changes: 191 additions & 11 deletions t/03-proxy_wasm/hfuncs/111-proxy_set_http_request_header.t
Original file line number Diff line number Diff line change
Expand Up @@ -295,26 +295,206 @@ path: /test



=== TEST 12: proxy_wasm - set_http_request_headers() cannot set ':path' with querystring (NYI)
=== TEST 12: proxy_wasm - set_http_request_headers() can set ':path' with querystring
--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '\$request_uri \$uri \$is_args \$args\n';
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?foo=bar';
return 200;
proxy_wasm hostcalls 'test=/t/log/request_path';
proxy_pass http://test_upstream$uri$is_args$args;
}
--- error_code: 500
--- response_body_like: 500 Internal Server Error
--- grep_error_log eval: qr/(NYI|\[.*?failed resuming).*/
--- grep_error_log_out eval
qr/.*?NYI - cannot set request path with querystring.*
\[info\] .*? filter chain failed resuming: previous error \(instance trapped\)/
--- response_body
/test?foo=bar /test ? foo=bar
--- error_log
path: /test?foo=bar
--- no_error_log
[error]
[crit]



=== TEST 13: proxy_wasm - set_http_request_headers() setting ':path' with empty querystring drops the querystring
--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n';
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?';
proxy_wasm hostcalls 'test=/t/log/request_path';
proxy_pass http://test_upstream$uri$is_args$args;
}
--- response_body
(/test) (/test) () ()
--- error_log
path: /test
--- no_error_log
[error]
[crit]



=== TEST 14: proxy_wasm - set_http_request_headers() can set ':path' with empty path
--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n';
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=';
proxy_wasm hostcalls 'test=/t/log/request_path';
proxy_pass http://test_upstream$uri$is_args$args;
}
--- response_body
(/t) (/t) () ()
--- error_log
path:
--- no_error_log
[error]
[crit]



=== TEST 15: proxy_wasm - set_http_request_headers() setting ':path' with single '?' has same behavior as empty path
--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n';
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=?';
proxy_wasm hostcalls 'test=/t/log/request_path';
proxy_pass http://test_upstream$uri$is_args$args;
}
--- response_body
(/t) (/t) () ()
--- error_log
path:
--- no_error_log
[error]
[crit]



=== TEST 16: proxy_wasm - set_http_request_headers() setting ':path' with invalid querystring matches nginx behavior
See following test for a showcase of the nginx behavior.

--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n';
}
}
}
--- config
location /set_by_proxy_wasm {
proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?foo=bár%20bla';
proxy_wasm hostcalls 'test=/t/log/request_path';
proxy_pass http://test_upstream$uri$is_args$args;
}
--- request
GET /set_by_proxy_wasm
--- response_body
(/test?foo=bár%20bla) (/test) (?) (foo=bár%20bla)
--- error_log
path: /test
--- no_error_log
[error]
[crit]



=== TEST 17: proxy_wasm - showcase that that path with invalid querystring passes through
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to make tests 16 and 17 into a single test using --- request eval and ["GET /set_by_proxy_wasm", "GET /raw_nginx"]. That worked in isolation, but it messed up the plan_tests count.

This test is here just as documentation, but it showcases
the same behavior as set_http_request_headers(':path');
see previous test for the proxy-wasm behavior.

--- wasm_modules: hostcalls
--- http_config eval
qq{
upstream test_upstream {
server unix:$ENV{TEST_NGINX_UNIX_SOCKET};
}

server {
listen unix:$ENV{TEST_NGINX_UNIX_SOCKET};

location / {
return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n';
}
}
}
--- config
location /raw_nginx {
proxy_pass http://test_upstream$uri$is_args$args;
}
--- request
GET /raw_nginx?foo=bár%20bla
--- response_body
(/raw_nginx?foo=bár%20bla) (/raw_nginx) (?) (foo=bár%20bla)
--- no_error_log
[error]
[crit]
[alert]
[stderr]



=== TEST 13: proxy_wasm - set_http_request_header() sets ':method'
=== TEST 18: proxy_wasm - set_http_request_header() sets ':method'
--- wasm_modules: hostcalls
--- http_config eval
qq{
Expand Down Expand Up @@ -344,7 +524,7 @@ POST



=== TEST 14: proxy_wasm - set_http_request_header() cannot set ':scheme'
=== TEST 19: proxy_wasm - set_http_request_header() cannot set ':scheme'
--- wasm_modules: hostcalls
--- http_config eval
qq{
Expand Down
56 changes: 56 additions & 0 deletions t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t
Original file line number Diff line number Diff line change
Expand Up @@ -1329,3 +1329,59 @@ cannot override the "Host" header, skipping
cannot override the "Connection" header, skipping
--- no_error_log
[error]



=== TEST 51: proxy_wasm - dispatch_http_call() can use ':path' with querystring
--- load_nginx_modules: ngx_http_echo_module
--- wasm_modules: hostcalls
--- config
location /dispatched {
return 200 "Hello back $request_uri $uri $is_args $args";
}

location /t {
proxy_wasm hostcalls 'on=request_body \
test=/t/dispatch_http_call \
host=127.0.0.1:$TEST_NGINX_SERVER_PORT \
path=/dispatched?foo=bar \
on_http_call_response=echo_response_body';
echo failed;
}
--- request
GET /t

Hello world
--- response_body
Hello back /dispatched?foo=bar /dispatched ? foo=bar
--- no_error_log
[error]
[crit]



=== TEST 52: proxy_wasm - dispatch_http_call() can use ':path' with querystring, passes through invalid characters
--- load_nginx_modules: ngx_http_echo_module
--- wasm_modules: hostcalls
--- config
location /dispatched {
return 200 "Hello back $request_uri $uri $is_args $args";
}

location /t {
proxy_wasm hostcalls 'on=request_body \
test=/t/dispatch_http_call \
host=127.0.0.1:$TEST_NGINX_SERVER_PORT \
path=/dispatched?foo=bár%20bla \
on_http_call_response=echo_response_body';
echo failed;
}
--- request
GET /t

Hello world
--- response_body
Hello back /dispatched?foo=bár%20bla /dispatched ? foo=bár%20bla
--- no_error_log
[error]
[crit]
Loading