@algolia/requester-node-http 5.0.0-alpha.1 → 5.0.0-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/{requester-node-http.cjs.js → requester-node-http.cjs} +72 -71
- package/dist/requester-node-http.esm.node.js +72 -64
- package/dist/src/createHttpRequester.d.ts +15 -2
- package/dist/src/createHttpRequester.d.ts.map +1 -1
- package/dist/src/echoRequester.d.ts +2 -2
- package/dist/src/echoRequester.d.ts.map +1 -1
- package/package.json +14 -10
- package/src/__tests__/node-http-requester.test.ts +82 -15
- package/src/createHttpRequester.ts +30 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './src/echoRequester';
|
|
2
|
-
export * from './src/createHttpRequester';
|
|
1
|
+
export * from './src/echoRequester';
|
|
2
|
+
export * from './src/createHttpRequester';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,83 +1,84 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var url = require('url');
|
|
6
4
|
var clientCommon = require('@algolia/client-common');
|
|
7
5
|
var http = require('http');
|
|
8
6
|
var https = require('https');
|
|
9
7
|
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
|
|
13
|
-
var https__default = /*#__PURE__*/_interopDefaultLegacy(https);
|
|
14
|
-
|
|
15
|
-
function echoRequester(status = 200) {
|
|
16
|
-
return clientCommon.createEchoRequester({ getURL: (url$1) => new url.URL(url$1), status });
|
|
8
|
+
function echoRequester(status = 200) {
|
|
9
|
+
return clientCommon.createEchoRequester({ getURL: (url$1) => new url.URL(url$1), status });
|
|
17
10
|
}
|
|
18
11
|
|
|
19
|
-
// Global agents allow us to reuse the TCP protocol with multiple clients
|
|
20
|
-
const agentOptions = { keepAlive: true };
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
function createHttpRequester() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
12
|
+
// Global agents allow us to reuse the TCP protocol with multiple clients
|
|
13
|
+
const agentOptions = { keepAlive: true };
|
|
14
|
+
const defaultHttpAgent = new http.Agent(agentOptions);
|
|
15
|
+
const defaultHttpsAgent = new https.Agent(agentOptions);
|
|
16
|
+
function createHttpRequester({ agent: userGlobalAgent, httpAgent: userHttpAgent, httpsAgent: userHttpsAgent, requesterOptions = {}, } = {}) {
|
|
17
|
+
const httpAgent = userHttpAgent || userGlobalAgent || defaultHttpAgent;
|
|
18
|
+
const httpsAgent = userHttpsAgent || userGlobalAgent || defaultHttpsAgent;
|
|
19
|
+
function send(request) {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
let responseTimeout;
|
|
22
|
+
// eslint-disable-next-line prefer-const -- linter thinks this is not reassigned
|
|
23
|
+
let connectTimeout;
|
|
24
|
+
const url$1 = new url.URL(request.url);
|
|
25
|
+
const path = url$1.search === null ? url$1.pathname : `${url$1.pathname}${url$1.search}`;
|
|
26
|
+
const options = {
|
|
27
|
+
agent: url$1.protocol === 'https:' ? httpsAgent : httpAgent,
|
|
28
|
+
hostname: url$1.hostname,
|
|
29
|
+
path,
|
|
30
|
+
method: request.method,
|
|
31
|
+
...requesterOptions,
|
|
32
|
+
headers: {
|
|
33
|
+
...request.headers,
|
|
34
|
+
...requesterOptions.headers,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
if (url$1.port && !requesterOptions.port) {
|
|
38
|
+
options.port = url$1.port;
|
|
39
|
+
}
|
|
40
|
+
const req = (url$1.protocol === 'https:' ? https : http).request(options, (response) => {
|
|
41
|
+
let contentBuffers = [];
|
|
42
|
+
response.on('data', (chunk) => {
|
|
43
|
+
contentBuffers = contentBuffers.concat(chunk);
|
|
44
|
+
});
|
|
45
|
+
response.on('end', () => {
|
|
46
|
+
clearTimeout(connectTimeout);
|
|
47
|
+
clearTimeout(responseTimeout);
|
|
48
|
+
resolve({
|
|
49
|
+
status: response.statusCode || 0,
|
|
50
|
+
content: Buffer.concat(contentBuffers).toString(),
|
|
51
|
+
isTimedOut: false,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
const createTimeout = (timeout, content) => {
|
|
56
|
+
return setTimeout(() => {
|
|
57
|
+
req.destroy();
|
|
58
|
+
resolve({
|
|
59
|
+
status: 0,
|
|
60
|
+
content,
|
|
61
|
+
isTimedOut: true,
|
|
62
|
+
});
|
|
63
|
+
}, timeout);
|
|
64
|
+
};
|
|
65
|
+
connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
|
|
66
|
+
req.on('error', (error) => {
|
|
67
|
+
clearTimeout(connectTimeout);
|
|
68
|
+
clearTimeout(responseTimeout);
|
|
69
|
+
resolve({ status: 0, content: error.message, isTimedOut: false });
|
|
70
|
+
});
|
|
71
|
+
req.once('response', () => {
|
|
72
|
+
clearTimeout(connectTimeout);
|
|
73
|
+
responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
|
|
74
|
+
});
|
|
75
|
+
if (request.data !== undefined) {
|
|
76
|
+
req.write(request.data);
|
|
77
|
+
}
|
|
78
|
+
req.end();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return { send };
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
exports.createHttpRequester = createHttpRequester;
|
|
@@ -3,72 +3,80 @@ import { createEchoRequester } from '@algolia/client-common';
|
|
|
3
3
|
import http from 'http';
|
|
4
4
|
import https from 'https';
|
|
5
5
|
|
|
6
|
-
function echoRequester(status = 200) {
|
|
7
|
-
return createEchoRequester({ getURL: (url) => new URL(url), status });
|
|
6
|
+
function echoRequester(status = 200) {
|
|
7
|
+
return createEchoRequester({ getURL: (url) => new URL(url), status });
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
// Global agents allow us to reuse the TCP protocol with multiple clients
|
|
11
|
-
const agentOptions = { keepAlive: true };
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
function createHttpRequester() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
let
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
10
|
+
// Global agents allow us to reuse the TCP protocol with multiple clients
|
|
11
|
+
const agentOptions = { keepAlive: true };
|
|
12
|
+
const defaultHttpAgent = new http.Agent(agentOptions);
|
|
13
|
+
const defaultHttpsAgent = new https.Agent(agentOptions);
|
|
14
|
+
function createHttpRequester({ agent: userGlobalAgent, httpAgent: userHttpAgent, httpsAgent: userHttpsAgent, requesterOptions = {}, } = {}) {
|
|
15
|
+
const httpAgent = userHttpAgent || userGlobalAgent || defaultHttpAgent;
|
|
16
|
+
const httpsAgent = userHttpsAgent || userGlobalAgent || defaultHttpsAgent;
|
|
17
|
+
function send(request) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
let responseTimeout;
|
|
20
|
+
// eslint-disable-next-line prefer-const -- linter thinks this is not reassigned
|
|
21
|
+
let connectTimeout;
|
|
22
|
+
const url = new URL(request.url);
|
|
23
|
+
const path = url.search === null ? url.pathname : `${url.pathname}${url.search}`;
|
|
24
|
+
const options = {
|
|
25
|
+
agent: url.protocol === 'https:' ? httpsAgent : httpAgent,
|
|
26
|
+
hostname: url.hostname,
|
|
27
|
+
path,
|
|
28
|
+
method: request.method,
|
|
29
|
+
...requesterOptions,
|
|
30
|
+
headers: {
|
|
31
|
+
...request.headers,
|
|
32
|
+
...requesterOptions.headers,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
if (url.port && !requesterOptions.port) {
|
|
36
|
+
options.port = url.port;
|
|
37
|
+
}
|
|
38
|
+
const req = (url.protocol === 'https:' ? https : http).request(options, (response) => {
|
|
39
|
+
let contentBuffers = [];
|
|
40
|
+
response.on('data', (chunk) => {
|
|
41
|
+
contentBuffers = contentBuffers.concat(chunk);
|
|
42
|
+
});
|
|
43
|
+
response.on('end', () => {
|
|
44
|
+
clearTimeout(connectTimeout);
|
|
45
|
+
clearTimeout(responseTimeout);
|
|
46
|
+
resolve({
|
|
47
|
+
status: response.statusCode || 0,
|
|
48
|
+
content: Buffer.concat(contentBuffers).toString(),
|
|
49
|
+
isTimedOut: false,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
const createTimeout = (timeout, content) => {
|
|
54
|
+
return setTimeout(() => {
|
|
55
|
+
req.destroy();
|
|
56
|
+
resolve({
|
|
57
|
+
status: 0,
|
|
58
|
+
content,
|
|
59
|
+
isTimedOut: true,
|
|
60
|
+
});
|
|
61
|
+
}, timeout);
|
|
62
|
+
};
|
|
63
|
+
connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
|
|
64
|
+
req.on('error', (error) => {
|
|
65
|
+
clearTimeout(connectTimeout);
|
|
66
|
+
clearTimeout(responseTimeout);
|
|
67
|
+
resolve({ status: 0, content: error.message, isTimedOut: false });
|
|
68
|
+
});
|
|
69
|
+
req.once('response', () => {
|
|
70
|
+
clearTimeout(connectTimeout);
|
|
71
|
+
responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
|
|
72
|
+
});
|
|
73
|
+
if (request.data !== undefined) {
|
|
74
|
+
req.write(request.data);
|
|
75
|
+
}
|
|
76
|
+
req.end();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return { send };
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
export { createHttpRequester, echoRequester };
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import http from 'http';
|
|
4
|
+
import https from 'https';
|
|
5
|
+
import type { Requester } from '@algolia/client-common';
|
|
6
|
+
export type CreateHttpRequesterOptions = Partial<{
|
|
7
|
+
agent: http.Agent | https.Agent;
|
|
8
|
+
httpAgent: http.Agent;
|
|
9
|
+
httpsAgent: https.Agent;
|
|
10
|
+
/**
|
|
11
|
+
* RequestOptions to be merged with the end request, it will override default options if provided.
|
|
12
|
+
*/
|
|
13
|
+
requesterOptions: https.RequestOptions;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function createHttpRequester({ agent: userGlobalAgent, httpAgent: userHttpAgent, httpsAgent: userHttpsAgent, requesterOptions, }?: CreateHttpRequesterOptions): Requester;
|
|
3
16
|
//# sourceMappingURL=createHttpRequester.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createHttpRequester.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"createHttpRequester.d.ts","sourceRoot":"","sources":["../../src/createHttpRequester.ts"],"names":[],"mappings":";;AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAc,SAAS,EAAY,MAAM,wBAAwB,CAAC;AAE9E,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC;IAC/C,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAChC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC;IACtB,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC;IACxB;;OAEG;IACH,gBAAgB,EAAE,KAAK,CAAC,cAAc,CAAC;CACxC,CAAC,CAAC;AAOH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,cAAc,EAC1B,gBAAqB,GACtB,GAAE,0BAA+B,GAAG,SAAS,CA6F7C"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { Requester } from '@algolia/client-common';
|
|
2
|
-
export declare function echoRequester(status?: number): Requester;
|
|
1
|
+
import type { Requester } from '@algolia/client-common';
|
|
2
|
+
export declare function echoRequester(status?: number): Requester;
|
|
3
3
|
//# sourceMappingURL=echoRequester.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"echoRequester.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"echoRequester.d.ts","sourceRoot":"","sources":["../../src/echoRequester.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,wBAAgB,aAAa,CAAC,MAAM,GAAE,MAAY,GAAG,SAAS,CAE7D"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@algolia/requester-node-http",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.100",
|
|
4
4
|
"description": "Promise-based request library for node using the native http module.",
|
|
5
5
|
"repository": "algolia/algoliasearch-client-javascript",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Algolia",
|
|
8
|
-
"
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/requester-node-http.cjs",
|
|
9
10
|
"module": "dist/requester-node-http.esm.node.js",
|
|
10
11
|
"types": "dist/index.d.ts",
|
|
11
12
|
"files": [
|
|
@@ -14,19 +15,22 @@
|
|
|
14
15
|
"index.ts"
|
|
15
16
|
],
|
|
16
17
|
"scripts": {
|
|
17
|
-
"
|
|
18
|
+
"build": "yarn clean && rollup --config",
|
|
19
|
+
"clean": "rm -rf ./dist || true",
|
|
18
20
|
"test": "jest"
|
|
19
21
|
},
|
|
20
22
|
"dependencies": {
|
|
21
|
-
"@algolia/client-common": "5.0.0-alpha.
|
|
23
|
+
"@algolia/client-common": "5.0.0-alpha.100"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
24
|
-
"@
|
|
25
|
-
"@
|
|
26
|
-
"jest": "
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
26
|
+
"@babel/preset-env": "7.23.9",
|
|
27
|
+
"@babel/preset-typescript": "7.23.3",
|
|
28
|
+
"@types/jest": "29.5.11",
|
|
29
|
+
"@types/node": "20.11.0",
|
|
30
|
+
"jest": "29.7.0",
|
|
31
|
+
"nock": "13.5.1",
|
|
32
|
+
"ts-jest": "29.1.2",
|
|
33
|
+
"typescript": "5.3.3"
|
|
30
34
|
},
|
|
31
35
|
"engines": {
|
|
32
36
|
"node": ">= 14.0.0"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import https from 'https';
|
|
2
3
|
import { Readable } from 'stream';
|
|
3
4
|
|
|
4
5
|
import type { EndRequest } from '@algolia/client-common';
|
|
@@ -17,6 +18,72 @@ import {
|
|
|
17
18
|
|
|
18
19
|
const requester = createHttpRequester();
|
|
19
20
|
|
|
21
|
+
const httpsBaseRequest = https.request;
|
|
22
|
+
const httpBaseRequest = http.request;
|
|
23
|
+
|
|
24
|
+
describe('api', () => {
|
|
25
|
+
const mockedRequestResponse = {
|
|
26
|
+
destroy: jest.fn(),
|
|
27
|
+
on: jest.fn(),
|
|
28
|
+
once: jest.fn(),
|
|
29
|
+
write: jest.fn(),
|
|
30
|
+
end: jest.fn(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
beforeAll(() => {
|
|
34
|
+
// @ts-expect-error we don't care about the response for those tests
|
|
35
|
+
https.request = jest.fn(() => mockedRequestResponse);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
afterAll(() => {
|
|
39
|
+
https.request = httpsBaseRequest;
|
|
40
|
+
http.request = httpBaseRequest;
|
|
41
|
+
jest.resetAllMocks();
|
|
42
|
+
jest.clearAllMocks();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('allow init without parameters', () => {
|
|
46
|
+
expect(() => createHttpRequester()).not.toThrow();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('allow providing custom agent', async () => {
|
|
50
|
+
const agent = new http.Agent();
|
|
51
|
+
// @ts-expect-error we don't care about the response for those tests
|
|
52
|
+
http.request = jest.fn(() => mockedRequestResponse);
|
|
53
|
+
const tmpRequester = createHttpRequester({
|
|
54
|
+
agent,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await tmpRequester.send({
|
|
58
|
+
...requestStub,
|
|
59
|
+
url: 'http://algolia-dns.net/foo?x-algolia-header=bar',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(http.request).toHaveBeenCalled();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('allow overriding default options', async () => {
|
|
66
|
+
const tmpRequester = createHttpRequester({
|
|
67
|
+
requesterOptions: {
|
|
68
|
+
headers: {
|
|
69
|
+
'my-extra-header': 'algolia',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await tmpRequester.send(requestStub);
|
|
75
|
+
|
|
76
|
+
expect(https.request).toHaveBeenCalledWith(
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
headers: expect.objectContaining({
|
|
79
|
+
'my-extra-header': 'algolia',
|
|
80
|
+
}),
|
|
81
|
+
}),
|
|
82
|
+
expect.any(Function)
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
20
87
|
describe('status code handling', () => {
|
|
21
88
|
it('sends requests', async () => {
|
|
22
89
|
const body = getStringifiedBody();
|
|
@@ -84,8 +151,8 @@ describe('status code handling', () => {
|
|
|
84
151
|
// create a test response stream that is chunked inside a unicode character
|
|
85
152
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
86
153
|
function* generate() {
|
|
87
|
-
yield data.
|
|
88
|
-
yield data.
|
|
154
|
+
yield data.subarray(0, 3);
|
|
155
|
+
yield data.subarray(3);
|
|
89
156
|
}
|
|
90
157
|
|
|
91
158
|
const testStream = Readable.from(generate());
|
|
@@ -119,14 +186,14 @@ describe('timeout handling', () => {
|
|
|
119
186
|
const response = await requester.send({
|
|
120
187
|
...timeoutRequest,
|
|
121
188
|
connectTimeout: 1000,
|
|
122
|
-
url: 'http://
|
|
189
|
+
url: 'http://localhost:1111/connection_timeout',
|
|
123
190
|
});
|
|
124
191
|
|
|
125
192
|
const now = Date.now();
|
|
126
193
|
|
|
127
194
|
expect(response.content).toBe('Connection timeout');
|
|
128
|
-
expect(now - before).
|
|
129
|
-
expect(now - before).
|
|
195
|
+
expect(now - before).toBeGreaterThanOrEqual(999);
|
|
196
|
+
expect(now - before).toBeLessThanOrEqual(1200);
|
|
130
197
|
});
|
|
131
198
|
|
|
132
199
|
it('connection timeouts with the given 2 seconds connection timeout', async () => {
|
|
@@ -134,14 +201,14 @@ describe('timeout handling', () => {
|
|
|
134
201
|
const response = await requester.send({
|
|
135
202
|
...timeoutRequest,
|
|
136
203
|
connectTimeout: 2000,
|
|
137
|
-
url: 'http://
|
|
204
|
+
url: 'http://localhost:1111/connection_timeout',
|
|
138
205
|
});
|
|
139
206
|
|
|
140
207
|
const now = Date.now();
|
|
141
208
|
|
|
142
209
|
expect(response.content).toBe('Connection timeout');
|
|
143
|
-
expect(now - before).
|
|
144
|
-
expect(now - before).
|
|
210
|
+
expect(now - before).toBeGreaterThanOrEqual(1999);
|
|
211
|
+
expect(now - before).toBeLessThanOrEqual(2200);
|
|
145
212
|
});
|
|
146
213
|
|
|
147
214
|
it("socket timeouts if response don't appears before the timeout with 2 seconds timeout", async () => {
|
|
@@ -156,8 +223,8 @@ describe('timeout handling', () => {
|
|
|
156
223
|
const now = Date.now();
|
|
157
224
|
|
|
158
225
|
expect(response.content).toBe('Socket timeout');
|
|
159
|
-
expect(now - before).
|
|
160
|
-
expect(now - before).
|
|
226
|
+
expect(now - before).toBeGreaterThanOrEqual(1999);
|
|
227
|
+
expect(now - before).toBeLessThanOrEqual(2200);
|
|
161
228
|
});
|
|
162
229
|
|
|
163
230
|
it("socket timeouts if response don't appears before the timeout with 3 seconds timeout", async () => {
|
|
@@ -171,8 +238,8 @@ describe('timeout handling', () => {
|
|
|
171
238
|
const now = Date.now();
|
|
172
239
|
|
|
173
240
|
expect(response.content).toBe('Socket timeout');
|
|
174
|
-
expect(now - before).
|
|
175
|
-
expect(now - before).
|
|
241
|
+
expect(now - before).toBeGreaterThanOrEqual(2999);
|
|
242
|
+
expect(now - before).toBeLessThanOrEqual(3200);
|
|
176
243
|
});
|
|
177
244
|
|
|
178
245
|
it('do not timeouts if response appears before the timeout', async () => {
|
|
@@ -188,8 +255,8 @@ describe('timeout handling', () => {
|
|
|
188
255
|
expect(response.isTimedOut).toBe(false);
|
|
189
256
|
expect(response.status).toBe(200);
|
|
190
257
|
expect(response.content).toBe('{"foo": "bar"}');
|
|
191
|
-
expect(now - before).
|
|
192
|
-
expect(now - before).
|
|
258
|
+
expect(now - before).toBeGreaterThanOrEqual(4999);
|
|
259
|
+
expect(now - before).toBeLessThanOrEqual(5200);
|
|
193
260
|
}, 10000); // This is a long-running test, default server timeout is set to 5000ms
|
|
194
261
|
});
|
|
195
262
|
|
|
@@ -4,12 +4,30 @@ import { URL } from 'url';
|
|
|
4
4
|
|
|
5
5
|
import type { EndRequest, Requester, Response } from '@algolia/client-common';
|
|
6
6
|
|
|
7
|
+
export type CreateHttpRequesterOptions = Partial<{
|
|
8
|
+
agent: http.Agent | https.Agent;
|
|
9
|
+
httpAgent: http.Agent;
|
|
10
|
+
httpsAgent: https.Agent;
|
|
11
|
+
/**
|
|
12
|
+
* RequestOptions to be merged with the end request, it will override default options if provided.
|
|
13
|
+
*/
|
|
14
|
+
requesterOptions: https.RequestOptions;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
7
17
|
// Global agents allow us to reuse the TCP protocol with multiple clients
|
|
8
18
|
const agentOptions = { keepAlive: true };
|
|
9
|
-
const
|
|
10
|
-
const
|
|
19
|
+
const defaultHttpAgent = new http.Agent(agentOptions);
|
|
20
|
+
const defaultHttpsAgent = new https.Agent(agentOptions);
|
|
21
|
+
|
|
22
|
+
export function createHttpRequester({
|
|
23
|
+
agent: userGlobalAgent,
|
|
24
|
+
httpAgent: userHttpAgent,
|
|
25
|
+
httpsAgent: userHttpsAgent,
|
|
26
|
+
requesterOptions = {},
|
|
27
|
+
}: CreateHttpRequesterOptions = {}): Requester {
|
|
28
|
+
const httpAgent = userHttpAgent || userGlobalAgent || defaultHttpAgent;
|
|
29
|
+
const httpsAgent = userHttpsAgent || userGlobalAgent || defaultHttpsAgent;
|
|
11
30
|
|
|
12
|
-
export function createHttpRequester(): Requester {
|
|
13
31
|
function send(request: EndRequest): Promise<Response> {
|
|
14
32
|
return new Promise((resolve) => {
|
|
15
33
|
let responseTimeout: NodeJS.Timeout | undefined;
|
|
@@ -23,10 +41,17 @@ export function createHttpRequester(): Requester {
|
|
|
23
41
|
hostname: url.hostname,
|
|
24
42
|
path,
|
|
25
43
|
method: request.method,
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
...requesterOptions,
|
|
45
|
+
headers: {
|
|
46
|
+
...request.headers,
|
|
47
|
+
...requesterOptions.headers,
|
|
48
|
+
},
|
|
28
49
|
};
|
|
29
50
|
|
|
51
|
+
if (url.port && !requesterOptions.port) {
|
|
52
|
+
options.port = url.port;
|
|
53
|
+
}
|
|
54
|
+
|
|
30
55
|
const req = (url.protocol === 'https:' ? https : http).request(
|
|
31
56
|
options,
|
|
32
57
|
(response) => {
|