mirror of
https://github.com/actions/http-client.git
synced 2025-04-21 09:42:29 +00:00
parent
60c8242c8c
commit
cadfa571cb
38
.github/workflows/test.yml
vendored
38
.github/workflows/test.yml
vendored
@ -1,16 +1,15 @@
|
||||
name: http-tests
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
|
||||
@ -23,22 +22,25 @@ jobs:
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
- name: Compile
|
||||
run: npm run build
|
||||
- name: Compile
|
||||
run: npm run build
|
||||
|
||||
- name: npm test
|
||||
run: npm test
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: audit security
|
||||
run: npm audit
|
||||
- name: npm test
|
||||
run: npm test
|
||||
|
||||
- name: audit security
|
||||
run: npm audit
|
||||
|
117
auth.ts
117
auth.ts
@ -1,71 +1,86 @@
|
||||
|
||||
import ifm = require('./interfaces');
|
||||
import ifm = require("./interfaces");
|
||||
|
||||
export class BasicCredentialHandler implements ifm.IRequestHandler {
|
||||
username: string;
|
||||
password: string;
|
||||
username: string;
|
||||
password: string;
|
||||
|
||||
constructor(username: string, password: string) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
constructor(username: string, password: string) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
prepareRequest(options:any): void {
|
||||
options.headers['Authorization'] = 'Basic ' + Buffer.from(this.username + ':' + this.password).toString('base64');
|
||||
}
|
||||
prepareRequest(options: any): void {
|
||||
options.headers["Authorization"] =
|
||||
"Basic " +
|
||||
Buffer.from(this.username + ":" + this.password).toString("base64");
|
||||
}
|
||||
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
handleAuthentication(
|
||||
httpClient: ifm.IHttpClient,
|
||||
requestInfo: ifm.IRequestInfo,
|
||||
objs
|
||||
): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class BearerCredentialHandler implements ifm.IRequestHandler {
|
||||
token: string;
|
||||
token: string;
|
||||
|
||||
constructor(token: string) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(token: string) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
// currently implements pre-authorization
|
||||
// TODO: support preAuth = false where it hooks on 401
|
||||
prepareRequest(options:any): void {
|
||||
options.headers['Authorization'] = 'Bearer ' + this.token;
|
||||
}
|
||||
// currently implements pre-authorization
|
||||
// TODO: support preAuth = false where it hooks on 401
|
||||
prepareRequest(options: any): void {
|
||||
options.headers["Authorization"] = "Bearer " + this.token;
|
||||
}
|
||||
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
handleAuthentication(
|
||||
httpClient: ifm.IHttpClient,
|
||||
requestInfo: ifm.IRequestInfo,
|
||||
objs
|
||||
): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class PersonalAccessTokenCredentialHandler implements ifm.IRequestHandler {
|
||||
token: string;
|
||||
export class PersonalAccessTokenCredentialHandler
|
||||
implements ifm.IRequestHandler {
|
||||
token: string;
|
||||
|
||||
constructor(token: string) {
|
||||
this.token = token;
|
||||
}
|
||||
constructor(token: string) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
// currently implements pre-authorization
|
||||
// TODO: support preAuth = false where it hooks on 401
|
||||
prepareRequest(options:any): void {
|
||||
options.headers['Authorization'] = 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64');
|
||||
}
|
||||
// currently implements pre-authorization
|
||||
// TODO: support preAuth = false where it hooks on 401
|
||||
prepareRequest(options: any): void {
|
||||
options.headers["Authorization"] =
|
||||
"Basic " + Buffer.from("PAT:" + this.token).toString("base64");
|
||||
}
|
||||
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
// This handler cannot handle 401
|
||||
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
handleAuthentication(
|
||||
httpClient: ifm.IHttpClient,
|
||||
requestInfo: ifm.IRequestInfo,
|
||||
objs
|
||||
): Promise<ifm.IHttpClientResponse> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
112
interfaces.ts
112
interfaces.ts
@ -1,55 +1,99 @@
|
||||
import http = require("http");
|
||||
import url = require("url");
|
||||
|
||||
export interface IHeaders { [key: string]: any };
|
||||
export interface IHeaders {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface IHttpClient {
|
||||
options(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
get(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
del(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
post(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
patch(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
put(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
sendStream(verb: string, requestUrl: string, stream: NodeJS.ReadableStream, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>;
|
||||
request(verb: string, requestUrl: string, data: string | NodeJS.ReadableStream, headers: IHeaders): Promise<IHttpClientResponse>;
|
||||
requestRaw(info: IRequestInfo, data: string | NodeJS.ReadableStream): Promise<IHttpClientResponse>;
|
||||
requestRawWithCallback(info: IRequestInfo, data: string | NodeJS.ReadableStream, onResult: (err: any, res: IHttpClientResponse) => void): void;
|
||||
options(
|
||||
requestUrl: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
get(
|
||||
requestUrl: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
del(
|
||||
requestUrl: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
post(
|
||||
requestUrl: string,
|
||||
data: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
patch(
|
||||
requestUrl: string,
|
||||
data: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
put(
|
||||
requestUrl: string,
|
||||
data: string,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
sendStream(
|
||||
verb: string,
|
||||
requestUrl: string,
|
||||
stream: NodeJS.ReadableStream,
|
||||
additionalHeaders?: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
request(
|
||||
verb: string,
|
||||
requestUrl: string,
|
||||
data: string | NodeJS.ReadableStream,
|
||||
headers: IHeaders
|
||||
): Promise<IHttpClientResponse>;
|
||||
requestRaw(
|
||||
info: IRequestInfo,
|
||||
data: string | NodeJS.ReadableStream
|
||||
): Promise<IHttpClientResponse>;
|
||||
requestRawWithCallback(
|
||||
info: IRequestInfo,
|
||||
data: string | NodeJS.ReadableStream,
|
||||
onResult: (err: any, res: IHttpClientResponse) => void
|
||||
): void;
|
||||
}
|
||||
|
||||
export interface IRequestHandler {
|
||||
prepareRequest(options: http.RequestOptions): void;
|
||||
canHandleAuthentication(response: IHttpClientResponse): boolean;
|
||||
handleAuthentication(httpClient: IHttpClient, requestInfo: IRequestInfo, objs): Promise<IHttpClientResponse>;
|
||||
prepareRequest(options: http.RequestOptions): void;
|
||||
canHandleAuthentication(response: IHttpClientResponse): boolean;
|
||||
handleAuthentication(
|
||||
httpClient: IHttpClient,
|
||||
requestInfo: IRequestInfo,
|
||||
objs
|
||||
): Promise<IHttpClientResponse>;
|
||||
}
|
||||
|
||||
export interface IHttpClientResponse {
|
||||
message: http.IncomingMessage;
|
||||
readBody(): Promise<string>;
|
||||
message: http.IncomingMessage;
|
||||
readBody(): Promise<string>;
|
||||
}
|
||||
|
||||
export interface IRequestInfo {
|
||||
options: http.RequestOptions;
|
||||
parsedUrl: url.Url;
|
||||
httpModule: any;
|
||||
options: http.RequestOptions;
|
||||
parsedUrl: url.Url;
|
||||
httpModule: any;
|
||||
}
|
||||
|
||||
export interface IRequestOptions {
|
||||
headers?: IHeaders;
|
||||
socketTimeout?: number;
|
||||
ignoreSslError?: boolean;
|
||||
allowRedirects?: boolean;
|
||||
allowRedirectDowngrade?: boolean;
|
||||
maxRedirects?: number;
|
||||
maxSockets?: number;
|
||||
keepAlive?: boolean;
|
||||
deserializeDates?: boolean;
|
||||
// Allows retries only on Read operations (since writes may not be idempotent)
|
||||
allowRetries?: boolean;
|
||||
maxRetries?: number;
|
||||
headers?: IHeaders;
|
||||
socketTimeout?: number;
|
||||
ignoreSslError?: boolean;
|
||||
allowRedirects?: boolean;
|
||||
allowRedirectDowngrade?: boolean;
|
||||
maxRedirects?: number;
|
||||
maxSockets?: number;
|
||||
keepAlive?: boolean;
|
||||
deserializeDates?: boolean;
|
||||
// Allows retries only on Read operations (since writes may not be idempotent)
|
||||
allowRetries?: boolean;
|
||||
maxRetries?: number;
|
||||
}
|
||||
|
||||
export interface ITypedResponse<T> {
|
||||
statusCode: number,
|
||||
result: T | null,
|
||||
headers: Object
|
||||
statusCode: number;
|
||||
result: T | null;
|
||||
headers: Object;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
moduleFileExtensions: ["js", "ts"],
|
||||
testEnvironment: "node",
|
||||
testMatch: ["**/__tests__/*.test.ts"],
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
"^.+\\.ts$": "ts-jest",
|
||||
},
|
||||
verbose: true
|
||||
}
|
||||
verbose: true,
|
||||
};
|
||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -3413,6 +3413,12 @@
|
||||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz",
|
||||
"integrity": "sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==",
|
||||
"dev": true
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "25.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz",
|
||||
|
@ -5,6 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "rm -Rf ./_out && tsc && cp package*.json ./_out && cp *.md ./_out && cp LICENSE ./_out && cp actions.png ./_out",
|
||||
"lint": "prettier --check *.{ts,js,json} **/*.yml",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
@ -25,6 +26,7 @@
|
||||
"@types/jest": "^25.1.4",
|
||||
"@types/node": "^12.12.31",
|
||||
"jest": "^25.1.0",
|
||||
"prettier": "2.0.4",
|
||||
"proxy": "^1.0.1",
|
||||
"ts-jest": "^25.2.1",
|
||||
"typescript": "^3.8.3"
|
||||
|
101
proxy.ts
101
proxy.ts
@ -1,65 +1,62 @@
|
||||
import * as url from 'url';
|
||||
import * as url from "url";
|
||||
|
||||
export function getProxyUrl(reqUrl: url.Url): url.Url | undefined {
|
||||
let usingSsl = reqUrl.protocol === 'https:';
|
||||
|
||||
let proxyUrl: url.Url;
|
||||
if (checkBypass(reqUrl)) {
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
let proxyVar: string;
|
||||
if (usingSsl) {
|
||||
proxyVar = process.env["https_proxy"] ||
|
||||
process.env["HTTPS_PROXY"];
|
||||
|
||||
} else {
|
||||
proxyVar = process.env["http_proxy"] ||
|
||||
process.env["HTTP_PROXY"];
|
||||
}
|
||||
|
||||
if (proxyVar) {
|
||||
proxyUrl = url.parse(proxyVar);
|
||||
}
|
||||
let usingSsl = reqUrl.protocol === "https:";
|
||||
|
||||
let proxyUrl: url.Url;
|
||||
if (checkBypass(reqUrl)) {
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
let proxyVar: string;
|
||||
if (usingSsl) {
|
||||
proxyVar = process.env["https_proxy"] || process.env["HTTPS_PROXY"];
|
||||
} else {
|
||||
proxyVar = process.env["http_proxy"] || process.env["HTTP_PROXY"];
|
||||
}
|
||||
|
||||
if (proxyVar) {
|
||||
proxyUrl = url.parse(proxyVar);
|
||||
}
|
||||
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
|
||||
export function checkBypass(reqUrl: url.Url): boolean {
|
||||
if (!reqUrl.hostname) {
|
||||
return false
|
||||
}
|
||||
if (!reqUrl.hostname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let noProxy = process.env["no_proxy"] || process.env["NO_PROXY"] || '';
|
||||
if (!noProxy) {
|
||||
return false
|
||||
}
|
||||
let noProxy = process.env["no_proxy"] || process.env["NO_PROXY"] || "";
|
||||
if (!noProxy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine the request port
|
||||
let reqPort: number
|
||||
if (reqUrl.port) {
|
||||
reqPort = Number(reqUrl.port)
|
||||
}
|
||||
else if (reqUrl.protocol === 'http:') {
|
||||
reqPort = 80
|
||||
}
|
||||
else if (reqUrl.protocol === 'https:') {
|
||||
reqPort = 443
|
||||
}
|
||||
// Determine the request port
|
||||
let reqPort: number;
|
||||
if (reqUrl.port) {
|
||||
reqPort = Number(reqUrl.port);
|
||||
} else if (reqUrl.protocol === "http:") {
|
||||
reqPort = 80;
|
||||
} else if (reqUrl.protocol === "https:") {
|
||||
reqPort = 443;
|
||||
}
|
||||
|
||||
// Format the request hostname and hostname with port
|
||||
let upperReqHosts = [reqUrl.hostname.toUpperCase()]
|
||||
if (typeof reqPort === 'number') {
|
||||
upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`)
|
||||
}
|
||||
// Format the request hostname and hostname with port
|
||||
let upperReqHosts = [reqUrl.hostname.toUpperCase()];
|
||||
if (typeof reqPort === "number") {
|
||||
upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`);
|
||||
}
|
||||
|
||||
// Compare request host against noproxy
|
||||
for (let upperNoProxyItem of noProxy.split(',').map(x => x.trim().toUpperCase()).filter(x => x)) {
|
||||
if (upperReqHosts.some(x => x === upperNoProxyItem)) {
|
||||
return true
|
||||
}
|
||||
// Compare request host against noproxy
|
||||
for (let upperNoProxyItem of noProxy
|
||||
.split(",")
|
||||
.map((x) => x.trim().toUpperCase())
|
||||
.filter((x) => x)) {
|
||||
if (upperReqHosts.some((x) => x === upperNoProxyItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"typeRoots": [ "node_modules/@types" ],
|
||||
"declaration": true,
|
||||
"outDir": "_out",
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
"auth.ts"
|
||||
]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"declaration": true,
|
||||
"outDir": "_out",
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": ["index.ts", "auth.ts"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user