]> git.kaiwu.me - njs.git/commitdiff
Fetch: fix missing CONNECT request terminator without proxy auth
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 11 Jun 2026 23:48:37 +0000 (16:48 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Fri, 12 Jun 2026 03:26:59 +0000 (20:26 -0700)
Previously, ngx_js_http_build_connect_request() emitted the blank
line terminating the request headers only when a proxy auth header
was present.  An HTTPS request through a proxy configured without
credentials sent a CONNECT request with no terminating blank line,
so the proxy kept waiting for more headers and the fetch timed out.

nginx/ngx_js_http.c
nginx/t/js_fetch_proxy_https.t

index 3f9355dd7ec3cbc101a8efb4c4057b6c784b08ee..bd8260a2c536a1a1258205e3922535c1c2415a3e 100644 (file)
@@ -522,8 +522,9 @@ ngx_js_http_build_connect_request(ngx_js_http_t *http)
     if (http->proxy.auth.len != 0) {
         njs_chb_append(&http->chain, http->proxy.auth.data,
                        http->proxy.auth.len);
-        njs_chb_append_literal(&http->chain, CRLF);
     }
+
+    njs_chb_append_literal(&http->chain, CRLF);
 }
 
 
index 6589cd3bc63250c6338f4bd314dd4c44d8ef9962..7b4d10ed0073c77c57b8ceb7f8764c22e574b509 100644 (file)
@@ -63,6 +63,12 @@ http {
             js_content test.https_fetch;
         }
 
+        location /https_via_proxy_no_auth {
+            js_fetch_proxy http://forward.proxy.net:%%PORT_8084%%;
+            js_fetch_timeout 2s;
+            js_content test.https_fetch;
+        }
+
         location /https_no_proxy {
             js_content test.https_fetch;
         }
@@ -85,6 +91,7 @@ EOF
 
 my $p2 = port(8082);
 my $p3 = port(8083);
+my $p4 = port(8084);
 
 $t->write_file('test.js', <<EOF);
     function engine(r) {
@@ -185,11 +192,13 @@ foreach my $name ('example.com') {
                . $t->read_file('intermediate.crt'));
 }
 
-$t->try_run('no js_fetch_proxy')->plan(8);
+$t->try_run('no js_fetch_proxy')->plan(9);
 
-$t->run_daemon(\&https_proxy_daemon, $p2);
+$t->run_daemon(\&https_proxy_daemon, $p2, 1);
+$t->run_daemon(\&https_proxy_daemon, $p4, 0);
 $t->run_daemon(\&dns_daemon, port(8981), $t);
 $t->waitforsocket('127.0.0.1:' . $p2);
+$t->waitforsocket('127.0.0.1:' . $p4);
 $t->waitforfile($t->testdir . '/' . port(8981));
 
 ###############################################################################
@@ -203,6 +212,9 @@ $resp = http_post('/https_via_proxy?domain=example.com');
 like($resp, qr/METHOD: POST/, 'https through proxy received POST method');
 like($resp, qr/BODY: REQ-BODY/, 'https through proxy received request body');
 
+like(http_get('/https_via_proxy_no_auth?domain=example.com'), qr/ORIGIN/,
+       'https through proxy without auth');
+
 like(http_get('/https_no_proxy?domain=example.com'), qr/ORIGIN/,
        'https without proxy');
 
@@ -214,7 +226,7 @@ like(http_get('/https_via_broken_proxy?domain=example.com'),
 ###############################################################################
 
 sub https_proxy_daemon {
-       my ($port) = @_;
+       my ($port, $auth) = @_;
 
        my $server = IO::Socket::INET->new(
                Proto     => 'tcp',
@@ -311,9 +323,11 @@ sub https_proxy_daemon {
                                                }
                                        }
 
-                                       if (uc($method) eq 'CONNECT'
-                                               && $proxy_auth =~ /^Basic\s+dXNlcjpwYXNz$/i)
-                                       {
+                                       my $auth_ok = $auth
+                                               ? $proxy_auth =~ /^Basic\s+dXNlcjpwYXNz$/i
+                                               : $proxy_auth eq '';
+
+                                       if (uc($method) eq 'CONNECT' && $auth_ok) {
                                                print $sock "HTTP/1.1 200 established" . CRLF . CRLF;
 
                                                my ($host, $port) = split(/:/, $target);