apply formatting

This commit is contained in:
Bryan MacFarlane 2020-04-10 09:50:06 -04:00
parent c715044f28
commit 7af5adfb99
12 changed files with 1573 additions and 1234 deletions

View File

@ -40,8 +40,8 @@ jobs:
- name: npm test - name: npm test
run: npm test run: npm test
# - name: Format - name: Format
# run: npm run format-check run: npm run format-check
- name: audit security - name: audit security
run: npm audit --audit-level=moderate run: npm audit --audit-level=moderate

View File

@ -1,56 +1,61 @@
import * as httpm from '../_out'; import * as httpm from '../_out'
import * as am from '../_out/auth'; import * as am from '../_out/auth'
describe('auth', () => { describe('auth', () => {
beforeEach(() => { beforeEach(() => {})
afterEach(() => {})
it('does basic http get request with basic auth', async () => {
let bh: am.BasicCredentialHandler = new am.BasicCredentialHandler(
'johndoe',
'password'
)
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [bh])
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get')
expect(res.message.statusCode).toBe(200)
let body: string = await res.readBody()
let obj: any = JSON.parse(body)
let auth: string = obj.headers.Authorization
let creds: string = Buffer.from(
auth.substring('Basic '.length),
'base64'
).toString()
expect(creds).toBe('johndoe:password')
expect(obj.url).toBe('http://httpbin.org/get')
}) })
afterEach(() => { it('does basic http get request with pat token auth', async () => {
let token: string = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs'
let ph: am.PersonalAccessTokenCredentialHandler = new am.PersonalAccessTokenCredentialHandler(
token
)
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ph])
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get')
expect(res.message.statusCode).toBe(200)
let body: string = await res.readBody()
let obj: any = JSON.parse(body)
let auth: string = obj.headers.Authorization
let creds: string = Buffer.from(
auth.substring('Basic '.length),
'base64'
).toString()
expect(creds).toBe('PAT:' + token)
expect(obj.url).toBe('http://httpbin.org/get')
}) })
it('does basic http get request with basic auth', async() => { it('does basic http get request with pat token auth', async () => {
let bh: am.BasicCredentialHandler = new am.BasicCredentialHandler('johndoe', 'password'); let token: string = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs'
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [bh]); let ph: am.BearerCredentialHandler = new am.BearerCredentialHandler(token)
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get');
expect(res.message.statusCode).toBe(200);
let body: string = await res.readBody();
let obj:any = JSON.parse(body);
let auth: string = obj.headers.Authorization;
let creds: string = Buffer.from(auth.substring('Basic '.length), 'base64').toString();
expect(creds).toBe('johndoe:password');
expect(obj.url).toBe("http://httpbin.org/get");
});
it('does basic http get request with pat token auth', async() => { let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ph])
let token: string = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs'; let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get')
let ph: am.PersonalAccessTokenCredentialHandler = expect(res.message.statusCode).toBe(200)
new am.PersonalAccessTokenCredentialHandler(token); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ph]); let auth: string = obj.headers.Authorization
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get'); expect(auth).toBe('Bearer ' + token)
expect(res.message.statusCode).toBe(200); expect(obj.url).toBe('http://httpbin.org/get')
let body: string = await res.readBody(); })
let obj:any = JSON.parse(body);
let auth: string = obj.headers.Authorization;
let creds: string = Buffer.from(auth.substring('Basic '.length), 'base64').toString();
expect(creds).toBe('PAT:' + token);
expect(obj.url).toBe("http://httpbin.org/get");
});
it('does basic http get request with pat token auth', async() => {
let token: string = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs';
let ph: am.BearerCredentialHandler =
new am.BearerCredentialHandler(token);
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ph]);
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get');
expect(res.message.statusCode).toBe(200);
let body: string = await res.readBody();
let obj:any = JSON.parse(body);
let auth: string = obj.headers.Authorization;
expect(auth).toBe('Bearer ' + token);
expect(obj.url).toBe("http://httpbin.org/get");
});
}) })

View File

@ -1,33 +1,31 @@
import * as httpm from '../_out'; import * as httpm from '../_out'
import * as ifm from '../_out/interfaces' import * as ifm from '../_out/interfaces'
import * as path from 'path'; import * as path from 'path'
import * as fs from 'fs'; import * as fs from 'fs'
let sampleFilePath: string = path.join(__dirname, 'testoutput.txt'); let sampleFilePath: string = path.join(__dirname, 'testoutput.txt')
interface HttpBinData { interface HttpBinData {
url: string; url: string
data: any; data: any
json: any; json: any
headers: any; headers: any
args?: any args?: any
} }
describe('basics', () => { describe('basics', () => {
let _http: httpm.HttpClient; let _http: httpm.HttpClient
beforeEach(() => { beforeEach(() => {
_http = new httpm.HttpClient('http-client-tests'); _http = new httpm.HttpClient('http-client-tests')
}) })
afterEach(() => { afterEach(() => {})
})
it('constructs', () => { it('constructs', () => {
let http: httpm.HttpClient = new httpm.HttpClient('thttp-client-tests'); let http: httpm.HttpClient = new httpm.HttpClient('thttp-client-tests')
expect(http).toBeDefined(); expect(http).toBeDefined()
}); })
// responses from httpbin return something like: // responses from httpbin return something like:
// { // {
@ -41,216 +39,291 @@ describe('basics', () => {
// "url": "https://httpbin.org/get" // "url": "https://httpbin.org/get"
// } // }
it('does basic http get request', async(done) => { it('does basic http get request', async done => {
let res: httpm.HttpClientResponse = await _http.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/get"); let body: string = await res.readBody()
expect(obj.headers["User-Agent"]).toBeTruthy(); let obj: any = JSON.parse(body)
done(); expect(obj.url).toBe('http://httpbin.org/get')
}); expect(obj.headers['User-Agent']).toBeTruthy()
done()
})
it('does basic http get request with no user agent', async(done) => { it('does basic http get request with no user agent', async done => {
let http: httpm.HttpClient = new httpm.HttpClient(); let http: httpm.HttpClient = new httpm.HttpClient()
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get')
expect(res.message.statusCode).toBe(200); expect(res.message.statusCode).toBe(200)
let body: string = await res.readBody(); let body: string = await res.readBody()
let obj: any = JSON.parse(body); let obj: any = JSON.parse(body)
expect(obj.url).toBe("http://httpbin.org/get"); expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.headers["User-Agent"]).toBeFalsy(); expect(obj.headers['User-Agent']).toBeFalsy()
done(); done()
}); })
it('does basic https get request', async(done) => { it('does basic https get request', async done => {
let res: httpm.HttpClientResponse = await _http.get('https://httpbin.org/get'); let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(200); 'https://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("https://httpbin.org/get"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.url).toBe('https://httpbin.org/get')
done()
})
it('does basic http get request with default headers', async(done) => { it('does basic http get request with default headers', async done => {
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [], { let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [], {
headers: { headers: {
'Accept': 'application/json', Accept: 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}); })
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get')
expect(res.message.statusCode).toBe(200); expect(res.message.statusCode).toBe(200)
let body: string = await res.readBody(); let body: string = await res.readBody()
let obj:any = JSON.parse(body); let obj: any = JSON.parse(body)
expect(obj.headers.Accept).toBe('application/json'); expect(obj.headers.Accept).toBe('application/json')
expect(obj.headers['Content-Type']).toBe('application/json'); expect(obj.headers['Content-Type']).toBe('application/json')
expect(obj.url).toBe("http://httpbin.org/get"); expect(obj.url).toBe('http://httpbin.org/get')
done(); done()
}); })
it('does basic http get request with merged headers', async(done) => { it('does basic http get request with merged headers', async done => {
let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [], { let http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [], {
headers: { headers: {
'Accept': 'application/json', Accept: 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}); })
let res: httpm.HttpClientResponse = await http.get('http://httpbin.org/get', { let res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get',
{
'content-type': 'application/x-www-form-urlencoded' 'content-type': 'application/x-www-form-urlencoded'
}); }
expect(res.message.statusCode).toBe(200); )
let body: string = await res.readBody(); expect(res.message.statusCode).toBe(200)
let obj:any = JSON.parse(body); let body: string = await res.readBody()
expect(obj.headers.Accept).toBe('application/json'); let obj: any = JSON.parse(body)
expect(obj.headers['Content-Type']).toBe('application/x-www-form-urlencoded'); expect(obj.headers.Accept).toBe('application/json')
expect(obj.url).toBe("http://httpbin.org/get"); expect(obj.headers['Content-Type']).toBe(
done(); 'application/x-www-form-urlencoded'
}); )
expect(obj.url).toBe('http://httpbin.org/get')
done()
})
it('pipes a get request', () => { it('pipes a get request', () => {
return new Promise<string>(async (resolve, reject) => { return new Promise<string>(async (resolve, reject) => {
let file: NodeJS.WritableStream = fs.createWriteStream(sampleFilePath); let file: NodeJS.WritableStream = fs.createWriteStream(sampleFilePath)
(await _http.get('https://httpbin.org/get')).message.pipe(file).on('close', () => { ;(await _http.get('https://httpbin.org/get')).message
let body: string = fs.readFileSync(sampleFilePath).toString(); .pipe(file)
let obj:any = JSON.parse(body); .on('close', () => {
expect(obj.url).toBe("https://httpbin.org/get"); let body: string = fs.readFileSync(sampleFilePath).toString()
resolve(); let obj: any = JSON.parse(body)
}); expect(obj.url).toBe('https://httpbin.org/get')
}); resolve()
}); })
})
})
it('does basic get request with redirects', async(done) => { it('does basic get request with redirects', async done => {
let res: httpm.HttpClientResponse = await _http.get("https://httpbin.org/redirect-to?url=" + encodeURIComponent("https://httpbin.org/get")) let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(200); 'https://httpbin.org/redirect-to?url=' +
let body: string = await res.readBody(); encodeURIComponent('https://httpbin.org/get')
let obj:any = JSON.parse(body); )
expect(obj.url).toBe("https://httpbin.org/get"); expect(res.message.statusCode).toBe(200)
done(); let body: string = await res.readBody()
}); let obj: any = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
done()
})
it('does basic get request with redirects (303)', async(done) => { it('does basic get request with redirects (303)', async done => {
let res: httpm.HttpClientResponse = await _http.get("https://httpbin.org/redirect-to?url=" + encodeURIComponent("https://httpbin.org/get") + '&status_code=303') let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(200); 'https://httpbin.org/redirect-to?url=' +
let body: string = await res.readBody(); encodeURIComponent('https://httpbin.org/get') +
let obj:any = JSON.parse(body); '&status_code=303'
expect(obj.url).toBe("https://httpbin.org/get"); )
done(); expect(res.message.statusCode).toBe(200)
}); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
done()
})
it('returns 404 for not found get request on redirect', async(done) => { it('returns 404 for not found get request on redirect', async done => {
let res: httpm.HttpClientResponse = await _http.get("https://httpbin.org/redirect-to?url=" + encodeURIComponent("https://httpbin.org/status/404") + '&status_code=303') let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(404); 'https://httpbin.org/redirect-to?url=' +
let body: string = await res.readBody(); encodeURIComponent('https://httpbin.org/status/404') +
done(); '&status_code=303'
}); )
expect(res.message.statusCode).toBe(404)
let body: string = await res.readBody()
done()
})
it('does not follow redirects if disabled', async(done) => { it('does not follow redirects if disabled', async done => {
let http: httpm.HttpClient = new httpm.HttpClient('typed-test-client-tests', null, { allowRedirects: false }); let http: httpm.HttpClient = new httpm.HttpClient(
let res: httpm.HttpClientResponse = await http.get("https://httpbin.org/redirect-to?url=" + encodeURIComponent("https://httpbin.org/get")) 'typed-test-client-tests',
expect(res.message.statusCode).toBe(302); null,
let body: string = await res.readBody(); {allowRedirects: false}
done(); )
}); let res: httpm.HttpClientResponse = await http.get(
'https://httpbin.org/redirect-to?url=' +
encodeURIComponent('https://httpbin.org/get')
)
expect(res.message.statusCode).toBe(302)
let body: string = await res.readBody()
done()
})
it('does basic head request', async(done) => { it('does basic head request', async done => {
let res: httpm.HttpClientResponse = await _http.head('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await _http.head(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
done(); )
}); expect(res.message.statusCode).toBe(200)
done()
})
it('does basic http delete request', async(done) => { it('does basic http delete request', async done => {
let res: httpm.HttpClientResponse = await _http.del('http://httpbin.org/delete'); let res: httpm.HttpClientResponse = await _http.del(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/delete'
let body: string = await res.readBody(); )
let obj:any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
done(); let body: string = await res.readBody()
}); let obj: any = JSON.parse(body)
done()
})
it('does basic http post request', async(done) => { it('does basic http post request', async done => {
let b: string = 'Hello World!'; let b: string = 'Hello World!'
let res: httpm.HttpClientResponse = await _http.post('http://httpbin.org/post', b); let res: httpm.HttpClientResponse = await _http.post(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/post',
let body: string = await res.readBody(); b
let obj:any = JSON.parse(body); )
expect(obj.data).toBe(b); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/post"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/post')
done()
})
it('does basic http patch request', async(done) => { it('does basic http patch request', async done => {
let b: string = 'Hello World!'; let b: string = 'Hello World!'
let res: httpm.HttpClientResponse = await _http.patch('http://httpbin.org/patch', b); let res: httpm.HttpClientResponse = await _http.patch(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/patch',
let body: string = await res.readBody(); b
let obj:any = JSON.parse(body); )
expect(obj.data).toBe(b); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/patch"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/patch')
done()
})
it('does basic http options request', async(done) => { it('does basic http options request', async done => {
let res: httpm.HttpClientResponse = await _http.options('http://httpbin.org'); let res: httpm.HttpClientResponse = await _http.options(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org'
let body: string = await res.readBody(); )
done(); expect(res.message.statusCode).toBe(200)
}); let body: string = await res.readBody()
done()
})
it('returns 404 for not found get request', async(done) => { it('returns 404 for not found get request', async done => {
let res: httpm.HttpClientResponse = await _http.get('http://httpbin.org/status/404'); let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(404); 'http://httpbin.org/status/404'
let body: string = await res.readBody(); )
done(); expect(res.message.statusCode).toBe(404)
}); let body: string = await res.readBody()
done()
})
it('gets a json object', async() => { it('gets a json object', async () => {
let jsonObj: ifm.ITypedResponse<HttpBinData> = await _http.getJson<HttpBinData>('https://httpbin.org/get'); let jsonObj: ifm.ITypedResponse<HttpBinData> = await _http.getJson<
expect(jsonObj.statusCode).toBe(200); HttpBinData
expect(jsonObj.result).toBeDefined(); >('https://httpbin.org/get')
expect(jsonObj.result.url).toBe('https://httpbin.org/get'); expect(jsonObj.statusCode).toBe(200)
expect(jsonObj.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson); expect(jsonObj.result).toBeDefined()
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); expect(jsonObj.result.url).toBe('https://httpbin.org/get')
}); expect(jsonObj.result.headers['Accept']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
it('getting a non existent json object returns null', async() => { it('getting a non existent json object returns null', async () => {
let jsonObj: ifm.ITypedResponse<HttpBinData> = await _http.getJson<HttpBinData>('https://httpbin.org/status/404'); let jsonObj: ifm.ITypedResponse<HttpBinData> = await _http.getJson<
expect(jsonObj.statusCode).toBe(404); HttpBinData
expect(jsonObj.result).toBeNull(); >('https://httpbin.org/status/404')
}); expect(jsonObj.statusCode).toBe(404)
expect(jsonObj.result).toBeNull()
})
it('posts a json object', async() => { it('posts a json object', async () => {
let res: any = { name: 'foo' }; let res: any = {name: 'foo'}
let restRes: ifm.ITypedResponse<HttpBinData> = await _http.postJson<HttpBinData>('https://httpbin.org/post', res); let restRes: ifm.ITypedResponse<HttpBinData> = await _http.postJson<
expect(restRes.statusCode).toBe(200); HttpBinData
expect(restRes.result).toBeDefined(); >('https://httpbin.org/post', res)
expect(restRes.result.url).toBe('https://httpbin.org/post'); expect(restRes.statusCode).toBe(200)
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result).toBeDefined()
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.url).toBe('https://httpbin.org/post')
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.json.name).toBe('foo')
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.headers['Accept']).toBe(
}); httpm.MediaTypes.ApplicationJson
)
expect(restRes.result.headers['Content-Type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
it('puts a json object', async() => { it('puts a json object', async () => {
let res: any = { name: 'foo' }; let res: any = {name: 'foo'}
let restRes: ifm.ITypedResponse<HttpBinData> = await _http.putJson<HttpBinData>('https://httpbin.org/put', res); let restRes: ifm.ITypedResponse<HttpBinData> = await _http.putJson<
expect(restRes.statusCode).toBe(200); HttpBinData
expect(restRes.result).toBeDefined(); >('https://httpbin.org/put', res)
expect(restRes.result.url).toBe('https://httpbin.org/put'); expect(restRes.statusCode).toBe(200)
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result).toBeDefined()
expect(restRes.result.url).toBe('https://httpbin.org/put')
expect(restRes.result.json.name).toBe('foo')
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.headers['Accept']).toBe(
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson); httpm.MediaTypes.ApplicationJson
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); )
}); expect(restRes.result.headers['Content-Type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
it('patch a json object', async() => { it('patch a json object', async () => {
let res: any = { name: 'foo' }; let res: any = {name: 'foo'}
let restRes: ifm.ITypedResponse<HttpBinData> = await _http.patchJson<HttpBinData>('https://httpbin.org/patch', res); let restRes: ifm.ITypedResponse<HttpBinData> = await _http.patchJson<
expect(restRes.statusCode).toBe(200); HttpBinData
expect(restRes.result).toBeDefined(); >('https://httpbin.org/patch', res)
expect(restRes.result.url).toBe('https://httpbin.org/patch'); expect(restRes.statusCode).toBe(200)
expect(restRes.result.json.name).toBe('foo'); expect(restRes.result).toBeDefined()
expect(restRes.result.headers["Accept"]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.url).toBe('https://httpbin.org/patch')
expect(restRes.result.headers["Content-Type"]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.json.name).toBe('foo')
expect(restRes.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); expect(restRes.result.headers['Accept']).toBe(
}); httpm.MediaTypes.ApplicationJson
}); )
expect(restRes.result.headers['Content-Type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
})

View File

@ -1,79 +1,115 @@
import * as httpm from '../_out'; import * as httpm from '../_out'
import * as ifm from '../_out/interfaces' import * as ifm from '../_out/interfaces'
describe('headers', () => { describe('headers', () => {
let _http: httpm.HttpClient; let _http: httpm.HttpClient
beforeEach(() => { beforeEach(() => {
_http = new httpm.HttpClient('http-client-tests'); _http = new httpm.HttpClient('http-client-tests')
}); })
it('preserves existing headers on getJson', async() => { it('preserves existing headers on getJson', async () => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" }; let additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj: ifm.ITypedResponse<any> = await _http.getJson<any>('https://httpbin.org/get', additionalHeaders); let jsonObj: ifm.ITypedResponse<any> = await _http.getJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("foo"); 'https://httpbin.org/get',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
let httpWithHeaders = new httpm.HttpClient(); let httpWithHeaders = new httpm.HttpClient()
httpWithHeaders.requestOptions = { httpWithHeaders.requestOptions = {
headers: { headers: {
[httpm.Headers.Accept]: "baz" [httpm.Headers.Accept]: 'baz'
} }
}; }
jsonObj = await httpWithHeaders.getJson<any>('https://httpbin.org/get'); jsonObj = await httpWithHeaders.getJson<any>('https://httpbin.org/get')
expect(jsonObj.result.headers["Accept"]).toBe("baz"); expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
}); httpm.MediaTypes.ApplicationJson
)
})
it('preserves existing headers on postJson', async() => { it('preserves existing headers on postJson', async () => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" }; let additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj: ifm.ITypedResponse<any> = await _http.postJson<any>('https://httpbin.org/post', {}, additionalHeaders); let jsonObj: ifm.ITypedResponse<any> = await _http.postJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("foo"); 'https://httpbin.org/post',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); {},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
let httpWithHeaders = new httpm.HttpClient(); let httpWithHeaders = new httpm.HttpClient()
httpWithHeaders.requestOptions = { httpWithHeaders.requestOptions = {
headers: { headers: {
[httpm.Headers.Accept]: "baz" [httpm.Headers.Accept]: 'baz'
} }
}; }
jsonObj = await httpWithHeaders.postJson<any>('https://httpbin.org/post', {}); jsonObj = await httpWithHeaders.postJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("baz"); 'https://httpbin.org/post',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); {}
}); )
expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
it('preserves existing headers on putJson', async() => { it('preserves existing headers on putJson', async () => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" }; let additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj: ifm.ITypedResponse<any> = await _http.putJson<any>('https://httpbin.org/put', {}, additionalHeaders); let jsonObj: ifm.ITypedResponse<any> = await _http.putJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("foo"); 'https://httpbin.org/put',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); {},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
let httpWithHeaders = new httpm.HttpClient(); let httpWithHeaders = new httpm.HttpClient()
httpWithHeaders.requestOptions = { httpWithHeaders.requestOptions = {
headers: { headers: {
[httpm.Headers.Accept]: "baz" [httpm.Headers.Accept]: 'baz'
} }
}; }
jsonObj = await httpWithHeaders.putJson<any>('https://httpbin.org/put', {}); jsonObj = await httpWithHeaders.putJson<any>('https://httpbin.org/put', {})
expect(jsonObj.result.headers["Accept"]).toBe("baz"); expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
}); httpm.MediaTypes.ApplicationJson
)
})
it('preserves existing headers on patchJson', async() => { it('preserves existing headers on patchJson', async () => {
let additionalHeaders = { [httpm.Headers.Accept]: "foo" }; let additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj: ifm.ITypedResponse<any> = await _http.patchJson<any>('https://httpbin.org/patch', {}, additionalHeaders); let jsonObj: ifm.ITypedResponse<any> = await _http.patchJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("foo"); 'https://httpbin.org/patch',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); {},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
let httpWithHeaders = new httpm.HttpClient(); let httpWithHeaders = new httpm.HttpClient()
httpWithHeaders.requestOptions = { httpWithHeaders.requestOptions = {
headers: { headers: {
[httpm.Headers.Accept]: "baz" [httpm.Headers.Accept]: 'baz'
} }
}; }
jsonObj = await httpWithHeaders.patchJson<any>('https://httpbin.org/patch', {}); jsonObj = await httpWithHeaders.patchJson<any>(
expect(jsonObj.result.headers["Accept"]).toBe("baz"); 'https://httpbin.org/patch',
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(httpm.MediaTypes.ApplicationJson); {}
}); )
expect(jsonObj.result.headers['Accept']).toBe('baz')
}); expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
httpm.MediaTypes.ApplicationJson
)
})
})

View File

@ -1,65 +1,79 @@
import * as httpm from '../_out'; import * as httpm from '../_out'
describe('basics', () => { describe('basics', () => {
let _http: httpm.HttpClient; let _http: httpm.HttpClient
beforeEach(() => { beforeEach(() => {
_http = new httpm.HttpClient('http-client-tests', [], { keepAlive: true }); _http = new httpm.HttpClient('http-client-tests', [], {keepAlive: true})
}) })
afterEach(() => { afterEach(() => {
_http.dispose(); _http.dispose()
}) })
it('does basic http get request with keepAlive true', async(done) => { it('does basic http get request with keepAlive true', async done => {
let res: httpm.HttpClientResponse = await _http.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await _http.get(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
let body: string = await res.readBody(); )
let obj:any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/get"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.url).toBe('http://httpbin.org/get')
done()
})
it('does basic head request with keepAlive true', async(done) => { it('does basic head request with keepAlive true', async done => {
let res: httpm.HttpClientResponse = await _http.head('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await _http.head(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
done(); )
}); expect(res.message.statusCode).toBe(200)
done()
})
it('does basic http delete request with keepAlive true', async(done) => { it('does basic http delete request with keepAlive true', async done => {
let res: httpm.HttpClientResponse = await _http.del('http://httpbin.org/delete'); let res: httpm.HttpClientResponse = await _http.del(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/delete'
let body: string = await res.readBody(); )
let obj:any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
done(); let body: string = await res.readBody()
}); let obj: any = JSON.parse(body)
done()
})
it('does basic http post request with keepAlive true', async(done) => { it('does basic http post request with keepAlive true', async done => {
let b: string = 'Hello World!'; let b: string = 'Hello World!'
let res: httpm.HttpClientResponse = await _http.post('http://httpbin.org/post', b); let res: httpm.HttpClientResponse = await _http.post(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/post',
let body: string = await res.readBody(); b
let obj:any = JSON.parse(body); )
expect(obj.data).toBe(b); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/post"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/post')
done()
})
it('does basic http patch request with keepAlive true', async(done) => { it('does basic http patch request with keepAlive true', async done => {
let b: string = 'Hello World!'; let b: string = 'Hello World!'
let res: httpm.HttpClientResponse = await _http.patch('http://httpbin.org/patch', b); let res: httpm.HttpClientResponse = await _http.patch(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/patch',
let body: string = await res.readBody(); b
let obj:any = JSON.parse(body); )
expect(obj.data).toBe(b); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/patch"); let body: string = await res.readBody()
done(); let obj: any = JSON.parse(body)
}); expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/patch')
done()
})
it('does basic http options request with keepAlive true', async(done) => { it('does basic http options request with keepAlive true', async done => {
let res: httpm.HttpClientResponse = await _http.options('http://httpbin.org'); let res: httpm.HttpClientResponse = await _http.options(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org'
let body: string = await res.readBody(); )
done(); expect(res.message.statusCode).toBe(200)
}); let body: string = await res.readBody()
}); done()
})
})

View File

@ -1,8 +1,8 @@
import * as http from 'http' import * as http from 'http'
import * as httpm from '../_out'; import * as httpm from '../_out'
import * as pm from '../_out/proxy'; import * as pm from '../_out/proxy'
import * as proxy from 'proxy' import * as proxy from 'proxy'
import * as url from 'url'; import * as url from 'url'
let _proxyConnects: string[] let _proxyConnects: string[]
let _proxyServer: http.Server let _proxyServer: http.Server
@ -12,13 +12,13 @@ describe('proxy', () => {
beforeAll(async () => { beforeAll(async () => {
// Start proxy server // Start proxy server
_proxyServer = proxy() _proxyServer = proxy()
await new Promise((resolve) => { await new Promise(resolve => {
const port = Number(_proxyUrl.split(':')[2]) const port = Number(_proxyUrl.split(':')[2])
_proxyServer.listen(port, () => resolve()) _proxyServer.listen(port, () => resolve())
}) })
_proxyServer.on('connect', (req) => { _proxyServer.on('connect', req => {
_proxyConnects.push(req.url) _proxyConnects.push(req.url)
}); })
}) })
beforeEach(() => { beforeEach(() => {
@ -26,176 +26,183 @@ describe('proxy', () => {
_clearVars() _clearVars()
}) })
afterEach(() => { afterEach(() => {})
})
afterAll(async() => { afterAll(async () => {
_clearVars() _clearVars()
// Stop proxy server // Stop proxy server
await new Promise((resolve) => { await new Promise(resolve => {
_proxyServer.once('close', () => resolve()) _proxyServer.once('close', () => resolve())
_proxyServer.close() _proxyServer.close()
}) })
}) })
it('getProxyUrl does not return proxyUrl if variables not set', () => { it('getProxyUrl does not return proxyUrl if variables not set', () => {
let proxyUrl = pm.getProxyUrl(url.parse('https://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('https://github.com'))
expect(proxyUrl).toBeUndefined(); expect(proxyUrl).toBeUndefined()
}) })
it('getProxyUrl returns proxyUrl if https_proxy set for https url', () => { it('getProxyUrl returns proxyUrl if https_proxy set for https url', () => {
process.env["https_proxy"] = "https://myproxysvr"; process.env['https_proxy'] = 'https://myproxysvr'
let proxyUrl = pm.getProxyUrl(url.parse('https://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('https://github.com'))
expect(proxyUrl).toBeDefined(); expect(proxyUrl).toBeDefined()
}) })
it('getProxyUrl does not return proxyUrl if http_proxy set for https url', () => { it('getProxyUrl does not return proxyUrl if http_proxy set for https url', () => {
process.env["http_proxy"] = "https://myproxysvr"; process.env['http_proxy'] = 'https://myproxysvr'
let proxyUrl = pm.getProxyUrl(url.parse('https://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('https://github.com'))
expect(proxyUrl).toBeUndefined(); expect(proxyUrl).toBeUndefined()
}) })
it('getProxyUrl returns proxyUrl if http_proxy set for http url', () => { it('getProxyUrl returns proxyUrl if http_proxy set for http url', () => {
process.env["http_proxy"] = "http://myproxysvr"; process.env['http_proxy'] = 'http://myproxysvr'
let proxyUrl = pm.getProxyUrl(url.parse('http://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('http://github.com'))
expect(proxyUrl).toBeDefined(); expect(proxyUrl).toBeDefined()
}) })
it('getProxyUrl does not return proxyUrl if https_proxy set and in no_proxy list', () => { it('getProxyUrl does not return proxyUrl if https_proxy set and in no_proxy list', () => {
process.env["https_proxy"] = "https://myproxysvr"; process.env['https_proxy'] = 'https://myproxysvr'
process.env["no_proxy"] = "otherserver,myserver,anotherserver:8080" process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080'
let proxyUrl = pm.getProxyUrl(url.parse('https://myserver')); let proxyUrl = pm.getProxyUrl(url.parse('https://myserver'))
expect(proxyUrl).toBeUndefined(); expect(proxyUrl).toBeUndefined()
}) })
it('getProxyUrl returns proxyUrl if https_proxy set and not in no_proxy list', () => { it('getProxyUrl returns proxyUrl if https_proxy set and not in no_proxy list', () => {
process.env["https_proxy"] = "https://myproxysvr"; process.env['https_proxy'] = 'https://myproxysvr'
process.env["no_proxy"] = "otherserver,myserver,anotherserver:8080" process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080'
let proxyUrl = pm.getProxyUrl(url.parse('https://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('https://github.com'))
expect(proxyUrl).toBeDefined(); expect(proxyUrl).toBeDefined()
}) })
it('getProxyUrl does not return proxyUrl if http_proxy set and in no_proxy list', () => { it('getProxyUrl does not return proxyUrl if http_proxy set and in no_proxy list', () => {
process.env["http_proxy"] = "http://myproxysvr"; process.env['http_proxy'] = 'http://myproxysvr'
process.env["no_proxy"] = "otherserver,myserver,anotherserver:8080" process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080'
let proxyUrl = pm.getProxyUrl(url.parse('http://myserver')); let proxyUrl = pm.getProxyUrl(url.parse('http://myserver'))
expect(proxyUrl).toBeUndefined(); expect(proxyUrl).toBeUndefined()
}) })
it('getProxyUrl returns proxyUrl if http_proxy set and not in no_proxy list', () => { it('getProxyUrl returns proxyUrl if http_proxy set and not in no_proxy list', () => {
process.env["http_proxy"] = "http://myproxysvr"; process.env['http_proxy'] = 'http://myproxysvr'
process.env["no_proxy"] = "otherserver,myserver,anotherserver:8080" process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080'
let proxyUrl = pm.getProxyUrl(url.parse('http://github.com')); let proxyUrl = pm.getProxyUrl(url.parse('http://github.com'))
expect(proxyUrl).toBeDefined(); expect(proxyUrl).toBeDefined()
}) })
it('checkBypass returns true if host as no_proxy list', () => { it('checkBypass returns true if host as no_proxy list', () => {
process.env["no_proxy"] = "myserver" process.env['no_proxy'] = 'myserver'
let bypass = pm.checkBypass(url.parse('https://myserver')); let bypass = pm.checkBypass(url.parse('https://myserver'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host in no_proxy list', () => { it('checkBypass returns true if host in no_proxy list', () => {
process.env["no_proxy"] = "otherserver,myserver,anotherserver:8080" process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080'
let bypass = pm.checkBypass(url.parse('https://myserver')); let bypass = pm.checkBypass(url.parse('https://myserver'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host in no_proxy list with spaces', () => { it('checkBypass returns true if host in no_proxy list with spaces', () => {
process.env["no_proxy"] = "otherserver, myserver ,anotherserver:8080" process.env['no_proxy'] = 'otherserver, myserver ,anotherserver:8080'
let bypass = pm.checkBypass(url.parse('https://myserver')); let bypass = pm.checkBypass(url.parse('https://myserver'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host in no_proxy list with port', () => { it('checkBypass returns true if host in no_proxy list with port', () => {
process.env["no_proxy"] = "otherserver, myserver:8080 ,anotherserver" process.env['no_proxy'] = 'otherserver, myserver:8080 ,anotherserver'
let bypass = pm.checkBypass(url.parse('https://myserver:8080')); let bypass = pm.checkBypass(url.parse('https://myserver:8080'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host with port in no_proxy list without port', () => { it('checkBypass returns true if host with port in no_proxy list without port', () => {
process.env["no_proxy"] = "otherserver, myserver ,anotherserver" process.env['no_proxy'] = 'otherserver, myserver ,anotherserver'
let bypass = pm.checkBypass(url.parse('https://myserver:8080')); let bypass = pm.checkBypass(url.parse('https://myserver:8080'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host in no_proxy list with default https port', () => { it('checkBypass returns true if host in no_proxy list with default https port', () => {
process.env["no_proxy"] = "otherserver, myserver:443 ,anotherserver" process.env['no_proxy'] = 'otherserver, myserver:443 ,anotherserver'
let bypass = pm.checkBypass(url.parse('https://myserver')); let bypass = pm.checkBypass(url.parse('https://myserver'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns true if host in no_proxy list with default http port', () => { it('checkBypass returns true if host in no_proxy list with default http port', () => {
process.env["no_proxy"] = "otherserver, myserver:80 ,anotherserver" process.env['no_proxy'] = 'otherserver, myserver:80 ,anotherserver'
let bypass = pm.checkBypass(url.parse('http://myserver')); let bypass = pm.checkBypass(url.parse('http://myserver'))
expect(bypass).toBeTruthy(); expect(bypass).toBeTruthy()
}) })
it('checkBypass returns false if host not in no_proxy list', () => { it('checkBypass returns false if host not in no_proxy list', () => {
process.env["no_proxy"] = "otherserver, myserver ,anotherserver:8080" process.env['no_proxy'] = 'otherserver, myserver ,anotherserver:8080'
let bypass = pm.checkBypass(url.parse('https://github.com')); let bypass = pm.checkBypass(url.parse('https://github.com'))
expect(bypass).toBeFalsy(); expect(bypass).toBeFalsy()
}) })
it('checkBypass returns false if empty no_proxy', () => { it('checkBypass returns false if empty no_proxy', () => {
process.env["no_proxy"] = "" process.env['no_proxy'] = ''
let bypass = pm.checkBypass(url.parse('https://github.com')); let bypass = pm.checkBypass(url.parse('https://github.com'))
expect(bypass).toBeFalsy(); expect(bypass).toBeFalsy()
}) })
it('HttpClient does basic http get request through proxy', async () => { it('HttpClient does basic http get request through proxy', async () => {
process.env['http_proxy'] = _proxyUrl process.env['http_proxy'] = _proxyUrl
const httpClient = new httpm.HttpClient(); const httpClient = new httpm.HttpClient()
let res: httpm.HttpClientResponse = await httpClient.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await httpClient.get(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/get"); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(_proxyConnects).toEqual(['httpbin.org:80']) expect(_proxyConnects).toEqual(['httpbin.org:80'])
}) })
it('HttoClient does basic http get request when bypass proxy', async () => { it('HttoClient does basic http get request when bypass proxy', async () => {
process.env['http_proxy'] = _proxyUrl process.env['http_proxy'] = _proxyUrl
process.env['no_proxy'] = 'httpbin.org' process.env['no_proxy'] = 'httpbin.org'
const httpClient = new httpm.HttpClient(); const httpClient = new httpm.HttpClient()
let res: httpm.HttpClientResponse = await httpClient.get('http://httpbin.org/get'); let res: httpm.HttpClientResponse = await httpClient.get(
expect(res.message.statusCode).toBe(200); 'http://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("http://httpbin.org/get"); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(_proxyConnects).toHaveLength(0) expect(_proxyConnects).toHaveLength(0)
}) })
it('HttpClient does basic https get request through proxy', async () => { it('HttpClient does basic https get request through proxy', async () => {
process.env['https_proxy'] = _proxyUrl process.env['https_proxy'] = _proxyUrl
const httpClient = new httpm.HttpClient(); const httpClient = new httpm.HttpClient()
let res: httpm.HttpClientResponse = await httpClient.get('https://httpbin.org/get'); let res: httpm.HttpClientResponse = await httpClient.get(
expect(res.message.statusCode).toBe(200); 'https://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("https://httpbin.org/get"); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(_proxyConnects).toEqual(['httpbin.org:443']) expect(_proxyConnects).toEqual(['httpbin.org:443'])
}) })
it('HttpClient does basic https get request when bypass proxy', async () => { it('HttpClient does basic https get request when bypass proxy', async () => {
process.env['https_proxy'] = _proxyUrl process.env['https_proxy'] = _proxyUrl
process.env['no_proxy'] = 'httpbin.org' process.env['no_proxy'] = 'httpbin.org'
const httpClient = new httpm.HttpClient(); const httpClient = new httpm.HttpClient()
let res: httpm.HttpClientResponse = await httpClient.get('https://httpbin.org/get'); let res: httpm.HttpClientResponse = await httpClient.get(
expect(res.message.statusCode).toBe(200); 'https://httpbin.org/get'
let body: string = await res.readBody(); )
let obj: any = JSON.parse(body); expect(res.message.statusCode).toBe(200)
expect(obj.url).toBe("https://httpbin.org/get"); let body: string = await res.readBody()
let obj: any = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(_proxyConnects).toHaveLength(0) expect(_proxyConnects).toHaveLength(0)
}) })
}) })
function _clearVars() { function _clearVars() {
delete process.env.http_proxy; delete process.env.http_proxy
delete process.env.HTTP_PROXY; delete process.env.HTTP_PROXY
delete process.env.https_proxy; delete process.env.https_proxy
delete process.env.HTTPS_PROXY; delete process.env.HTTPS_PROXY
delete process.env.no_proxy; delete process.env.no_proxy
delete process.env.NO_PROXY; delete process.env.NO_PROXY
} }

67
auth.ts
View File

@ -1,71 +1,86 @@
import ifm = require('./interfaces')
import ifm = require('./interfaces');
export class BasicCredentialHandler implements ifm.IRequestHandler { export class BasicCredentialHandler implements ifm.IRequestHandler {
username: string; username: string
password: string; password: string
constructor(username: string, password: string) { constructor(username: string, password: string) {
this.username = username; this.username = username
this.password = password; this.password = password
} }
prepareRequest(options:any): void { prepareRequest(options: any): void {
options.headers['Authorization'] = 'Basic ' + Buffer.from(this.username + ':' + this.password).toString('base64'); options.headers['Authorization'] =
'Basic ' +
Buffer.from(this.username + ':' + this.password).toString('base64')
} }
// This handler cannot handle 401 // This handler cannot handle 401
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean { canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
return false; return false
} }
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> { handleAuthentication(
return null; httpClient: ifm.IHttpClient,
requestInfo: ifm.IRequestInfo,
objs
): Promise<ifm.IHttpClientResponse> {
return null
} }
} }
export class BearerCredentialHandler implements ifm.IRequestHandler { export class BearerCredentialHandler implements ifm.IRequestHandler {
token: string; token: string
constructor(token: string) { constructor(token: string) {
this.token = token; this.token = token
} }
// currently implements pre-authorization // currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401 // TODO: support preAuth = false where it hooks on 401
prepareRequest(options:any): void { prepareRequest(options: any): void {
options.headers['Authorization'] = 'Bearer ' + this.token; options.headers['Authorization'] = 'Bearer ' + this.token
} }
// This handler cannot handle 401 // This handler cannot handle 401
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean { canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
return false; return false
} }
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> { handleAuthentication(
return null; httpClient: ifm.IHttpClient,
requestInfo: ifm.IRequestInfo,
objs
): Promise<ifm.IHttpClientResponse> {
return null
} }
} }
export class PersonalAccessTokenCredentialHandler implements ifm.IRequestHandler { export class PersonalAccessTokenCredentialHandler
token: string; implements ifm.IRequestHandler {
token: string
constructor(token: string) { constructor(token: string) {
this.token = token; this.token = token
} }
// currently implements pre-authorization // currently implements pre-authorization
// TODO: support preAuth = false where it hooks on 401 // TODO: support preAuth = false where it hooks on 401
prepareRequest(options:any): void { prepareRequest(options: any): void {
options.headers['Authorization'] = 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64'); options.headers['Authorization'] =
'Basic ' + Buffer.from('PAT:' + this.token).toString('base64')
} }
// This handler cannot handle 401 // This handler cannot handle 401
canHandleAuthentication(response: ifm.IHttpClientResponse): boolean { canHandleAuthentication(response: ifm.IHttpClientResponse): boolean {
return false; return false
} }
handleAuthentication(httpClient: ifm.IHttpClient, requestInfo: ifm.IRequestInfo, objs): Promise<ifm.IHttpClientResponse> { handleAuthentication(
return null; httpClient: ifm.IHttpClient,
requestInfo: ifm.IRequestInfo,
objs
): Promise<ifm.IHttpClientResponse> {
return null
} }
} }

640
index.ts
View File

@ -1,10 +1,10 @@
import url = require("url"); import url = require('url')
import http = require("http"); import http = require('http')
import https = require("https"); import https = require('https')
import ifm = require('./interfaces'); import ifm = require('./interfaces')
import pm = require('./proxy'); import pm = require('./proxy')
let tunnel: any; let tunnel: any
export enum HttpCodes { export enum HttpCodes {
OK = 200, OK = 200,
@ -33,16 +33,16 @@ export enum HttpCodes {
NotImplemented = 501, NotImplemented = 501,
BadGateway = 502, BadGateway = 502,
ServiceUnavailable = 503, ServiceUnavailable = 503,
GatewayTimeout = 504, GatewayTimeout = 504
} }
export enum Headers { export enum Headers {
Accept = "accept", Accept = 'accept',
ContentType = "content-type" ContentType = 'content-type'
} }
export enum MediaTypes { export enum MediaTypes {
ApplicationJson = "application/json" ApplicationJson = 'application/json'
} }
/** /**
@ -54,156 +54,257 @@ export function getProxyUrl(serverUrl: string): string {
return proxyUrl ? proxyUrl.href : '' return proxyUrl ? proxyUrl.href : ''
} }
const HttpRedirectCodes: number[] = [HttpCodes.MovedPermanently, HttpCodes.ResourceMoved, HttpCodes.SeeOther, HttpCodes.TemporaryRedirect, HttpCodes.PermanentRedirect]; const HttpRedirectCodes: number[] = [
const HttpResponseRetryCodes: number[] = [HttpCodes.BadGateway, HttpCodes.ServiceUnavailable, HttpCodes.GatewayTimeout]; HttpCodes.MovedPermanently,
const RetryableHttpVerbs: string[] = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; HttpCodes.ResourceMoved,
const ExponentialBackoffCeiling = 10; HttpCodes.SeeOther,
const ExponentialBackoffTimeSlice = 5; HttpCodes.TemporaryRedirect,
HttpCodes.PermanentRedirect
]
const HttpResponseRetryCodes: number[] = [
HttpCodes.BadGateway,
HttpCodes.ServiceUnavailable,
HttpCodes.GatewayTimeout
]
const RetryableHttpVerbs: string[] = ['OPTIONS', 'GET', 'DELETE', 'HEAD']
const ExponentialBackoffCeiling = 10
const ExponentialBackoffTimeSlice = 5
export class HttpClientResponse implements ifm.IHttpClientResponse { export class HttpClientResponse implements ifm.IHttpClientResponse {
constructor(message: http.IncomingMessage) { constructor(message: http.IncomingMessage) {
this.message = message; this.message = message
} }
public message: http.IncomingMessage; public message: http.IncomingMessage
readBody(): Promise<string> { readBody(): Promise<string> {
return new Promise<string>(async (resolve, reject) => { return new Promise<string>(async (resolve, reject) => {
let output = Buffer.alloc(0); let output = Buffer.alloc(0)
this.message.on('data', (chunk: Buffer) => { this.message.on('data', (chunk: Buffer) => {
output = Buffer.concat([output, chunk]); output = Buffer.concat([output, chunk])
}); })
this.message.on('end', () => { this.message.on('end', () => {
resolve(output.toString()); resolve(output.toString())
}); })
}); })
} }
} }
export function isHttps(requestUrl: string) { export function isHttps(requestUrl: string) {
let parsedUrl: url.Url = url.parse(requestUrl); let parsedUrl: url.Url = url.parse(requestUrl)
return parsedUrl.protocol === 'https:'; return parsedUrl.protocol === 'https:'
} }
export class HttpClient { export class HttpClient {
userAgent: string | undefined; userAgent: string | undefined
handlers: ifm.IRequestHandler[]; handlers: ifm.IRequestHandler[]
requestOptions: ifm.IRequestOptions; requestOptions: ifm.IRequestOptions
private _ignoreSslError: boolean = false; private _ignoreSslError: boolean = false
private _socketTimeout: number; private _socketTimeout: number
private _allowRedirects: boolean = true; private _allowRedirects: boolean = true
private _allowRedirectDowngrade: boolean = false; private _allowRedirectDowngrade: boolean = false
private _maxRedirects: number = 50; private _maxRedirects: number = 50
private _allowRetries: boolean = false; private _allowRetries: boolean = false
private _maxRetries: number = 1; private _maxRetries: number = 1
private _agent; private _agent
private _proxyAgent; private _proxyAgent
private _keepAlive: boolean = false; private _keepAlive: boolean = false
private _disposed: boolean = false; private _disposed: boolean = false
constructor(userAgent?: string, handlers?: ifm.IRequestHandler[], requestOptions?: ifm.IRequestOptions) { constructor(
this.userAgent = userAgent; userAgent?: string,
this.handlers = handlers || []; handlers?: ifm.IRequestHandler[],
this.requestOptions = requestOptions; requestOptions?: ifm.IRequestOptions
) {
this.userAgent = userAgent
this.handlers = handlers || []
this.requestOptions = requestOptions
if (requestOptions) { if (requestOptions) {
if (requestOptions.ignoreSslError != null) { if (requestOptions.ignoreSslError != null) {
this._ignoreSslError = requestOptions.ignoreSslError; this._ignoreSslError = requestOptions.ignoreSslError
} }
this._socketTimeout = requestOptions.socketTimeout; this._socketTimeout = requestOptions.socketTimeout
if (requestOptions.allowRedirects != null) { if (requestOptions.allowRedirects != null) {
this._allowRedirects = requestOptions.allowRedirects; this._allowRedirects = requestOptions.allowRedirects
} }
if (requestOptions.allowRedirectDowngrade != null) { if (requestOptions.allowRedirectDowngrade != null) {
this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade
} }
if (requestOptions.maxRedirects != null) { if (requestOptions.maxRedirects != null) {
this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); this._maxRedirects = Math.max(requestOptions.maxRedirects, 0)
} }
if (requestOptions.keepAlive != null) { if (requestOptions.keepAlive != null) {
this._keepAlive = requestOptions.keepAlive; this._keepAlive = requestOptions.keepAlive
} }
if (requestOptions.allowRetries != null) { if (requestOptions.allowRetries != null) {
this._allowRetries = requestOptions.allowRetries; this._allowRetries = requestOptions.allowRetries
} }
if (requestOptions.maxRetries != null) { if (requestOptions.maxRetries != null) {
this._maxRetries = requestOptions.maxRetries; this._maxRetries = requestOptions.maxRetries
} }
} }
} }
public options(requestUrl: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public options(
return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); requestUrl: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('OPTIONS', requestUrl, null, additionalHeaders || {})
} }
public get(requestUrl: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public get(
return this.request('GET', requestUrl, null, additionalHeaders || {}); requestUrl: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('GET', requestUrl, null, additionalHeaders || {})
} }
public del(requestUrl: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public del(
return this.request('DELETE', requestUrl, null, additionalHeaders || {}); requestUrl: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('DELETE', requestUrl, null, additionalHeaders || {})
} }
public post(requestUrl: string, data: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public post(
return this.request('POST', requestUrl, data, additionalHeaders || {}); requestUrl: string,
data: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('POST', requestUrl, data, additionalHeaders || {})
} }
public patch(requestUrl: string, data: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public patch(
return this.request('PATCH', requestUrl, data, additionalHeaders || {}); requestUrl: string,
data: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('PATCH', requestUrl, data, additionalHeaders || {})
} }
public put(requestUrl: string, data: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public put(
return this.request('PUT', requestUrl, data, additionalHeaders || {}); requestUrl: string,
data: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('PUT', requestUrl, data, additionalHeaders || {})
} }
public head(requestUrl: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public head(
return this.request('HEAD', requestUrl, null, additionalHeaders || {}); requestUrl: string,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request('HEAD', requestUrl, null, additionalHeaders || {})
} }
public sendStream(verb: string, requestUrl: string, stream: NodeJS.ReadableStream, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public sendStream(
return this.request(verb, requestUrl, stream, additionalHeaders); verb: string,
requestUrl: string,
stream: NodeJS.ReadableStream,
additionalHeaders?: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
return this.request(verb, requestUrl, stream, additionalHeaders)
} }
/** /**
* Gets a typed object from an endpoint * Gets a typed object from an endpoint
* Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise
*/ */
public async getJson<T>(requestUrl: string, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> { public async getJson<T>(
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson) requestUrl: string,
let res: ifm.IHttpClientResponse = await this.get(requestUrl, additionalHeaders); additionalHeaders: ifm.IHeaders = {}
return this._processResponse<T>(res, this.requestOptions); ): Promise<ifm.ITypedResponse<T>> {
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.Accept,
MediaTypes.ApplicationJson
)
let res: ifm.IHttpClientResponse = await this.get(
requestUrl,
additionalHeaders
)
return this._processResponse<T>(res, this.requestOptions)
} }
public async postJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> { public async postJson<T>(
let data: string = JSON.stringify(obj, null, 2); requestUrl: string,
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson) obj: any,
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); additionalHeaders: ifm.IHeaders = {}
let res: ifm.IHttpClientResponse = await this.post(requestUrl, data, additionalHeaders); ): Promise<ifm.ITypedResponse<T>> {
return this._processResponse<T>(res, this.requestOptions); let data: string = JSON.stringify(obj, null, 2)
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.Accept,
MediaTypes.ApplicationJson
)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.ContentType,
MediaTypes.ApplicationJson
)
let res: ifm.IHttpClientResponse = await this.post(
requestUrl,
data,
additionalHeaders
)
return this._processResponse<T>(res, this.requestOptions)
} }
public async putJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> { public async putJson<T>(
let data: string = JSON.stringify(obj, null, 2); requestUrl: string,
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson) obj: any,
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); additionalHeaders: ifm.IHeaders = {}
let res: ifm.IHttpClientResponse = await this.put(requestUrl, data, additionalHeaders); ): Promise<ifm.ITypedResponse<T>> {
return this._processResponse<T>(res, this.requestOptions); let data: string = JSON.stringify(obj, null, 2)
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.Accept,
MediaTypes.ApplicationJson
)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.ContentType,
MediaTypes.ApplicationJson
)
let res: ifm.IHttpClientResponse = await this.put(
requestUrl,
data,
additionalHeaders
)
return this._processResponse<T>(res, this.requestOptions)
} }
public async patchJson<T>(requestUrl: string, obj: any, additionalHeaders: ifm.IHeaders = {}): Promise<ifm.ITypedResponse<T>> { public async patchJson<T>(
let data: string = JSON.stringify(obj, null, 2); requestUrl: string,
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson) obj: any,
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); additionalHeaders: ifm.IHeaders = {}
let res: ifm.IHttpClientResponse = await this.patch(requestUrl, data, additionalHeaders); ): Promise<ifm.ITypedResponse<T>> {
return this._processResponse<T>(res, this.requestOptions); let data: string = JSON.stringify(obj, null, 2)
additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.Accept,
MediaTypes.ApplicationJson
)
additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(
additionalHeaders,
Headers.ContentType,
MediaTypes.ApplicationJson
)
let res: ifm.IHttpClientResponse = await this.patch(
requestUrl,
data,
additionalHeaders
)
return this._processResponse<T>(res, this.requestOptions)
} }
/** /**
@ -211,82 +312,100 @@ export class HttpClient {
* All other methods such as get, post, patch, and request ultimately call this. * All other methods such as get, post, patch, and request ultimately call this.
* Prefer get, del, post and patch * Prefer get, del, post and patch
*/ */
public async request(verb: string, requestUrl: string, data: string | NodeJS.ReadableStream, headers: ifm.IHeaders): Promise<ifm.IHttpClientResponse> { public async request(
verb: string,
requestUrl: string,
data: string | NodeJS.ReadableStream,
headers: ifm.IHeaders
): Promise<ifm.IHttpClientResponse> {
if (this._disposed) { if (this._disposed) {
throw new Error("Client has already been disposed."); throw new Error('Client has already been disposed.')
} }
let parsedUrl = url.parse(requestUrl); let parsedUrl = url.parse(requestUrl)
let info: ifm.IRequestInfo = this._prepareRequest(verb, parsedUrl, headers); let info: ifm.IRequestInfo = this._prepareRequest(verb, parsedUrl, headers)
// Only perform retries on reads since writes may not be idempotent. // Only perform retries on reads since writes may not be idempotent.
let maxTries: number = (this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1) ? this._maxRetries + 1 : 1; let maxTries: number =
let numTries: number = 0; this._allowRetries && RetryableHttpVerbs.indexOf(verb) != -1
? this._maxRetries + 1
: 1
let numTries: number = 0
let response: HttpClientResponse; let response: HttpClientResponse
while (numTries < maxTries) { while (numTries < maxTries) {
response = await this.requestRaw(info, data); response = await this.requestRaw(info, data)
// Check if it's an authentication challenge // Check if it's an authentication challenge
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { if (
let authenticationHandler: ifm.IRequestHandler; response &&
response.message &&
response.message.statusCode === HttpCodes.Unauthorized
) {
let authenticationHandler: ifm.IRequestHandler
for (let i = 0; i < this.handlers.length; i++) { for (let i = 0; i < this.handlers.length; i++) {
if (this.handlers[i].canHandleAuthentication(response)) { if (this.handlers[i].canHandleAuthentication(response)) {
authenticationHandler = this.handlers[i]; authenticationHandler = this.handlers[i]
break; break
} }
} }
if (authenticationHandler) { if (authenticationHandler) {
return authenticationHandler.handleAuthentication(this, info, data); return authenticationHandler.handleAuthentication(this, info, data)
} } else {
else {
// We have received an unauthorized response but have no handlers to handle it. // We have received an unauthorized response but have no handlers to handle it.
// Let the response return to the caller. // Let the response return to the caller.
return response; return response
} }
} }
let redirectsRemaining: number = this._maxRedirects; let redirectsRemaining: number = this._maxRedirects
while (HttpRedirectCodes.indexOf(response.message.statusCode) != -1 while (
&& this._allowRedirects HttpRedirectCodes.indexOf(response.message.statusCode) != -1 &&
&& redirectsRemaining > 0) { this._allowRedirects &&
redirectsRemaining > 0
const redirectUrl: string | null = response.message.headers["location"]; ) {
const redirectUrl: string | null = response.message.headers['location']
if (!redirectUrl) { if (!redirectUrl) {
// if there's no location to redirect to, we won't // if there's no location to redirect to, we won't
break; break
} }
let parsedRedirectUrl = url.parse(redirectUrl); let parsedRedirectUrl = url.parse(redirectUrl)
if (parsedUrl.protocol == 'https:' && parsedUrl.protocol != parsedRedirectUrl.protocol && !this._allowRedirectDowngrade) { if (
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."); parsedUrl.protocol == 'https:' &&
parsedUrl.protocol != parsedRedirectUrl.protocol &&
!this._allowRedirectDowngrade
) {
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.'
)
} }
// we need to finish reading the response before reassigning response // we need to finish reading the response before reassigning response
// which will leak the open socket. // which will leak the open socket.
await response.readBody(); await response.readBody()
// let's make the request with the new redirectUrl // let's make the request with the new redirectUrl
info = this._prepareRequest(verb, parsedRedirectUrl, headers); info = this._prepareRequest(verb, parsedRedirectUrl, headers)
response = await this.requestRaw(info, data); response = await this.requestRaw(info, data)
redirectsRemaining--; redirectsRemaining--
} }
if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) { if (HttpResponseRetryCodes.indexOf(response.message.statusCode) == -1) {
// If not a retry code, return immediately instead of retrying // If not a retry code, return immediately instead of retrying
return response; return response
} }
numTries += 1; numTries += 1
if (numTries < maxTries) { if (numTries < maxTries) {
await response.readBody(); await response.readBody()
await this._performExponentialBackoff(numTries); await this._performExponentialBackoff(numTries)
} }
} }
return response; return response
} }
/** /**
@ -294,10 +413,10 @@ export class HttpClient {
*/ */
public dispose() { public dispose() {
if (this._agent) { if (this._agent) {
this._agent.destroy(); this._agent.destroy()
} }
this._disposed = true; this._disposed = true
} }
/** /**
@ -305,18 +424,24 @@ export class HttpClient {
* @param info * @param info
* @param data * @param data
*/ */
public requestRaw(info: ifm.IRequestInfo, data: string | NodeJS.ReadableStream): Promise<ifm.IHttpClientResponse> { public requestRaw(
info: ifm.IRequestInfo,
data: string | NodeJS.ReadableStream
): Promise<ifm.IHttpClientResponse> {
return new Promise<ifm.IHttpClientResponse>((resolve, reject) => { return new Promise<ifm.IHttpClientResponse>((resolve, reject) => {
let callbackForResult = function (err: any, res: ifm.IHttpClientResponse) { let callbackForResult = function (
err: any,
res: ifm.IHttpClientResponse
) {
if (err) { if (err) {
reject(err); reject(err)
} }
resolve(res); resolve(res)
}; }
this.requestRawWithCallback(info, data, callbackForResult); this.requestRawWithCallback(info, data, callbackForResult)
}); })
} }
/** /**
@ -325,57 +450,63 @@ export class HttpClient {
* @param data * @param data
* @param onResult * @param onResult
*/ */
public requestRawWithCallback(info: ifm.IRequestInfo, data: string | NodeJS.ReadableStream, onResult: (err: any, res: ifm.IHttpClientResponse) => void): void { public requestRawWithCallback(
let socket; info: ifm.IRequestInfo,
data: string | NodeJS.ReadableStream,
onResult: (err: any, res: ifm.IHttpClientResponse) => void
): void {
let socket
if (typeof (data) === 'string') { if (typeof data === 'string') {
info.options.headers["Content-Length"] = Buffer.byteLength(data, 'utf8'); info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8')
} }
let callbackCalled: boolean = false; let callbackCalled: boolean = false
let handleResult = (err: any, res: HttpClientResponse) => { let handleResult = (err: any, res: HttpClientResponse) => {
if (!callbackCalled) { if (!callbackCalled) {
callbackCalled = true; callbackCalled = true
onResult(err, res); onResult(err, res)
}
} }
};
let req: http.ClientRequest = info.httpModule.request(info.options, (msg: http.IncomingMessage) => { let req: http.ClientRequest = info.httpModule.request(
let res: HttpClientResponse = new HttpClientResponse(msg); info.options,
handleResult(null, res); (msg: http.IncomingMessage) => {
}); let res: HttpClientResponse = new HttpClientResponse(msg)
handleResult(null, res)
}
)
req.on('socket', (sock) => { req.on('socket', sock => {
socket = sock; socket = sock
}); })
// If we ever get disconnected, we want the socket to timeout eventually // If we ever get disconnected, we want the socket to timeout eventually
req.setTimeout(this._socketTimeout || 3 * 60000, () => { req.setTimeout(this._socketTimeout || 3 * 60000, () => {
if (socket) { if (socket) {
socket.end(); socket.end()
} }
handleResult(new Error('Request timeout: ' + info.options.path), null); handleResult(new Error('Request timeout: ' + info.options.path), null)
}); })
req.on('error', function (err) { req.on('error', function (err) {
// err has statusCode property // err has statusCode property
// res should have headers // res should have headers
handleResult(err, null); handleResult(err, null)
}); })
if (data && typeof (data) === 'string') { if (data && typeof data === 'string') {
req.write(data, 'utf8'); req.write(data, 'utf8')
} }
if (data && typeof (data) !== 'string') { if (data && typeof data !== 'string') {
data.on('close', function () { data.on('close', function () {
req.end(); req.end()
}); })
data.pipe(req); data.pipe(req)
} } else {
else { req.end()
req.end();
} }
} }
@ -389,80 +520,93 @@ export class HttpClient {
return this._getAgent(parsedUrl) return this._getAgent(parsedUrl)
} }
private _prepareRequest(method: string, requestUrl: url.Url, headers: ifm.IHeaders): ifm.IRequestInfo { private _prepareRequest(
const info: ifm.IRequestInfo = <ifm.IRequestInfo>{}; method: string,
requestUrl: url.Url,
headers: ifm.IHeaders
): ifm.IRequestInfo {
const info: ifm.IRequestInfo = <ifm.IRequestInfo>{}
info.parsedUrl = requestUrl; info.parsedUrl = requestUrl
const usingSsl: boolean = info.parsedUrl.protocol === 'https:'; const usingSsl: boolean = info.parsedUrl.protocol === 'https:'
info.httpModule = usingSsl ? https : http; info.httpModule = usingSsl ? https : http
const defaultPort: number = usingSsl ? 443 : 80; const defaultPort: number = usingSsl ? 443 : 80
info.options = <http.RequestOptions>{}; info.options = <http.RequestOptions>{}
info.options.host = info.parsedUrl.hostname; info.options.host = info.parsedUrl.hostname
info.options.port = info.parsedUrl.port ? parseInt(info.parsedUrl.port) : defaultPort; info.options.port = info.parsedUrl.port
info.options.path = (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); ? parseInt(info.parsedUrl.port)
info.options.method = method; : defaultPort
info.options.headers = this._mergeHeaders(headers); info.options.path =
(info.parsedUrl.pathname || '') + (info.parsedUrl.search || '')
info.options.method = method
info.options.headers = this._mergeHeaders(headers)
if (this.userAgent != null) { if (this.userAgent != null) {
info.options.headers["user-agent"] = this.userAgent; info.options.headers['user-agent'] = this.userAgent
} }
info.options.agent = this._getAgent(info.parsedUrl); info.options.agent = this._getAgent(info.parsedUrl)
// gives handlers an opportunity to participate // gives handlers an opportunity to participate
if (this.handlers) { if (this.handlers) {
this.handlers.forEach((handler) => { this.handlers.forEach(handler => {
handler.prepareRequest(info.options); handler.prepareRequest(info.options)
}); })
} }
return info; return info
} }
private _mergeHeaders(headers: ifm.IHeaders) : ifm.IHeaders { private _mergeHeaders(headers: ifm.IHeaders): ifm.IHeaders {
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => (c[k.toLowerCase()] = obj[k], c), {}); const lowercaseKeys = obj =>
Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {})
if (this.requestOptions && this.requestOptions.headers) { if (this.requestOptions && this.requestOptions.headers) {
return Object.assign( return Object.assign(
{}, {},
lowercaseKeys(this.requestOptions.headers), lowercaseKeys(this.requestOptions.headers),
lowercaseKeys(headers) lowercaseKeys(headers)
); )
} }
return lowercaseKeys(headers || {}); return lowercaseKeys(headers || {})
} }
private _getExistingOrDefaultHeader(additionalHeaders: ifm.IHeaders, header: string, _default: string) { private _getExistingOrDefaultHeader(
const lowercaseKeys = obj => Object.keys(obj).reduce((c, k) => (c[k.toLowerCase()] = obj[k], c), {}); additionalHeaders: ifm.IHeaders,
header: string,
_default: string
) {
const lowercaseKeys = obj =>
Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {})
let clientHeader: string; let clientHeader: string
if(this.requestOptions && this.requestOptions.headers) { if (this.requestOptions && this.requestOptions.headers) {
clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; clientHeader = lowercaseKeys(this.requestOptions.headers)[header]
} }
return additionalHeaders[header] || clientHeader || _default; return additionalHeaders[header] || clientHeader || _default
} }
private _getAgent(parsedUrl: url.Url): http.Agent { private _getAgent(parsedUrl: url.Url): http.Agent {
let agent; let agent
let proxyUrl: url.Url = pm.getProxyUrl(parsedUrl); let proxyUrl: url.Url = pm.getProxyUrl(parsedUrl)
let useProxy = proxyUrl && proxyUrl.hostname; let useProxy = proxyUrl && proxyUrl.hostname
if (this._keepAlive && useProxy) { if (this._keepAlive && useProxy) {
agent = this._proxyAgent; agent = this._proxyAgent
} }
if (this._keepAlive && !useProxy) { if (this._keepAlive && !useProxy) {
agent = this._agent; agent = this._agent
} }
// if agent is already assigned use that agent. // if agent is already assigned use that agent.
if (!!agent) { if (!!agent) {
return agent; return agent
} }
const usingSsl = parsedUrl.protocol === 'https:'; const usingSsl = parsedUrl.protocol === 'https:'
let maxSockets = 100; let maxSockets = 100
if (!!this.requestOptions) { if (!!this.requestOptions) {
maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets
} }
@ -470,7 +614,7 @@ export class HttpClient {
if (useProxy) { if (useProxy) {
// If using proxy, need tunnel // If using proxy, need tunnel
if (!tunnel) { if (!tunnel) {
tunnel = require('tunnel'); tunnel = require('tunnel')
} }
const agentOptions = { const agentOptions = {
@ -480,123 +624,127 @@ export class HttpClient {
proxyAuth: proxyUrl.auth, proxyAuth: proxyUrl.auth,
host: proxyUrl.hostname, host: proxyUrl.hostname,
port: proxyUrl.port port: proxyUrl.port
}, }
};
let tunnelAgent: Function;
const overHttps = proxyUrl.protocol === 'https:';
if (usingSsl) {
tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp;
} else {
tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp;
} }
agent = tunnelAgent(agentOptions); let tunnelAgent: Function
this._proxyAgent = agent; const overHttps = proxyUrl.protocol === 'https:'
if (usingSsl) {
tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp
} else {
tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp
}
agent = tunnelAgent(agentOptions)
this._proxyAgent = agent
} }
// if reusing agent across request and tunneling agent isn't assigned create a new agent // if reusing agent across request and tunneling agent isn't assigned create a new agent
if (this._keepAlive && !agent) { if (this._keepAlive && !agent) {
const options = { keepAlive: this._keepAlive, maxSockets: maxSockets }; const options = {keepAlive: this._keepAlive, maxSockets: maxSockets}
agent = usingSsl ? new https.Agent(options) : new http.Agent(options); agent = usingSsl ? new https.Agent(options) : new http.Agent(options)
this._agent = agent; this._agent = agent
} }
// if not using private agent and tunnel agent isn't setup then use global agent // if not using private agent and tunnel agent isn't setup then use global agent
if (!agent) { if (!agent) {
agent = usingSsl ? https.globalAgent : http.globalAgent; agent = usingSsl ? https.globalAgent : http.globalAgent
} }
if (usingSsl && this._ignoreSslError) { if (usingSsl && this._ignoreSslError) {
// we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process
// http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options
// we have to cast it to any and change it directly // we have to cast it to any and change it directly
agent.options = Object.assign(agent.options || {}, { rejectUnauthorized: false }); agent.options = Object.assign(agent.options || {}, {
rejectUnauthorized: false
})
} }
return agent; return agent
} }
private _performExponentialBackoff(retryNumber: number): Promise<void> { private _performExponentialBackoff(retryNumber: number): Promise<void> {
retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber)
const ms: number = ExponentialBackoffTimeSlice*Math.pow(2, retryNumber); const ms: number = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber)
return new Promise(resolve => setTimeout(()=>resolve(), ms)); return new Promise(resolve => setTimeout(() => resolve(), ms))
} }
private static dateTimeDeserializer(key: any, value: any): any { private static dateTimeDeserializer(key: any, value: any): any {
if (typeof value === 'string'){ if (typeof value === 'string') {
let a = new Date(value); let a = new Date(value)
if (!isNaN(a.valueOf())) { if (!isNaN(a.valueOf())) {
return a; return a
} }
} }
return value; return value
} }
private async _processResponse<T>(res: ifm.IHttpClientResponse, options: ifm.IRequestOptions): Promise<ifm.ITypedResponse<T>> { private async _processResponse<T>(
res: ifm.IHttpClientResponse,
options: ifm.IRequestOptions
): Promise<ifm.ITypedResponse<T>> {
return new Promise<ifm.ITypedResponse<T>>(async (resolve, reject) => { return new Promise<ifm.ITypedResponse<T>>(async (resolve, reject) => {
const statusCode: number = res.message.statusCode; const statusCode: number = res.message.statusCode
const response: ifm.ITypedResponse<T> = { const response: ifm.ITypedResponse<T> = {
statusCode: statusCode, statusCode: statusCode,
result: null, result: null,
headers: {} headers: {}
}; }
// not found leads to null obj returned // not found leads to null obj returned
if (statusCode == HttpCodes.NotFound) { if (statusCode == HttpCodes.NotFound) {
resolve(response); resolve(response)
} }
let obj: any; let obj: any
let contents: string; let contents: string
// get the result from the body // get the result from the body
try { try {
contents = await res.readBody(); contents = await res.readBody()
if (contents && contents.length > 0) { if (contents && contents.length > 0) {
if (options && options.deserializeDates) { if (options && options.deserializeDates) {
obj = JSON.parse(contents, HttpClient.dateTimeDeserializer); obj = JSON.parse(contents, HttpClient.dateTimeDeserializer)
} else { } else {
obj = JSON.parse(contents); obj = JSON.parse(contents)
} }
response.result = obj; response.result = obj
} }
response.headers = res.message.headers; response.headers = res.message.headers
} } catch (err) {
catch (err) {
// Invalid resource (contents not json); leaving result obj null // Invalid resource (contents not json); leaving result obj null
} }
// note that 3xx redirects are handled by the http layer. // note that 3xx redirects are handled by the http layer.
if (statusCode > 299) { if (statusCode > 299) {
let msg: string; let msg: string
// if exception/error in body, attempt to get better error // if exception/error in body, attempt to get better error
if (obj && obj.message) { if (obj && obj.message) {
msg = obj.message; msg = obj.message
} else if (contents && contents.length > 0) { } else if (contents && contents.length > 0) {
// it may be the case that the exception is in the body message as string // it may be the case that the exception is in the body message as string
msg = contents; msg = contents
} else { } else {
msg = "Failed request: (" + statusCode + ")"; msg = 'Failed request: (' + statusCode + ')'
} }
let err: Error = new Error(msg); let err: Error = new Error(msg)
// attach statusCode and body obj (if available) to the error object // attach statusCode and body obj (if available) to the error object
err['statusCode'] = statusCode; err['statusCode'] = statusCode
if (response.result) { if (response.result) {
err['result'] = response.result; err['result'] = response.result
} }
reject(err); reject(err)
} else { } else {
resolve(response); resolve(response)
} }
}); })
} }
} }

View File

@ -1,55 +1,99 @@
import http = require("http"); import http = require('http')
import url = require("url"); import url = require('url')
export interface IHeaders { [key: string]: any }; export interface IHeaders {
[key: string]: any
}
export interface IHttpClient { export interface IHttpClient {
options(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; options(
get(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; requestUrl: string,
del(requestUrl: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; additionalHeaders?: IHeaders
post(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; ): Promise<IHttpClientResponse>
patch(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; get(
put(requestUrl: string, data: string, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; requestUrl: string,
sendStream(verb: string, requestUrl: string, stream: NodeJS.ReadableStream, additionalHeaders?: IHeaders): Promise<IHttpClientResponse>; additionalHeaders?: IHeaders
request(verb: string, requestUrl: string, data: string | NodeJS.ReadableStream, headers: IHeaders): Promise<IHttpClientResponse>; ): Promise<IHttpClientResponse>
requestRaw(info: IRequestInfo, data: string | NodeJS.ReadableStream): Promise<IHttpClientResponse>; del(
requestRawWithCallback(info: IRequestInfo, data: string | NodeJS.ReadableStream, onResult: (err: any, res: IHttpClientResponse) => void): void; 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 { export interface IRequestHandler {
prepareRequest(options: http.RequestOptions): void; prepareRequest(options: http.RequestOptions): void
canHandleAuthentication(response: IHttpClientResponse): boolean; canHandleAuthentication(response: IHttpClientResponse): boolean
handleAuthentication(httpClient: IHttpClient, requestInfo: IRequestInfo, objs): Promise<IHttpClientResponse>; handleAuthentication(
httpClient: IHttpClient,
requestInfo: IRequestInfo,
objs
): Promise<IHttpClientResponse>
} }
export interface IHttpClientResponse { export interface IHttpClientResponse {
message: http.IncomingMessage; message: http.IncomingMessage
readBody(): Promise<string>; readBody(): Promise<string>
} }
export interface IRequestInfo { export interface IRequestInfo {
options: http.RequestOptions; options: http.RequestOptions
parsedUrl: url.Url; parsedUrl: url.Url
httpModule: any; httpModule: any
} }
export interface IRequestOptions { export interface IRequestOptions {
headers?: IHeaders; headers?: IHeaders
socketTimeout?: number; socketTimeout?: number
ignoreSslError?: boolean; ignoreSslError?: boolean
allowRedirects?: boolean; allowRedirects?: boolean
allowRedirectDowngrade?: boolean; allowRedirectDowngrade?: boolean
maxRedirects?: number; maxRedirects?: number
maxSockets?: number; maxSockets?: number
keepAlive?: boolean; keepAlive?: boolean
deserializeDates?: boolean; deserializeDates?: boolean
// Allows retries only on Read operations (since writes may not be idempotent) // Allows retries only on Read operations (since writes may not be idempotent)
allowRetries?: boolean; allowRetries?: boolean
maxRetries?: number; maxRetries?: number
} }
export interface ITypedResponse<T> { export interface ITypedResponse<T> {
statusCode: number, statusCode: number
result: T | null, result: T | null
headers: Object headers: Object
} }

2
package-lock.json generated
View File

@ -3416,7 +3416,7 @@
"prettier": { "prettier": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz",
"integrity": "sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==", "integrity": "sha1-LRuuFz41WZbuNV7Jgwp6HuBUV+8=",
"dev": true "dev": true
}, },
"pretty-format": { "pretty-format": {

View File

@ -6,8 +6,8 @@
"scripts": { "scripts": {
"build": "rm -Rf ./_out && tsc && cp package*.json ./_out && cp *.md ./_out && cp LICENSE ./_out && cp actions.png ./_out", "build": "rm -Rf ./_out && tsc && cp package*.json ./_out && cp *.md ./_out && cp LICENSE ./_out && cp actions.png ./_out",
"test": "jest", "test": "jest",
"format": "prettier --write packages/**/*.ts", "format": "prettier --write *.ts && prettier --write **/*.ts",
"format-check": "prettier --check packages/**/*.ts", "format-check": "prettier --check *.ts && prettier --check **/*.ts",
"audit-check": "npm audit --audit-level=moderate" "audit-check": "npm audit --audit-level=moderate"
}, },
"repository": { "repository": {

View File

@ -1,37 +1,33 @@
import * as url from 'url'; import * as url from 'url'
export function getProxyUrl(reqUrl: url.Url): url.Url | undefined { export function getProxyUrl(reqUrl: url.Url): url.Url | undefined {
let usingSsl = reqUrl.protocol === 'https:'; let usingSsl = reqUrl.protocol === 'https:'
let proxyUrl: url.Url; let proxyUrl: url.Url
if (checkBypass(reqUrl)) { if (checkBypass(reqUrl)) {
return proxyUrl; return proxyUrl
} }
let proxyVar: string; let proxyVar: string
if (usingSsl) { if (usingSsl) {
proxyVar = process.env["https_proxy"] || proxyVar = process.env['https_proxy'] || process.env['HTTPS_PROXY']
process.env["HTTPS_PROXY"];
} else { } else {
proxyVar = process.env["http_proxy"] || proxyVar = process.env['http_proxy'] || process.env['HTTP_PROXY']
process.env["HTTP_PROXY"];
} }
if (proxyVar) { if (proxyVar) {
proxyUrl = url.parse(proxyVar); proxyUrl = url.parse(proxyVar)
} }
return proxyUrl; return proxyUrl
} }
export function checkBypass(reqUrl: url.Url): boolean { export function checkBypass(reqUrl: url.Url): boolean {
if (!reqUrl.hostname) { if (!reqUrl.hostname) {
return false return false
} }
let noProxy = process.env["no_proxy"] || process.env["NO_PROXY"] || ''; let noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''
if (!noProxy) { if (!noProxy) {
return false return false
} }
@ -40,11 +36,9 @@ export function checkBypass(reqUrl: url.Url): boolean {
let reqPort: number let reqPort: number
if (reqUrl.port) { if (reqUrl.port) {
reqPort = Number(reqUrl.port) reqPort = Number(reqUrl.port)
} } else if (reqUrl.protocol === 'http:') {
else if (reqUrl.protocol === 'http:') {
reqPort = 80 reqPort = 80
} } else if (reqUrl.protocol === 'https:') {
else if (reqUrl.protocol === 'https:') {
reqPort = 443 reqPort = 443
} }
@ -55,7 +49,10 @@ export function checkBypass(reqUrl: url.Url): boolean {
} }
// Compare request host against noproxy // Compare request host against noproxy
for (let upperNoProxyItem of noProxy.split(',').map(x => x.trim().toUpperCase()).filter(x => x)) { for (let upperNoProxyItem of noProxy
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) { if (upperReqHosts.some(x => x === upperNoProxyItem)) {
return true return true
} }