Skip to content

Commit a27d55a

Browse files
authored
feat: Add CONNECT tunneling support for HTTP proxy in sandboxed environments (#791)
This PR is a follow-up of PR #788, which unfortunately didn't fully fix the use of **apify-cli** in Claude Code sandbox (in the browser, not the local one). Currently, this is what's happening : 1. Proxy receives the request 2. Proxy returns: HTTP/1.1 301 Moved Permanently 3. Location: https://api.apify.com:443/v2/users/me (adds explicit :443 port) 4. axios follows redirect to https://api.apify.com:443/v2/users/me 5. Proxy strips the :443 and redirects back to https://api.apify.com/v2/users/me 6. **Infinite loop!** This is a known `axios` problem, referenced in several **unsolved** issues : - axios/axios#6725 - axios/axios#2072 - axios/axios#925 - axios/axios#4531 To fix this issue, this PR adds support for CONNECT tunneling through HTTP/HTTPS proxies, using [proxy-agents](https://github.com/TooTallNate/proxy-agents) modules. What this does : 1. HttpsProxyAgent sends CONNECT api.apify.com:443 2. Proxy establishes tunnel (returns 200 OK) 3. Client does TLS handshake through tunnel 4. Encrypted traffic flows through tunnel 5. Proxy cannot see/modify the HTTPS traffic (acts like classic proxy) 6. **No redirects, no loops!** ~By precaution, we keep here the current http[s] agent implementation when the `HTTP[S]_PROXY` env vars are not defined.~ (Changed since commit 89571f9)
1 parent a82832a commit a27d55a

File tree

3 files changed

+13
-29
lines changed

3 files changed

+13
-29
lines changed

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"axios": "^1.6.7",
7272
"content-type": "^1.0.5",
7373
"ow": "^0.28.2",
74+
"proxy-agent": "^6.5.0",
7475
"tslib": "^2.5.0",
7576
"type-fest": "^4.0.0"
7677
},

src/http_client.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import http from 'node:http';
2-
import https from 'node:https';
1+
import type http from 'node:http';
2+
import type https from 'node:https';
33
import os from 'node:os';
44

55
import type { RetryFunction } from 'async-retry';
66
import retry from 'async-retry';
77
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
88
import axios, { AxiosHeaders } from 'axios';
9+
import { ProxyAgent } from 'proxy-agent';
910

1011
import { APIFY_ENV_VARS } from '@apify/consts';
1112
import type { Log } from '@apify/log';
@@ -74,8 +75,11 @@ export class HttpClient {
7475
scheduling: 'lifo',
7576
};
7677

77-
this.httpAgent = new http.Agent(agentOptions);
78-
this.httpsAgent = new https.Agent(agentOptions);
78+
// Use ProxyAgent which automatically detects proxy from environment variables
79+
// and supports CONNECT tunneling
80+
const proxyAgent = new ProxyAgent(agentOptions);
81+
this.httpAgent = proxyAgent;
82+
this.httpsAgent = proxyAgent;
7983

8084
// Disable Nagle's algorithm for lower latency
8185
// This sends data immediately instead of buffering small packets
@@ -90,6 +94,8 @@ export class HttpClient {
9094
this.axios = axios.create({
9195
httpAgent: this.httpAgent,
9296
httpsAgent: this.httpsAgent,
97+
// Disable axios's built-in proxy handling since we're using custom agents
98+
proxy: false,
9399
paramsSerializer: (params) => {
94100
const formattedParams: [string, string][] = Object.entries<string | Date>(params)
95101
.filter(([, value]) => value !== undefined)

0 commit comments

Comments
 (0)