Skip to content

Use proxy-agent to support $HTTP_PROXY #2400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 4, 2020
Merged
2 changes: 1 addition & 1 deletion ci/dev/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ main() {

cd lib/vscode
# Run this periodically in vanilla VS code to make sure we don't add any more warnings.
yarn eslint --max-warnings=3
yarn -s eslint --max-warnings=3
cd "$OLDPWD"
}

Expand Down
616 changes: 589 additions & 27 deletions ci/dev/vscode.patch

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"js-yaml": "^3.13.1",
"limiter": "^1.1.5",
"pem": "^1.14.2",
"proxy-agent": "^4.0.0",
"qs": "6.7.0",
"rotating-file-stream": "^2.1.1",
"safe-buffer": "^5.1.1",
Expand Down
File renamed without changes.
5 changes: 4 additions & 1 deletion src/node/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
shouldOpenInExistingInstance,
shouldRunVsCodeCli,
} from "./cli"
import { coderCloudBind } from "./coder-cloud"
import { coderCloudBind } from "./coder_cloud"
import { commit, version } from "./constants"
import * as proxyAgent from "./proxy_agent"
import { register } from "./routes"
import { humanPath, isFile, open } from "./util"
import { isChild, wrapper } from "./wrapper"
Expand Down Expand Up @@ -154,6 +155,8 @@ const main = async (args: DefaultedArgs): Promise<void> => {
}

async function entry(): Promise<void> {
proxyAgent.monkeyPatch(false)

// There's no need to check flags like --help or to spawn in an existing
// instance for the child process because these would have already happened in
// the parent and the child wouldn't have been spawned. We also get the
Expand Down
62 changes: 62 additions & 0 deletions src/node/proxy_agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { logger } from "@coder/logger"
import * as http from "http"
import * as proxyagent from "proxy-agent"

/**
* This file does not have anything to do with the code-server proxy.
* It's for $HTTP_PROXY support!
* - https://github.com/cdr/code-server/issues/124
* - https://www.npmjs.com/package/proxy-agent
*
* This file exists in two locations:
* - src/node/proxy_agent.ts
* - lib/vscode/src/vs/base/node/proxy_agent.ts
* The second is a symlink to the first.
*/

/**
* monkeyPatch patches the node HTTP/HTTPS library to route all requests through our
* custom agent from the proxyAgent package.
*/
export function monkeyPatch(vscode: boolean): void {
// We do not support HTTPS_PROXY here to avoid confusion. proxy-agent will automatically
// use the correct protocol to connect to the proxy depending on the requested URL.
//
// We could implement support ourselves to allow people to configure the proxy used for
// HTTPS vs HTTP but there doesn't seem to be much value in that.
//
// At least of right now, it'd just be plain confusing to support HTTPS_PROXY when proxy-agent
// will still use HTTP to hit it for HTTP requests.
const proxyURL = process.env.HTTP_PROXY || process.env.http_proxy
if (!proxyURL) {
return
}

logger.debug(`using $HTTP_PROXY ${process.env.HTTP_PROXY}`)

let pa: http.Agent
// The reasoning for this split is that VS Code's build process does not have
// esModuleInterop enabled but the code-server one does. As a result depending on where
// we execute, we either have a default attribute or we don't.
//
// I can't enable esModuleInterop in VS Code's build process as it breaks and spits out
// a huge number of errors.
if (vscode) {
pa = new (proxyagent as any)(process.env.HTTP_PROXY)
} else {
pa = new (proxyagent as any).default(process.env.HTTP_PROXY)
}

/**
* None of our code ever passes in a explicit agent to the http modules but VS Code's
* does sometimes but only when a user sets the http.proxy configuration.
* See https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support
*
* Even if they do, it's probably the same proxy so we should be fine! And those are
* deprecated anyway.
*/
const http = require("http")
const https = require("https")
http.globalAgent = pa
https.globalAgent = pa
}
3 changes: 2 additions & 1 deletion src/node/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,13 @@ export class UpdateProvider {
const httpx = uri.startsWith("https") ? https : http
const client = httpx.get(uri, { headers: { "User-Agent": "code-server" } }, (response) => {
if (!response.statusCode || response.statusCode < 200 || response.statusCode >= 400) {
response.destroy()
return reject(new Error(`${uri}: ${response.statusCode || "500"}`))
}

if (response.statusCode >= 300) {
++redirects
response.destroy()
++redirects
if (redirects > maxRedirects) {
return reject(new Error("reached max redirects"))
}
Expand Down
Loading