@actions/http-client 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,537 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const http = require("http");
4
+ const https = require("https");
5
+ const pm = require("./proxy");
6
+ let tunnel;
7
+ var HttpCodes;
8
+ (function (HttpCodes) {
9
+ HttpCodes[HttpCodes["OK"] = 200] = "OK";
10
+ HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices";
11
+ HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently";
12
+ HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved";
13
+ HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther";
14
+ HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified";
15
+ HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy";
16
+ HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy";
17
+ HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect";
18
+ HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect";
19
+ HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
20
+ HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized";
21
+ HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired";
22
+ HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden";
23
+ HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound";
24
+ HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed";
25
+ HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable";
26
+ HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
27
+ HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout";
28
+ HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict";
29
+ HttpCodes[HttpCodes["Gone"] = 410] = "Gone";
30
+ HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests";
31
+ HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError";
32
+ HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented";
33
+ HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway";
34
+ HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable";
35
+ HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout";
36
+ })(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {}));
37
+ var Headers;
38
+ (function (Headers) {
39
+ Headers["Accept"] = "accept";
40
+ Headers["ContentType"] = "content-type";
41
+ })(Headers = exports.Headers || (exports.Headers = {}));
42
+ var MediaTypes;
43
+ (function (MediaTypes) {
44
+ MediaTypes["ApplicationJson"] = "application/json";
45
+ })(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {}));
46
+ /**
47
+ * Returns the proxy URL, depending upon the supplied url and proxy environment variables.
48
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
49
+ */
50
+ function getProxyUrl(serverUrl) {
51
+ let proxyUrl = pm.getProxyUrl(new URL(serverUrl));
52
+ return proxyUrl ? proxyUrl.href : '';
53
+ }
54
+ exports.getProxyUrl = getProxyUrl;
55
+ const HttpRedirectCodes = [
56
+ HttpCodes.MovedPermanently,
57
+ HttpCodes.ResourceMoved,
58
+ HttpCodes.SeeOther,
59
+ HttpCodes.TemporaryRedirect,
60
+ HttpCodes.PermanentRedirect
61
+ ];
62
+ const HttpResponseRetryCodes = [
63
+ HttpCodes.BadGateway,
64
+ HttpCodes.ServiceUnavailable,
65
+ HttpCodes.GatewayTimeout
66
+ ];
67
+ const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD'];
68
+ const ExponentialBackoffCeiling = 10;
69
+ const ExponentialBackoffTimeSlice = 5;
70
+ class HttpClientError extends Error {
71
+ constructor(message, statusCode) {
72
+ super(message);
73
+ this.name = 'HttpClientError';
74
+ this.statusCode = statusCode;
75
+ Object.setPrototypeOf(this, HttpClientError.prototype);
76
+ }
77
+ }
78
+ exports.HttpClientError = HttpClientError;
79
+ class HttpClientResponse {
80
+ constructor(message) {
81
+ this.message = message;
82
+ }
83
+ readBody() {
84
+ return new Promise(async (resolve, reject) => {
85
+ let output = Buffer.alloc(0);
86
+ this.message.on('data', (chunk) => {
87
+ output = Buffer.concat([output, chunk]);
88
+ });
89
+ this.message.on('end', () => {
90
+ resolve(output.toString());
91
+ });
92
+ });
93
+ }
94
+ }
95
+ exports.HttpClientResponse = HttpClientResponse;
96
+ function isHttps(requestUrl) {
97
+ let parsedUrl = new URL(requestUrl);
98
+ return parsedUrl.protocol === 'https:';
99
+ }
100
+ exports.isHttps = isHttps;
101
+ class HttpClient {
102
+ constructor(userAgent, handlers, requestOptions) {
103
+ this._ignoreSslError = false;
104
+ this._allowRedirects = true;
105
+ this._allowRedirectDowngrade = false;
106
+ this._maxRedirects = 50;
107
+ this._allowRetries = false;
108
+ this._maxRetries = 1;
109
+ this._keepAlive = false;
110
+ this._disposed = false;
111
+ this.userAgent = userAgent;
112
+ this.handlers = handlers || [];
113
+ this.requestOptions = requestOptions;
114
+ if (requestOptions) {
115
+ if (requestOptions.ignoreSslError != null) {
116
+ this._ignoreSslError = requestOptions.ignoreSslError;
117
+ }
118
+ this._socketTimeout = requestOptions.socketTimeout;
119
+ if (requestOptions.allowRedirects != null) {
120
+ this._allowRedirects = requestOptions.allowRedirects;
121
+ }
122
+ if (requestOptions.allowRedirectDowngrade != null) {
123
+ this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade;
124
+ }
125
+ if (requestOptions.maxRedirects != null) {
126
+ this._maxRedirects = Math.max(requestOptions.maxRedirects, 0);
127
+ }
128
+ if (requestOptions.keepAlive != null) {
129
+ this._keepAlive = requestOptions.keepAlive;
130
+ }
131
+ if (requestOptions.allowRetries != null) {
132
+ this._allowRetries = requestOptions.allowRetries;
133
+ }
134
+ if (requestOptions.maxRetries != null) {
135
+ this._maxRetries = requestOptions.maxRetries;
136
+ }
137
+ }
138
+ }
139
+ options(requestUrl, additionalHeaders) {
140
+ return this.request('OPTIONS', requestUrl, null, additionalHeaders || {});
141
+ }
142
+ get(requestUrl, additionalHeaders) {
143
+ return this.request('GET', requestUrl, null, additionalHeaders || {});
144
+ }
145
+ del(requestUrl, additionalHeaders) {
146
+ return this.request('DELETE', requestUrl, null, additionalHeaders || {});
147
+ }
148
+ post(requestUrl, data, additionalHeaders) {
149
+ return this.request('POST', requestUrl, data, additionalHeaders || {});
150
+ }
151
+ patch(requestUrl, data, additionalHeaders) {
152
+ return this.request('PATCH', requestUrl, data, additionalHeaders || {});
153
+ }
154
+ put(requestUrl, data, additionalHeaders) {
155
+ return this.request('PUT', requestUrl, data, additionalHeaders || {});
156
+ }
157
+ head(requestUrl, additionalHeaders) {
158
+ return this.request('HEAD', requestUrl, null, additionalHeaders || {});
159
+ }
160
+ sendStream(verb, requestUrl, stream, additionalHeaders) {
161
+ return this.request(verb, requestUrl, stream, additionalHeaders);
162
+ }
163
+ /**
164
+ * Gets a typed object from an endpoint
165
+ * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
166
+ */
167
+ async getJson(requestUrl, additionalHeaders = {}) {
168
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
169
+ let res = await this.get(requestUrl, additionalHeaders);
170
+ return this._processResponse(res, this.requestOptions);
171
+ }
172
+ async postJson(requestUrl, obj, additionalHeaders = {}) {
173
+ let data = JSON.stringify(obj, null, 2);
174
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
175
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
176
+ let res = await this.post(requestUrl, data, additionalHeaders);
177
+ return this._processResponse(res, this.requestOptions);
178
+ }
179
+ async putJson(requestUrl, obj, additionalHeaders = {}) {
180
+ let data = JSON.stringify(obj, null, 2);
181
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
182
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
183
+ let res = await this.put(requestUrl, data, additionalHeaders);
184
+ return this._processResponse(res, this.requestOptions);
185
+ }
186
+ async patchJson(requestUrl, obj, additionalHeaders = {}) {
187
+ let data = JSON.stringify(obj, null, 2);
188
+ additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson);
189
+ additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson);
190
+ let res = await this.patch(requestUrl, data, additionalHeaders);
191
+ return this._processResponse(res, this.requestOptions);
192
+ }
193
+ /**
194
+ * Makes a raw http request.
195
+ * All other methods such as get, post, patch, and request ultimately call this.
196
+ * Prefer get, del, post and patch
197
+ */
198
+ async request(verb, requestUrl, data, headers) {
199
+ if (this._disposed) {
200
+ throw new Error('Client has already been disposed.');
201
+ }
202
+ let parsedUrl = new URL(requestUrl);
203
+ let info = this._prepareRequest(verb, parsedUrl, headers);
204
+ // Only perform retries on reads since writes may not be idempotent.
205
+ let maxTries = this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
206
+ ? this._maxRetries + 1
207
+ : 1;
208
+ let numTries = 0;
209
+ let response;
210
+ while (numTries < maxTries) {
211
+ response = await this.requestRaw(info, data);
212
+ // Check if it's an authentication challenge
213
+ if (response &&
214
+ response.message &&
215
+ response.message.statusCode === HttpCodes.Unauthorized) {
216
+ let authenticationHandler;
217
+ for (let i = 0; i < this.handlers.length; i++) {
218
+ if (this.handlers[i].canHandleAuthentication(response)) {
219
+ authenticationHandler = this.handlers[i];
220
+ break;
221
+ }
222
+ }
223
+ if (authenticationHandler) {
224
+ return authenticationHandler.handleAuthentication(this, info, data);
225
+ }
226
+ else {
227
+ // We have received an unauthorized response but have no handlers to handle it.
228
+ // Let the response return to the caller.
229
+ return response;
230
+ }
231
+ }
232
+ let redirectsRemaining = this._maxRedirects;
233
+ while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
234
+ this._allowRedirects &&
235
+ redirectsRemaining > 0) {
236
+ const redirectUrl = response.message.headers['location'];
237
+ if (!redirectUrl) {
238
+ // if there's no location to redirect to, we won't
239
+ break;
240
+ }
241
+ let parsedRedirectUrl = new URL(redirectUrl);
242
+ if (parsedUrl.protocol == 'https:' &&
243
+ parsedUrl.protocol != parsedRedirectUrl.protocol &&
244
+ !this._allowRedirectDowngrade) {
245
+ throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.');
246
+ }
247
+ // we need to finish reading the response before reassigning response
248
+ // which will leak the open socket.
249
+ await response.readBody();
250
+ // strip authorization header if redirected to a different hostname
251
+ if (parsedRedirectUrl.hostname !== parsedUrl.hostname) {
252
+ for (let header in headers) {
253
+ // header names are case insensitive
254
+ if (header.toLowerCase() === 'authorization') {
255
+ delete headers[header];
256
+ }
257
+ }
258
+ }
259
+ // let's make the request with the new redirectUrl
260
+ info = this._prepareRequest(verb, parsedRedirectUrl, headers);
261
+ response = await this.requestRaw(info, data);
262
+ redirectsRemaining--;
263
+ }
264
+ if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
265
+ // If not a retry code, return immediately instead of retrying
266
+ return response;
267
+ }
268
+ numTries += 1;
269
+ if (numTries < maxTries) {
270
+ await response.readBody();
271
+ await this._performExponentialBackoff(numTries);
272
+ }
273
+ }
274
+ return response;
275
+ }
276
+ /**
277
+ * Needs to be called if keepAlive is set to true in request options.
278
+ */
279
+ dispose() {
280
+ if (this._agent) {
281
+ this._agent.destroy();
282
+ }
283
+ this._disposed = true;
284
+ }
285
+ /**
286
+ * Raw request.
287
+ * @param info
288
+ * @param data
289
+ */
290
+ requestRaw(info, data) {
291
+ return new Promise((resolve, reject) => {
292
+ let callbackForResult = function (err, res) {
293
+ if (err) {
294
+ reject(err);
295
+ }
296
+ resolve(res);
297
+ };
298
+ this.requestRawWithCallback(info, data, callbackForResult);
299
+ });
300
+ }
301
+ /**
302
+ * Raw request with callback.
303
+ * @param info
304
+ * @param data
305
+ * @param onResult
306
+ */
307
+ requestRawWithCallback(info, data, onResult) {
308
+ let socket;
309
+ if (typeof data === 'string') {
310
+ info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8');
311
+ }
312
+ let callbackCalled = false;
313
+ let handleResult = (err, res) => {
314
+ if (!callbackCalled) {
315
+ callbackCalled = true;
316
+ onResult(err, res);
317
+ }
318
+ };
319
+ let req = info.httpModule.request(info.options, (msg) => {
320
+ let res = new HttpClientResponse(msg);
321
+ handleResult(null, res);
322
+ });
323
+ req.on('socket', sock => {
324
+ socket = sock;
325
+ });
326
+ // If we ever get disconnected, we want the socket to timeout eventually
327
+ req.setTimeout(this._socketTimeout || 3 * 60000, () => {
328
+ if (socket) {
329
+ socket.end();
330
+ }
331
+ handleResult(new Error('Request timeout: ' + info.options.path), null);
332
+ });
333
+ req.on('error', function (err) {
334
+ // err has statusCode property
335
+ // res should have headers
336
+ handleResult(err, null);
337
+ });
338
+ if (data && typeof data === 'string') {
339
+ req.write(data, 'utf8');
340
+ }
341
+ if (data && typeof data !== 'string') {
342
+ data.on('close', function () {
343
+ req.end();
344
+ });
345
+ data.pipe(req);
346
+ }
347
+ else {
348
+ req.end();
349
+ }
350
+ }
351
+ /**
352
+ * Gets an http agent. This function is useful when you need an http agent that handles
353
+ * routing through a proxy server - depending upon the url and proxy environment variables.
354
+ * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com
355
+ */
356
+ getAgent(serverUrl) {
357
+ let parsedUrl = new URL(serverUrl);
358
+ return this._getAgent(parsedUrl);
359
+ }
360
+ _prepareRequest(method, requestUrl, headers) {
361
+ const info = {};
362
+ info.parsedUrl = requestUrl;
363
+ const usingSsl = info.parsedUrl.protocol === 'https:';
364
+ info.httpModule = usingSsl ? https : http;
365
+ const defaultPort = usingSsl ? 443 : 80;
366
+ info.options = {};
367
+ info.options.host = info.parsedUrl.hostname;
368
+ info.options.port = info.parsedUrl.port
369
+ ? parseInt(info.parsedUrl.port)
370
+ : defaultPort;
371
+ info.options.path =
372
+ (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '');
373
+ info.options.method = method;
374
+ info.options.headers = this._mergeHeaders(headers);
375
+ if (this.userAgent != null) {
376
+ info.options.headers['user-agent'] = this.userAgent;
377
+ }
378
+ info.options.agent = this._getAgent(info.parsedUrl);
379
+ // gives handlers an opportunity to participate
380
+ if (this.handlers) {
381
+ this.handlers.forEach(handler => {
382
+ handler.prepareRequest(info.options);
383
+ });
384
+ }
385
+ return info;
386
+ }
387
+ _mergeHeaders(headers) {
388
+ const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
389
+ if (this.requestOptions && this.requestOptions.headers) {
390
+ return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers));
391
+ }
392
+ return lowercaseKeys(headers || {});
393
+ }
394
+ _getExistingOrDefaultHeader(additionalHeaders, header, _default) {
395
+ const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {});
396
+ let clientHeader;
397
+ if (this.requestOptions && this.requestOptions.headers) {
398
+ clientHeader = lowercaseKeys(this.requestOptions.headers)[header];
399
+ }
400
+ return additionalHeaders[header] || clientHeader || _default;
401
+ }
402
+ _getAgent(parsedUrl) {
403
+ let agent;
404
+ let proxyUrl = pm.getProxyUrl(parsedUrl);
405
+ let useProxy = proxyUrl && proxyUrl.hostname;
406
+ if (this._keepAlive && useProxy) {
407
+ agent = this._proxyAgent;
408
+ }
409
+ if (this._keepAlive && !useProxy) {
410
+ agent = this._agent;
411
+ }
412
+ // if agent is already assigned use that agent.
413
+ if (!!agent) {
414
+ return agent;
415
+ }
416
+ const usingSsl = parsedUrl.protocol === 'https:';
417
+ let maxSockets = 100;
418
+ if (!!this.requestOptions) {
419
+ maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets;
420
+ }
421
+ if (useProxy) {
422
+ // If using proxy, need tunnel
423
+ if (!tunnel) {
424
+ tunnel = require('tunnel');
425
+ }
426
+ const agentOptions = {
427
+ maxSockets: maxSockets,
428
+ keepAlive: this._keepAlive,
429
+ proxy: {
430
+ ...((proxyUrl.username || proxyUrl.password) && {
431
+ proxyAuth: `${proxyUrl.username}:${proxyUrl.password}`
432
+ }),
433
+ host: proxyUrl.hostname,
434
+ port: proxyUrl.port
435
+ }
436
+ };
437
+ let tunnelAgent;
438
+ const overHttps = proxyUrl.protocol === 'https:';
439
+ if (usingSsl) {
440
+ tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
441
+ }
442
+ else {
443
+ tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
444
+ }
445
+ agent = tunnelAgent(agentOptions);
446
+ this._proxyAgent = agent;
447
+ }
448
+ // if reusing agent across request and tunneling agent isn't assigned create a new agent
449
+ if (this._keepAlive && !agent) {
450
+ const options = { keepAlive: this._keepAlive, maxSockets: maxSockets };
451
+ agent = usingSsl ? new https.Agent(options) : new http.Agent(options);
452
+ this._agent = agent;
453
+ }
454
+ // if not using private agent and tunnel agent isn't setup then use global agent
455
+ if (!agent) {
456
+ agent = usingSsl ? https.globalAgent : http.globalAgent;
457
+ }
458
+ if (usingSsl && this._ignoreSslError) {
459
+ // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
460
+ // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
461
+ // we have to cast it to any and change it directly
462
+ agent.options = Object.assign(agent.options || {}, {
463
+ rejectUnauthorized: false
464
+ });
465
+ }
466
+ return agent;
467
+ }
468
+ _performExponentialBackoff(retryNumber) {
469
+ retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
470
+ const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
471
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
472
+ }
473
+ static dateTimeDeserializer(key, value) {
474
+ if (typeof value === 'string') {
475
+ let a = new Date(value);
476
+ if (!isNaN(a.valueOf())) {
477
+ return a;
478
+ }
479
+ }
480
+ return value;
481
+ }
482
+ async _processResponse(res, options) {
483
+ return new Promise(async (resolve, reject) => {
484
+ const statusCode = res.message.statusCode;
485
+ const response = {
486
+ statusCode: statusCode,
487
+ result: null,
488
+ headers: {}
489
+ };
490
+ // not found leads to null obj returned
491
+ if (statusCode == HttpCodes.NotFound) {
492
+ resolve(response);
493
+ }
494
+ let obj;
495
+ let contents;
496
+ // get the result from the body
497
+ try {
498
+ contents = await res.readBody();
499
+ if (contents && contents.length > 0) {
500
+ if (options && options.deserializeDates) {
501
+ obj = JSON.parse(contents, HttpClient.dateTimeDeserializer);
502
+ }
503
+ else {
504
+ obj = JSON.parse(contents);
505
+ }
506
+ response.result = obj;
507
+ }
508
+ response.headers = res.message.headers;
509
+ }
510
+ catch (err) {
511
+ // Invalid resource (contents not json); leaving result obj null
512
+ }
513
+ // note that 3xx redirects are handled by the http layer.
514
+ if (statusCode > 299) {
515
+ let msg;
516
+ // if exception/error in body, attempt to get better error
517
+ if (obj && obj.message) {
518
+ msg = obj.message;
519
+ }
520
+ else if (contents && contents.length > 0) {
521
+ // it may be the case that the exception is in the body message as string
522
+ msg = contents;
523
+ }
524
+ else {
525
+ msg = 'Failed request: (' + statusCode + ')';
526
+ }
527
+ let err = new HttpClientError(msg, statusCode);
528
+ err.result = response.result;
529
+ reject(err);
530
+ }
531
+ else {
532
+ resolve(response);
533
+ }
534
+ });
535
+ }
536
+ }
537
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,49 @@
1
+ /// <reference types="node" />
2
+ import http = require('http');
3
+ export interface IHeaders {
4
+ [key: string]: any;
5
+ }
6
+ export interface IHttpClient {
7
+ options(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
8
+ get(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
9
+ del(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
10
+ post(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
11
+ patch(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
12
+ put(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
13
+ sendStream(verb: string, requestUrl: string, stream: NodeJS.ReadableStream, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
14
+ request(verb: string, requestUrl: string, data: string | NodeJS.ReadableStream, headers: IHeaders): Promise<IHttpClientResponse>;
15
+ requestRaw(info: IRequestInfo, data: string | NodeJS.ReadableStream): Promise<IHttpClientResponse>;
16
+ requestRawWithCallback(info: IRequestInfo, data: string | NodeJS.ReadableStream, onResult: (err: any, res: IHttpClientResponse) => void): void;
17
+ }
18
+ export interface IRequestHandler {
19
+ prepareRequest(options: http.RequestOptions): void;
20
+ canHandleAuthentication(response: IHttpClientResponse): boolean;
21
+ handleAuthentication(httpClient: IHttpClient, requestInfo: IRequestInfo, objs: any): Promise<IHttpClientResponse>;
22
+ }
23
+ export interface IHttpClientResponse {
24
+ message: http.IncomingMessage;
25
+ readBody(): Promise<string>;
26
+ }
27
+ export interface IRequestInfo {
28
+ options: http.RequestOptions;
29
+ parsedUrl: URL;
30
+ httpModule: any;
31
+ }
32
+ export interface IRequestOptions {
33
+ headers?: IHeaders;
34
+ socketTimeout?: number;
35
+ ignoreSslError?: boolean;
36
+ allowRedirects?: boolean;
37
+ allowRedirectDowngrade?: boolean;
38
+ maxRedirects?: number;
39
+ maxSockets?: number;
40
+ keepAlive?: boolean;
41
+ deserializeDates?: boolean;
42
+ allowRetries?: boolean;
43
+ maxRetries?: number;
44
+ }
45
+ export interface ITypedResponse<T> {
46
+ statusCode: number;
47
+ result: T | null;
48
+ headers: Object;
49
+ }
package/interfaces.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actions/http-client",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Actions Http Client",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/proxy.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function getProxyUrl(reqUrl: URL): URL | undefined;
2
+ export declare function checkBypass(reqUrl: URL): boolean;
package/proxy.js ADDED
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function getProxyUrl(reqUrl) {
4
+ let usingSsl = reqUrl.protocol === 'https:';
5
+ let proxyUrl;
6
+ if (checkBypass(reqUrl)) {
7
+ return proxyUrl;
8
+ }
9
+ let proxyVar;
10
+ if (usingSsl) {
11
+ proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY'];
12
+ }
13
+ else {
14
+ proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY'];
15
+ }
16
+ if (proxyVar) {
17
+ proxyUrl = new URL(proxyVar);
18
+ }
19
+ return proxyUrl;
20
+ }
21
+ exports.getProxyUrl = getProxyUrl;
22
+ function checkBypass(reqUrl) {
23
+ if (!reqUrl.hostname) {
24
+ return false;
25
+ }
26
+ let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
27
+ if (!noProxy) {
28
+ return false;
29
+ }
30
+ // Determine the request port
31
+ let reqPort;
32
+ if (reqUrl.port) {
33
+ reqPort = Number(reqUrl.port);
34
+ }
35
+ else if (reqUrl.protocol === 'http:') {
36
+ reqPort = 80;
37
+ }
38
+ else if (reqUrl.protocol === 'https:') {
39
+ reqPort = 443;
40
+ }
41
+ // Format the request hostname and hostname with port
42
+ let upperReqHosts = [reqUrl.hostname.toUpperCase()];
43
+ if (typeof reqPort === 'number') {
44
+ upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
45
+ }
46
+ // Compare request host against noproxy
47
+ for (let upperNoProxyItem of noProxy
48
+ .split(',')
49
+ .map(x => x.trim().toUpperCase())
50
+ .filter(x => x)) {
51
+ if (upperReqHosts.some(x => x === upperNoProxyItem)) {
52
+ return true;
53
+ }
54
+ }
55
+ return false;
56
+ }
57
+ exports.checkBypass = checkBypass;