diff --git a/README.md b/README.md index 7f5b08d..4f18170 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Table of Contents * [proxy_connect_send_timeout](#proxy_connect_send_timeout) * [proxy_connect_address](#proxy_connect_address) * [proxy_connect_bind](#proxy_connect_bind) + * [proxy_connect_response](#proxy_connect_response) * [Variables](#variables) * [$connect_host](#connect_host) * [$connect_port](#connect_port) @@ -37,7 +38,7 @@ Table of Contents * [$proxy_connect_send_timeout](#proxy_connect_send_timeout-1) * [$proxy_connect_resolve_time](#proxy_connect_resolve_time) * [$proxy_connect_connect_time](#proxy_connect_connect_time) - * [$proxy_connect_response](#proxy_connect_response) + * [$proxy_connect_response](#proxy_connect_response-1) * [Compatibility](#compatibility) * [Nginx Compatibility](#nginx-compatibility) * [OpenResty Compatibility](#openresty-compatibility) @@ -367,6 +368,44 @@ In order for this parameter to work, it is usually necessary to run nginx worker NOTE: If using `set $` and `proxy_connect_bind $` together, you should use `proxy_connect_rewrite.patch` instead, see [Install](#install) for more details. +proxy_connect_response +---------------------- + +Syntax: **proxy_connect_response `CONNECT response`** +Default: `HTTP/1.1 200 Connection Established\r\nProxy-agent: nginx\r\n\r\n` +Context: `server` + +Set the response of CONNECT request. + +Note that it is only used for CONNECT request, it cannot modify the data flow over CONNECT tunnel. + +For example: + +``` +proxy_connect_response "HTTP/1.1 200 Connection Established\r\nProxy-agent: nginx\r\nX-Proxy-Connected-Addr: $connect_addr\r\n\r\n"; + +``` + +The `curl` command test case with above config is as following: + +``` +$ curl https://github.com -sv -x localhost:3128 +* Connected to localhost (127.0.0.1) port 3128 (#0) +* allocate connect buffer! +* Establish HTTP proxy tunnel to github.com:443 +> CONNECT github.com:443 HTTP/1.1 +> Host: github.com:443 +> User-Agent: curl/7.64.1 +> Proxy-Connection: Keep-Alive +> +< HTTP/1.1 200 Connection Established --. +< Proxy-agent: nginx | custom CONNECT response +< X-Proxy-Connected-Addr: 13.229.188.59:443 --' +... + +``` + + Variables ========= @@ -465,6 +504,8 @@ rewrite_by_lua ' '; ``` +Also note that `set` or `rewrite_by_lua*` directive is run during the REWRITE phase, which is ahead of dns resolving phase. It cannot get right value of some variables, for example, `$connect_addr` value is `nil`. In such case, you should use [`proxy_connect_response` directive](#proxy_connect_response) instead. + Compatibility ============= diff --git a/ngx_http_proxy_connect_module.c b/ngx_http_proxy_connect_module.c index b1743ee..ca2e924 100644 --- a/ngx_http_proxy_connect_module.c +++ b/ngx_http_proxy_connect_module.c @@ -37,6 +37,8 @@ typedef struct { ngx_http_complex_value_t *address; ngx_http_proxy_connect_address_t *local; + + ngx_http_complex_value_t *response; } ngx_http_proxy_connect_loc_conf_t; @@ -201,6 +203,12 @@ static ngx_command_t ngx_http_proxy_connect_commands[] = { offsetof(ngx_http_proxy_connect_loc_conf_t, local), NULL }, + { ngx_string("proxy_connect_response"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_connect_loc_conf_t, response), + NULL }, ngx_null_command }; @@ -530,6 +538,23 @@ ngx_http_proxy_connect_send_connection_established(ngx_http_request_t *r) b = &ctx->buf; + /* modify CONNECT response via proxy_connect_response directive */ + { + ngx_str_t resp; + ngx_http_proxy_connect_loc_conf_t *plcf; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_connect_module); + + if (plcf->response + && ngx_http_complex_value(r, plcf->response, &resp) == NGX_OK) + { + if (resp.len > 0) { + b->pos = resp.data; + b->last = b->pos + resp.len; + } + } + } + ctx->send_established = 1; for (;;) { diff --git a/t/http_proxy_connect.t b/t/http_proxy_connect.t index 4b55f7b..eee51b5 100644 --- a/t/http_proxy_connect.t +++ b/t/http_proxy_connect.t @@ -346,6 +346,52 @@ if ($test_enable_rewrite_phase) { $t->stop(); +############################################################################### + +$t->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + access_log off; + + resolver 127.0.0.1:18085 ipv6=off; # NOTE: cannot connect ipv6 address ::1 in mac os x. + + server { + listen 127.0.0.1:8080; + proxy_connect; + proxy_connect_allow all; + + proxy_connect_response "HTTP/1.1 200 Connection Established\r\nProxy-agent: nginx\r\nX-Proxy-Connected-Addr: $connect_addr\r\n\r\n"; + } + + server { + listen 8081; + location / { + return 200 "backend"; + } + } +} + +EOF + +# test proxy_connect_response directive + +$t->run(); + +if ($test_enable_rewrite_phase) { + like(http_connect_request('set-response-header.com', '8081', '/'), qr/X-Proxy-Connected-Addr: 127.0.0.1:8081\r/, 'added header "Foo: bar" to CONNECT response'); +} + +$t->stop(); + # --- stop DNS server ---