mirror of
https://github.com/actions/http-client.git
synced 2025-04-21 09:42:29 +00:00
apply formatting
This commit is contained in:
parent
c715044f28
commit
7af5adfb99
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -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
|
||||||
|
@ -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");
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -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
67
auth.ts
@ -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
640
index.ts
@ -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)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
interfaces.ts
112
interfaces.ts
@ -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
2
package-lock.json
generated
@ -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": {
|
||||||
|
@ -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": {
|
||||||
|
35
proxy.ts
35
proxy.ts
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user