Skip to content

HTTP client: CONNECT tunnel support#1466

Open
WaberZhuang wants to merge 1 commit into
alibaba:mainfrom
WaberZhuang:main
Open

HTTP client: CONNECT tunnel support#1466
WaberZhuang wants to merge 1 commit into
alibaba:mainfrom
WaberZhuang:main

Conversation

@WaberZhuang

@WaberZhuang WaberZhuang commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

What changed

CONNECT tunnel for HTTPS proxy (new)

HTTPS targets through an HTTP/HTTPS proxy are now handled via CONNECT tunnels (RFC 7231 §4.3.6). Previously only HTTP/1.1 forward proxy was supported; HTTPS proxy connections would fail or produce incorrect requests.

The tunnel logic is implemented as private methods of PooledDialer (make_tunnel_stream, do_connect_handshake), reusing the same ISocketPool instance for connection grouping — no separate pool class introduced.

proxy_header (new interface)

A new CommonHeaders<> proxy_header field is introduced on Operation, with a companion CommonHeaders<>* proxy_headers() accessor on Client, dedicated to proxy-handshake headers (e.g. Proxy-Authorization). This separates proxy headers from req.headers (target-server headers).

Priority chain in call():

op->proxy_header  ←  merge client->proxy_headers()  ←  insert URL Basic auth
                          (op wins, allow_dup=0)        (allow_dup=0, manual wins)
  • HTTP proxy (target is HTTP): proxy_header is merged into req.headers before sending. Existing code that sets Proxy-Authorization in req.headers still works — merge with allow_dup=0 preserves the destination's existing value.
  • HTTPS proxy (target is HTTPS): proxy_header is consumed exclusively by the CONNECT handshake; req.headers is sent to the target server after the tunnel is established.

set_proxy() behavior change

  • Operation set_proxy(url): now also resets op->proxy_header — old proxy's auth headers are no longer valid for the new proxy.
  • Client set_proxy(url): now also resets client->proxy_headers().

Note: the old m_proxy_auth field is removed. Auth is now derived from the proxy URL at call() time and lives in proxy_header.

Key-based connection pooling (internal)

All connection types — direct TCP/TLS, HTTP proxy, and CONNECT tunnel — share a single ISocketPool (new_tcp_socket_pool) via connect(key, connector). Connection grouping is purely by key:

Connection type Key format
Direct / HTTP proxy <host>:<port>:<0|1> (0=TCP, 1=TLS)
CONNECT tunnel <proxy_host>:<proxy_port>:<s|p>:<target_host>:<target_port>[:<auth>]

The connector lambda (passed as TempDelegate, zero std::function overhead) is the factory that establishes new connections on pool miss. Different auth credentials or target endpoints produce different keys, preventing cross-contamination.

Verification

client_function_test  (-server_no_resp):   18/18 PASSED
client_tls_test       (client_tls.basic):   1/1  PASSED
client_tls_test       (client_proxy.*):     8/8  PASSED

@WaberZhuang
WaberZhuang marked this pull request as draft June 17, 2026 04:13
@WaberZhuang
WaberZhuang marked this pull request as ready for review June 29, 2026 12:56
@WaberZhuang
WaberZhuang force-pushed the main branch 4 times, most recently from 474c2ba to 3173d28 Compare July 3, 2026 07:36
@WaberZhuang
WaberZhuang force-pushed the main branch 8 times, most recently from 4dbc061 to 1496488 Compare July 16, 2026 08:53
Signed-off-by: zhuangbowei.zbw <zhuangbowei.zbw@alibaba-inc.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant