Skip to content

Commit af390eb

Browse files
committed
[SEA-NodeJS] refactor(kernel): pass proxy to the kernel as a structured object
Change the kernel proxy mapping from a flattened URL string to the structured napi `proxy` object (kernel #129), mirroring the kernel's internal ProxyConfig: `{ url, username?, password?, bypassHosts? }`. `buildKernelProxyOptions` now composes `url` from `protocol://host:port` (no embedded credentials) and forwards `auth.{username,password}` as separate basic-auth fields — eliminating the URL percent-encoding of credentials. The `noProxy` host list is forwarded as `bypassHosts` (previously unexpressible through the URL-string form). Regenerated napi contract (native/kernel/index.d.ts) carries the new `ProxyInput` object type. Verified via mitmproxy (HttpProxyTests, SEA leg): http / https / proxy-with-auth all route through the proxy and the query succeeds. Co-authored-by: Isaac
1 parent 0011da9 commit af390eb

2 files changed

Lines changed: 55 additions & 29 deletions

File tree

lib/kernel/KernelAuth.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,21 @@ export interface KernelHttpOptions {
176176

177177
/**
178178
* HTTP(S) proxy forwarded to the napi binding's `ConnectionOptions.proxy`
179-
* (kernel `ProxyConfig.url`). The public `ConnectionOptions.proxy` is the
179+
* (kernel `ProxyConfig`). The public `ConnectionOptions.proxy` is the
180180
* Thrift-shaped `{protocol, host, port, auth}`; `buildKernelProxyOptions`
181-
* composes a single proxy URL string (with any basic-auth credentials
182-
* percent-encoded into the `userinfo`) so the SAME connection option works
183-
* on both backends. The napi contract takes a flat `proxy?: string`.
181+
* maps it onto the kernel's structured proxy input — `url` composed from
182+
* `protocol://host:port`, with `auth.{username,password}` forwarded as
183+
* separate basic-auth fields (NOT embedded in the URL, so no percent-encoding
184+
* footgun) and the `noProxy` host list forwarded as `bypassHosts`. The same
185+
* connection option therefore works identically on both backends.
184186
*/
185187
export interface KernelProxyOptions {
186-
proxy?: string;
188+
proxy?: {
189+
url: string;
190+
username?: string;
191+
password?: string;
192+
bypassHosts?: string;
193+
};
187194
}
188195

189196
export type KernelNativeConnectionOptions = KernelSessionDefaults &
@@ -519,25 +526,28 @@ export function buildKernelRetryOptions(config: {
519526

520527
/**
521528
* Map the public `ConnectionOptions.proxy` (`{protocol, host, port, auth}` —
522-
* the same shape the Thrift backend accepts) onto the kernel's napi
523-
* `proxy?: string`. Composes `protocol://[user:pass@]host:port`, percent-
524-
* encoding any `auth.{username,password}` into the URL `userinfo` so
525-
* credentials containing reserved characters (`@`, `:`, `/`) survive intact —
526-
* the kernel parses the userinfo off and applies it as basic-auth. The kernel
527-
* accepts only `http://` / `https://`; a SOCKS protocol surfaces a clear
529+
* the same shape the Thrift backend accepts) onto the kernel's structured napi
530+
* proxy input. The `url` is composed from `protocol://host:port` (no embedded
531+
* credentials); `auth.{username,password}` are forwarded as separate
532+
* basic-auth fields (the kernel applies them via reqwest `Proxy::basic_auth`),
533+
* avoiding any URL percent-encoding footgun. The `noProxy` host list (a driver
534+
* option, not on the published `.d.ts`) is forwarded as `bypassHosts`. The
535+
* kernel accepts only `http://` / `https://`; a SOCKS protocol surfaces a clear
528536
* kernel error at connect (reqwest SOCKS support is not compiled in).
529537
*/
530538
export function buildKernelProxyOptions(options: ConnectionOptions): KernelProxyOptions {
531539
const { proxy } = options;
532540
if (!proxy) {
533541
return {};
534542
}
535-
const { username, password } = proxy.auth ?? {};
536-
const userinfo =
537-
username !== undefined ? `${encodeURIComponent(username)}:${encodeURIComponent(password ?? '')}@` : '';
538-
return {
539-
proxy: `${proxy.protocol}://${userinfo}${proxy.host}:${proxy.port}`,
543+
const { noProxy } = options as ConnectionOptions & { noProxy?: string };
544+
const out: NonNullable<KernelProxyOptions['proxy']> = {
545+
url: `${proxy.protocol}://${proxy.host}:${proxy.port}`,
540546
};
547+
if (proxy.auth?.username !== undefined) out.username = proxy.auth.username;
548+
if (proxy.auth?.password !== undefined) out.password = proxy.auth.password;
549+
if (typeof noProxy === 'string' && noProxy.length > 0) out.bypassHosts = noProxy;
550+
return { proxy: out };
541551
}
542552

543553
export function buildKernelConnectionOptions(options: ConnectionOptions): KernelNativeConnectionOptions {

native/kernel/index.d.ts

Lines changed: 29 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)