diff --git a/packages/language-server/api.d.ts b/packages/language-server/api.d.ts index 591a795d4..1cdbb5de2 100644 --- a/packages/language-server/api.d.ts +++ b/packages/language-server/api.d.ts @@ -1,3 +1,4 @@ +import { Agent } from "http"; /** * Absolute path to the server's "main" module * This is useful when launching the server in a separate process (e.g via spawn). @@ -13,4 +14,9 @@ export type FetchResponse = { json: () => Promise; }; -export type Fetcher = (url: string) => Promise; +export type Fetcher = ( + url: string, + options?: { + agent: Agent; + } +) => Promise; diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 850a28e6f..da67e202f 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -36,6 +36,8 @@ "@xml-tools/parser": "1.0.7", "assert-never": "1.2.1", "fs-extra": "9.0.1", + "http-proxy-agent": "4.0.1", + "https-proxy-agent": "5.0.0", "lodash": "4.17.20", "node-fetch": "2.6.0", "vscode-languageserver": "6.1.1", diff --git a/packages/language-server/src/ui5-model.ts b/packages/language-server/src/ui5-model.ts index 813a25b44..95fcfd1b9 100644 --- a/packages/language-server/src/ui5-model.ts +++ b/packages/language-server/src/ui5-model.ts @@ -2,6 +2,8 @@ import { map } from "lodash"; import fetch from "node-fetch"; import { resolve } from "path"; import { pathExists, lstat, readJson, writeJson, mkdirs } from "fs-extra"; +import { HttpsProxyAgent } from "https-proxy-agent"; +import { HttpProxyAgent } from "http-proxy-agent"; import { UI5SemanticModel } from "@ui5-language-assistant/semantic-model-types"; import { @@ -29,6 +31,7 @@ export async function getSemanticModelWithFetcher( const baseUrl = `https://sapui5.hana.ondemand.com/${version}/test-resources/`; const suffix = "/designtime/api.json"; const libs = getLibs(); + let cacheFolder: string | undefined; // Note: all cache handling (reading, writing etc) is optional from the user perspective but @@ -55,7 +58,41 @@ export async function getSemanticModelWithFetcher( // If the file doesn't exist in the cache (or we couldn't read it), fetch it from the network if (apiJson === undefined) { const url = baseUrl + libName.replace(/\./g, "/") + suffix; - const response = await fetcher(url); + + let response; + + if ( + process.env["NO_PROXY"] + ?.split(",") + .some((_noProxy) => url.includes(_noProxy)) + ) { + console.debug( + "Ressource URL is in NO_PROXY env, so no proxy is used." + ); + response = await fetcher(url); + } else if (process.env["HTTPS_PROXY"] && url.startsWith("https://")) { + console.debug( + "Ressource URL is https and HTTPS_PROXY env is set, so https proxy is used" + ); + const agent = new HttpsProxyAgent(process.env["HTTPS_PROXY"]); + + // https://github.com/TooTallNate/node-https-proxy-agent/issues/108 + // have to pass agent as any was workaround + response = await fetcher(url, { agent: agent as any }); + } else if (process.env["HTTP_PROXY"] && url.startsWith("http://")) { + console.debug( + "Ressource URL is https and HTTP_PROXY env is set, so http proxy is used" + ); + const agent = new HttpProxyAgent(process.env["HTTP_PROXY"]); + + // https://github.com/TooTallNate/node-https-proxy-agent/issues/108 + // have to pass agent as any was workaround + response = await fetcher(url, { agent: agent as any }); + } else { + console.debug("Using no proxy at all"); + response = await fetcher(url); + } + if (response.ok) { apiJson = await response.json(); await writeToCache(cacheFilePath, apiJson); diff --git a/yarn.lock b/yarn.lock index e657321cb..9756520e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1238,6 +1238,11 @@ dependencies: "@types/node" ">= 8" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@types/chai@4.2.12": version "4.2.12" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.12.tgz#6160ae454cd89dae05adc3bb97997f488b608201" @@ -1649,6 +1654,13 @@ agent-base@4, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" +agent-base@6: + version "6.0.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4" + integrity sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg== + dependencies: + debug "4" + agent-base@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -3015,6 +3027,13 @@ debug@3.2.6, debug@^3.1.0: dependencies: ms "^2.1.1" +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -3022,13 +3041,6 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -4525,6 +4537,15 @@ http-cache-semantics@^3.8.1: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== +http-proxy-agent@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + http-proxy-agent@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" @@ -4547,6 +4568,14 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + https-proxy-agent@^2.2.3, https-proxy-agent@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"