UNPKG

4.93 kBPlain TextView Raw
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License. See License.txt in the project root for license information.
3
4import {
5 BaseRequestPolicy,
6 RequestPolicy,
7 RequestPolicyFactory,
8 RequestPolicyOptionsLike,
9} from "./requestPolicy";
10import { HttpOperationResponse } from "../httpOperationResponse";
11import { ProxySettings } from "../serviceClient";
12import { WebResourceLike } from "../webResource";
13import { Constants } from "../util/constants";
14import { URLBuilder } from "../url";
15
16/**
17 * @internal
18 */
19export const noProxyList: string[] = loadNoProxy();
20const byPassedList: Map<string, boolean> = new Map();
21
22/**
23 * @internal
24 */
25export function getEnvironmentValue(name: string): string | undefined {
26 if (process.env[name]) {
27 return process.env[name];
28 } else if (process.env[name.toLowerCase()]) {
29 return process.env[name.toLowerCase()];
30 }
31 return undefined;
32}
33
34function loadEnvironmentProxyValue(): string | undefined {
35 if (!process) {
36 return undefined;
37 }
38
39 const httpsProxy = getEnvironmentValue(Constants.HTTPS_PROXY);
40 const allProxy = getEnvironmentValue(Constants.ALL_PROXY);
41 const httpProxy = getEnvironmentValue(Constants.HTTP_PROXY);
42
43 return httpsProxy || allProxy || httpProxy;
44}
45
46// Check whether the host of a given `uri` is in the noProxyList.
47// If there's a match, any request sent to the same host won't have the proxy settings set.
48// This implementation is a port of https://github.com/Azure/azure-sdk-for-net/blob/8cca811371159e527159c7eb65602477898683e2/sdk/core/Azure.Core/src/Pipeline/Internal/HttpEnvironmentProxy.cs#L210
49function isBypassed(uri: string): boolean | undefined {
50 if (noProxyList.length === 0) {
51 return false;
52 }
53 const host = URLBuilder.parse(uri).getHost()!;
54 if (byPassedList.has(host)) {
55 return byPassedList.get(host);
56 }
57 let isBypassedFlag = false;
58 for (const pattern of noProxyList) {
59 if (pattern[0] === ".") {
60 // This should match either domain it self or any subdomain or host
61 // .foo.com will match foo.com it self or *.foo.com
62 if (host.endsWith(pattern)) {
63 isBypassedFlag = true;
64 } else {
65 if (host.length === pattern.length - 1 && host === pattern.slice(1)) {
66 isBypassedFlag = true;
67 }
68 }
69 } else {
70 if (host === pattern) {
71 isBypassedFlag = true;
72 }
73 }
74 }
75 byPassedList.set(host, isBypassedFlag);
76 return isBypassedFlag;
77}
78
79/**
80 * @internal
81 */
82export function loadNoProxy(): string[] {
83 const noProxy = getEnvironmentValue(Constants.NO_PROXY);
84 if (noProxy) {
85 return noProxy
86 .split(",")
87 .map((item) => item.trim())
88 .filter((item) => item.length);
89 }
90
91 return [];
92}
93
94/**
95 * @internal
96 */
97function extractAuthFromUrl(
98 url: string
99): { username?: string; password?: string; urlWithoutAuth: string } {
100 const atIndex = url.indexOf("@");
101 if (atIndex === -1) {
102 return { urlWithoutAuth: url };
103 }
104
105 const schemeIndex = url.indexOf("://");
106 const authStart = schemeIndex !== -1 ? schemeIndex + 3 : 0;
107 const auth = url.substring(authStart, atIndex);
108 const colonIndex = auth.indexOf(":");
109 const hasPassword = colonIndex !== -1;
110 const username = hasPassword ? auth.substring(0, colonIndex) : auth;
111 const password = hasPassword ? auth.substring(colonIndex + 1) : undefined;
112 const urlWithoutAuth = url.substring(0, authStart) + url.substring(atIndex + 1);
113 return {
114 username,
115 password,
116 urlWithoutAuth,
117 };
118}
119
120export function getDefaultProxySettings(proxyUrl?: string): ProxySettings | undefined {
121 if (!proxyUrl) {
122 proxyUrl = loadEnvironmentProxyValue();
123 if (!proxyUrl) {
124 return undefined;
125 }
126 }
127
128 const { username, password, urlWithoutAuth } = extractAuthFromUrl(proxyUrl);
129 const parsedUrl = URLBuilder.parse(urlWithoutAuth);
130 const schema = parsedUrl.getScheme() ? parsedUrl.getScheme() + "://" : "";
131 return {
132 host: schema + parsedUrl.getHost(),
133 port: Number.parseInt(parsedUrl.getPort() || "80"),
134 username,
135 password,
136 };
137}
138
139export function proxyPolicy(proxySettings?: ProxySettings): RequestPolicyFactory {
140 if (!proxySettings) {
141 proxySettings = getDefaultProxySettings();
142 }
143 return {
144 create: (nextPolicy: RequestPolicy, options: RequestPolicyOptionsLike) => {
145 return new ProxyPolicy(nextPolicy, options, proxySettings!);
146 },
147 };
148}
149
150export class ProxyPolicy extends BaseRequestPolicy {
151 proxySettings: ProxySettings;
152
153 constructor(
154 nextPolicy: RequestPolicy,
155 options: RequestPolicyOptionsLike,
156 proxySettings: ProxySettings
157 ) {
158 super(nextPolicy, options);
159 this.proxySettings = proxySettings;
160 }
161
162 public sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
163 if (!request.proxySettings && !isBypassed(request.url)) {
164 request.proxySettings = this.proxySettings;
165 }
166 return this._nextPolicy.sendRequest(request);
167 }
168}