@e22m4u/js-trie-router 0.2.0 → 0.3.0
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/README.md +3 -3
- package/dist/cjs/index.cjs +225 -213
- package/examples/{cookie-parsing-example.js → cookies-parsing-example.js} +8 -8
- package/examples/params-parsing-example.js +11 -7
- package/examples/query-parsing-example.js +11 -7
- package/examples/uptime-example.js +4 -4
- package/package.json +9 -8
- package/src/debuggable-service.d.ts +2 -10
- package/src/debuggable-service.js +16 -17
- package/src/hooks/hook-invoker.js +3 -4
- package/src/hooks/hook-invoker.spec.js +3 -3
- package/src/hooks/hook-registry.d.ts +1 -1
- package/src/hooks/hook-registry.js +6 -7
- package/src/hooks/hook-registry.spec.js +14 -5
- package/src/parsers/body-parser.js +10 -11
- package/src/parsers/body-parser.spec.js +4 -4
- package/src/parsers/cookies-parser.d.ts +15 -0
- package/src/parsers/cookies-parser.js +33 -0
- package/src/parsers/{cookie-parser.spec.js → cookies-parser.spec.js} +6 -6
- package/src/parsers/index.d.ts +1 -1
- package/src/parsers/index.js +1 -1
- package/src/parsers/query-parser.js +4 -3
- package/src/parsers/request-parser.d.ts +2 -2
- package/src/parsers/request-parser.js +7 -7
- package/src/parsers/request-parser.spec.js +12 -12
- package/src/request-context.d.ts +3 -3
- package/src/request-context.js +5 -5
- package/src/request-context.spec.js +3 -3
- package/src/route-registry.js +14 -14
- package/src/route-registry.spec.js +4 -1
- package/src/route.d.ts +12 -7
- package/src/route.js +16 -14
- package/src/route.spec.js +13 -7
- package/src/router-options.js +1 -1
- package/src/router-options.spec.js +1 -1
- package/src/senders/data-sender.js +6 -5
- package/src/senders/error-sender.js +11 -4
- package/src/trie-router.js +46 -38
- package/src/trie-router.spec.js +54 -3
- package/src/utils/create-cookies-string.d.ts +6 -0
- package/src/utils/{create-cookie-string.js → create-cookies-string.js} +4 -4
- package/src/utils/{create-cookie-string.spec.js → create-cookies-string.spec.js} +7 -7
- package/src/utils/create-debugger.js +1 -1
- package/src/utils/create-debugger.spec.js +1 -1
- package/src/utils/create-error.js +2 -2
- package/src/utils/create-error.spec.js +2 -2
- package/src/utils/create-request-mock.d.ts +1 -1
- package/src/utils/create-request-mock.js +47 -43
- package/src/utils/create-request-mock.spec.js +18 -18
- package/src/utils/fetch-request-body.d.ts +11 -2
- package/src/utils/fetch-request-body.js +10 -17
- package/src/utils/fetch-request-body.spec.js +8 -9
- package/src/utils/get-request-pathname.js +1 -1
- package/src/utils/get-request-pathname.spec.js +1 -1
- package/src/utils/index.d.ts +2 -2
- package/src/utils/index.js +2 -2
- package/src/utils/is-readable-stream.js +1 -2
- package/src/utils/is-response-sent.js +1 -1
- package/src/utils/is-response-sent.spec.js +1 -1
- package/src/utils/parse-content-type.js +1 -1
- package/src/utils/parse-cookies.d.ts +19 -0
- package/src/utils/{parse-cookie.js → parse-cookies.js} +8 -5
- package/src/utils/{parse-cookie.spec.js → parse-cookies.spec.js} +13 -8
- package/src/utils/to-camel-case.js +1 -1
- package/src/utils/to-camel-case.spec.js +1 -1
- package/src/parsers/cookie-parser.d.ts +0 -15
- package/src/parsers/cookie-parser.js +0 -32
- package/src/utils/create-cookie-string.d.ts +0 -6
- package/src/utils/parse-cookie.d.ts +0 -19
package/src/trie-router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {HookType} from './hooks/index.js';
|
|
2
|
-
import {isPromise} from './utils/index.js';
|
|
2
|
+
import {isPromise, isResponseSent} from './utils/index.js';
|
|
3
3
|
import {HookInvoker} from './hooks/index.js';
|
|
4
4
|
import {DataSender} from './senders/index.js';
|
|
5
5
|
import {HookRegistry} from './hooks/index.js';
|
|
@@ -31,11 +31,11 @@ export class TrieRouter extends DebuggableService {
|
|
|
31
31
|
* ```
|
|
32
32
|
* const router = new TrieRouter();
|
|
33
33
|
* router.defineRoute({
|
|
34
|
-
* method: HttpMethod.POST,
|
|
34
|
+
* method: HttpMethod.POST, // Request method.
|
|
35
35
|
* path: '/users/:id', // The path template may have parameters.
|
|
36
|
-
* preHandler(ctx) { ... }, // The "preHandler"
|
|
36
|
+
* preHandler(ctx) { ... }, // The "preHandler" executes before a route handler.
|
|
37
37
|
* handler(ctx) { ... }, // Request handler function.
|
|
38
|
-
* postHandler(ctx, data) { ... }, // The "postHandler"
|
|
38
|
+
* postHandler(ctx, data) { ... }, // The "postHandler" executes after a route handler.
|
|
39
39
|
* });
|
|
40
40
|
* ```
|
|
41
41
|
*
|
|
@@ -75,11 +75,16 @@ export class TrieRouter extends DebuggableService {
|
|
|
75
75
|
* @private
|
|
76
76
|
*/
|
|
77
77
|
async _handleRequest(req, res) {
|
|
78
|
+
const debug = this.getDebuggerFor(this._handleRequest);
|
|
78
79
|
const requestPath = (req.url || '/').replace(/\?.*$/, '');
|
|
79
|
-
|
|
80
|
+
debug(
|
|
81
|
+
'Preparing to handle an incoming request %s %v.',
|
|
82
|
+
req.method,
|
|
83
|
+
requestPath,
|
|
84
|
+
);
|
|
80
85
|
const resolved = this.getService(RouteRegistry).matchRouteByRequest(req);
|
|
81
86
|
if (!resolved) {
|
|
82
|
-
|
|
87
|
+
debug('No route for the request %s %v.', req.method, requestPath);
|
|
83
88
|
this.getService(ErrorSender).send404(req, res);
|
|
84
89
|
} else {
|
|
85
90
|
const {route, params} = resolved;
|
|
@@ -95,27 +100,28 @@ export class TrieRouter extends DebuggableService {
|
|
|
95
100
|
// так как они были определены в момент
|
|
96
101
|
// поиска подходящего роута
|
|
97
102
|
context.params = params;
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
const reqDataOrPromise = this.getService(RequestParser).parse(req);
|
|
103
|
-
// результат разбора может являться асинхронным,
|
|
104
|
-
// и вместо того, что бы разрывать поток выполнения,
|
|
105
|
-
// стоит проверить, действительно ли необходимо
|
|
106
|
-
// использование оператора "await"
|
|
107
|
-
if (isPromise(reqDataOrPromise)) {
|
|
108
|
-
const reqData = await reqDataOrPromise;
|
|
109
|
-
Object.assign(context, reqData);
|
|
110
|
-
} else {
|
|
111
|
-
Object.assign(context, reqDataOrPromise);
|
|
112
|
-
}
|
|
113
|
-
// получение данных от обработчика, который
|
|
114
|
-
// находится в найденном роуте, и отправка
|
|
115
|
-
// результата в качестве ответа сервера
|
|
116
|
-
let data, error;
|
|
117
|
-
const hookInvoker = this.getService(HookInvoker);
|
|
103
|
+
// при разборе входящих данных и выполнении обработчиков
|
|
104
|
+
// запроса, требуется перехватывать возможные ошибки
|
|
105
|
+
// для корректной отправки сервисом ErrorSender
|
|
106
|
+
let data;
|
|
118
107
|
try {
|
|
108
|
+
// разбор тела, заголовков и других данных запроса
|
|
109
|
+
// выполняется отдельным сервисом, после чего результат
|
|
110
|
+
// записывается в контекст передаваемый обработчику
|
|
111
|
+
const reqDataOrPromise = this.getService(RequestParser).parse(req);
|
|
112
|
+
// результат разбора может являться асинхронным, и вместо
|
|
113
|
+
// того, что бы разрывать поток выполнения, стоит проверить,
|
|
114
|
+
// действительно ли необходимо использование оператора "await"
|
|
115
|
+
if (isPromise(reqDataOrPromise)) {
|
|
116
|
+
const reqData = await reqDataOrPromise;
|
|
117
|
+
Object.assign(context, reqData);
|
|
118
|
+
} else {
|
|
119
|
+
Object.assign(context, reqDataOrPromise);
|
|
120
|
+
}
|
|
121
|
+
// получение данных от обработчика, который находится
|
|
122
|
+
// в найденном маршруте, и отправка результата в качестве
|
|
123
|
+
// ответа сервера
|
|
124
|
+
const hookInvoker = this.getService(HookInvoker);
|
|
119
125
|
// если результатом вызова хуков "preHandler" является
|
|
120
126
|
// значение (или Promise) отличное от "undefined" и "null",
|
|
121
127
|
// то такое значение используется в качестве ответа
|
|
@@ -126,15 +132,15 @@ export class TrieRouter extends DebuggableService {
|
|
|
126
132
|
context,
|
|
127
133
|
);
|
|
128
134
|
if (isPromise(data)) data = await data;
|
|
129
|
-
// если ответ не
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
135
|
+
// если ответ не бы отправлен внутри "preHandler" хуков,
|
|
136
|
+
// и сами "preHandler" хуки не вернули значения, то вызывается
|
|
137
|
+
// основной обработчик маршрута, результат которого передается
|
|
138
|
+
// в хуки "postHandler"
|
|
139
|
+
if (!isResponseSent(res) && data == null) {
|
|
133
140
|
data = route.handle(context);
|
|
134
141
|
if (isPromise(data)) data = await data;
|
|
135
|
-
// вызываются хуки "postHandler", результат
|
|
136
|
-
//
|
|
137
|
-
// в качестве ответа
|
|
142
|
+
// вызываются хуки "postHandler", результат которых
|
|
143
|
+
// также может быть использован в качестве ответа
|
|
138
144
|
let postHandlerData = hookInvoker.invokeAndContinueUntilValueReceived(
|
|
139
145
|
route,
|
|
140
146
|
HookType.POST_HANDLER,
|
|
@@ -146,12 +152,14 @@ export class TrieRouter extends DebuggableService {
|
|
|
146
152
|
postHandlerData = await postHandlerData;
|
|
147
153
|
if (postHandlerData != null) data = postHandlerData;
|
|
148
154
|
}
|
|
149
|
-
} catch (
|
|
150
|
-
error = err;
|
|
151
|
-
}
|
|
152
|
-
if (error) {
|
|
155
|
+
} catch (error) {
|
|
153
156
|
this.getService(ErrorSender).send(req, res, error);
|
|
154
|
-
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// если ответ не был отправлен во время выполнения
|
|
160
|
+
// хуков и основного обработчика запроса,
|
|
161
|
+
// то результат передается в DataSender
|
|
162
|
+
if (!isResponseSent(res)) {
|
|
155
163
|
this.getService(DataSender).send(res, data);
|
|
156
164
|
}
|
|
157
165
|
}
|
package/src/trie-router.spec.js
CHANGED
|
@@ -75,13 +75,13 @@ describe('TrieRouter', function () {
|
|
|
75
75
|
router.requestListener(req, res);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
it('passes parsed
|
|
78
|
+
it('passes parsed cookies to the request context', function (done) {
|
|
79
79
|
const router = new TrieRouter();
|
|
80
80
|
router.defineRoute({
|
|
81
81
|
method: HttpMethod.GET,
|
|
82
82
|
path: '/',
|
|
83
|
-
handler: ({
|
|
84
|
-
expect(
|
|
83
|
+
handler: ({cookies}) => {
|
|
84
|
+
expect(cookies).to.be.eql({p1: 'foo', p2: 'bar'});
|
|
85
85
|
done();
|
|
86
86
|
},
|
|
87
87
|
});
|
|
@@ -472,6 +472,57 @@ describe('TrieRouter', function () {
|
|
|
472
472
|
const res = createResponseMock();
|
|
473
473
|
router.requestListener(req, res);
|
|
474
474
|
});
|
|
475
|
+
|
|
476
|
+
it('should send parsing error response instead of throwing error', async function () {
|
|
477
|
+
const router = new TrieRouter();
|
|
478
|
+
router.defineRoute({
|
|
479
|
+
method: HttpMethod.POST,
|
|
480
|
+
path: '/',
|
|
481
|
+
handler() {},
|
|
482
|
+
});
|
|
483
|
+
const req = createRequestMock({
|
|
484
|
+
method: HttpMethod.POST,
|
|
485
|
+
headers: {'content-type': 'application/json'},
|
|
486
|
+
body: 'invalid',
|
|
487
|
+
});
|
|
488
|
+
const res = createResponseMock();
|
|
489
|
+
router.requestListener(req, res);
|
|
490
|
+
const body = await res.getBody();
|
|
491
|
+
expect(res.statusCode).to.be.eq(400);
|
|
492
|
+
expect(JSON.parse(body)).to.be.eql({
|
|
493
|
+
error: {
|
|
494
|
+
message: `Unexpected token 'i', "invalid" is not valid JSON`,
|
|
495
|
+
},
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should not invoke the main handler if a preHandler sends the response asynchronously', async function () {
|
|
500
|
+
let handlerCalled = false;
|
|
501
|
+
const router = new TrieRouter();
|
|
502
|
+
router.defineRoute({
|
|
503
|
+
method: 'GET',
|
|
504
|
+
path: '/',
|
|
505
|
+
preHandler(ctx) {
|
|
506
|
+
return new Promise(resolve => {
|
|
507
|
+
setTimeout(() => {
|
|
508
|
+
ctx.res.setHeader('Content-Type', 'text/plain');
|
|
509
|
+
ctx.res.end('Response from preHandler');
|
|
510
|
+
resolve(undefined);
|
|
511
|
+
}, 10);
|
|
512
|
+
});
|
|
513
|
+
},
|
|
514
|
+
handler() {
|
|
515
|
+
handlerCalled = true;
|
|
516
|
+
return 'Response from main handler';
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
const req = createRequestMock({method: 'GET', path: '/'});
|
|
520
|
+
const res = createResponseMock();
|
|
521
|
+
await router._handleRequest(req, res);
|
|
522
|
+
const responseBody = await res.getBody();
|
|
523
|
+
expect(responseBody).to.equal('Response from preHandler');
|
|
524
|
+
expect(handlerCalled).to.be.false;
|
|
525
|
+
});
|
|
475
526
|
});
|
|
476
527
|
|
|
477
528
|
describe('addHook', function () {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {Errorf} from '@e22m4u/js-format';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Create
|
|
4
|
+
* Create cookies string.
|
|
5
5
|
*
|
|
6
6
|
* @param {object} data
|
|
7
7
|
* @returns {string}
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function createCookiesString(data) {
|
|
10
10
|
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
11
11
|
throw new Errorf(
|
|
12
|
-
'The first parameter of "
|
|
13
|
-
'an Object, but %v given.',
|
|
12
|
+
'The first parameter of "createCookiesString" should be ' +
|
|
13
|
+
'an Object, but %v was given.',
|
|
14
14
|
data,
|
|
15
15
|
);
|
|
16
16
|
let cookies = '';
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {expect} from '../chai.js';
|
|
2
2
|
import {format} from '@e22m4u/js-format';
|
|
3
|
-
import {
|
|
3
|
+
import {createCookiesString} from './create-cookies-string.js';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
5
|
+
describe('createCookiesString', function () {
|
|
6
6
|
it('requires the first argument to be an object', function () {
|
|
7
|
-
const throwable = v => () =>
|
|
7
|
+
const throwable = v => () => createCookiesString(v);
|
|
8
8
|
const error = v =>
|
|
9
9
|
format(
|
|
10
|
-
'The first parameter of "
|
|
11
|
-
'an Object, but %s given.',
|
|
10
|
+
'The first parameter of "createCookiesString" should be ' +
|
|
11
|
+
'an Object, but %s was given.',
|
|
12
12
|
v,
|
|
13
13
|
);
|
|
14
14
|
expect(throwable('str')).to.throw(error('"str"'));
|
|
@@ -25,12 +25,12 @@ describe('createCookieString', function () {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('returns an empty string if no keys', function () {
|
|
28
|
-
expect(
|
|
28
|
+
expect(createCookiesString({})).to.be.eq('');
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
it('returns a cookies string from a given object', function () {
|
|
32
32
|
const data = {foo: 'bar', baz: 'quz'};
|
|
33
|
-
const result =
|
|
33
|
+
const result = createCookiesString(data);
|
|
34
34
|
expect(result).to.be.eq('foo=bar; baz=quz;');
|
|
35
35
|
});
|
|
36
36
|
});
|
|
@@ -11,7 +11,7 @@ export function createDebugger(name) {
|
|
|
11
11
|
if (typeof name !== 'string')
|
|
12
12
|
throw new Errorf(
|
|
13
13
|
'The first argument of "createDebugger" should be ' +
|
|
14
|
-
'a String, but %v given.',
|
|
14
|
+
'a String, but %v was given.',
|
|
15
15
|
name,
|
|
16
16
|
);
|
|
17
17
|
const debug = DebugFactory(`jsTrieRouter:${name}`);
|
|
@@ -13,13 +13,13 @@ export function createError(errorCtor, message, ...args) {
|
|
|
13
13
|
if (typeof errorCtor !== 'function')
|
|
14
14
|
throw new Errorf(
|
|
15
15
|
'The first argument of "createError" should be ' +
|
|
16
|
-
'a constructor, but %v given.',
|
|
16
|
+
'a constructor, but %v was given.',
|
|
17
17
|
errorCtor,
|
|
18
18
|
);
|
|
19
19
|
if (message != null && typeof message !== 'string')
|
|
20
20
|
throw new Errorf(
|
|
21
21
|
'The second argument of "createError" should be ' +
|
|
22
|
-
'a String, but %v given.',
|
|
22
|
+
'a String, but %v was given.',
|
|
23
23
|
message,
|
|
24
24
|
);
|
|
25
25
|
if (message == null) return new errorCtor();
|
|
@@ -8,7 +8,7 @@ describe('createError', function () {
|
|
|
8
8
|
const error = v =>
|
|
9
9
|
format(
|
|
10
10
|
'The first argument of "createError" should be ' +
|
|
11
|
-
'a constructor, but %s given.',
|
|
11
|
+
'a constructor, but %s was given.',
|
|
12
12
|
v,
|
|
13
13
|
);
|
|
14
14
|
expect(throwable('str')).to.throw(error('"str"'));
|
|
@@ -29,7 +29,7 @@ describe('createError', function () {
|
|
|
29
29
|
const error = v =>
|
|
30
30
|
format(
|
|
31
31
|
'The second argument of "createError" should be ' +
|
|
32
|
-
'a String, but %s given.',
|
|
32
|
+
'a String, but %s was given.',
|
|
33
33
|
v,
|
|
34
34
|
);
|
|
35
35
|
expect(throwable(10)).to.throw(error('10'));
|
|
@@ -4,8 +4,8 @@ import {IncomingMessage} from 'http';
|
|
|
4
4
|
import queryString from 'querystring';
|
|
5
5
|
import {Errorf} from '@e22m4u/js-format';
|
|
6
6
|
import {isReadableStream} from './is-readable-stream.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import {createCookiesString} from './create-cookies-string.js';
|
|
8
|
+
import {CHARACTER_ENCODING_LIST} from './fetch-request-body.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {{
|
|
@@ -14,7 +14,7 @@ import {BUFFER_ENCODING_LIST} from './fetch-request-body.js';
|
|
|
14
14
|
* secure?: boolean;
|
|
15
15
|
* path?: string;
|
|
16
16
|
* query?: object;
|
|
17
|
-
*
|
|
17
|
+
* cookies?: object;
|
|
18
18
|
* headers?: object;
|
|
19
19
|
* body?: string;
|
|
20
20
|
* stream?: import('stream').Readable;
|
|
@@ -32,7 +32,7 @@ export function createRequestMock(patch) {
|
|
|
32
32
|
if ((patch != null && typeof patch !== 'object') || Array.isArray(patch)) {
|
|
33
33
|
throw new Errorf(
|
|
34
34
|
'The first parameter of "createRequestMock" ' +
|
|
35
|
-
'should be an Object, but %v given.',
|
|
35
|
+
'should be an Object, but %v was given.',
|
|
36
36
|
patch,
|
|
37
37
|
);
|
|
38
38
|
}
|
|
@@ -40,25 +40,25 @@ export function createRequestMock(patch) {
|
|
|
40
40
|
if (patch.host != null && typeof patch.host !== 'string')
|
|
41
41
|
throw new Errorf(
|
|
42
42
|
'The parameter "host" of "createRequestMock" ' +
|
|
43
|
-
'should be a String, but %v given.',
|
|
43
|
+
'should be a String, but %v was given.',
|
|
44
44
|
patch.host,
|
|
45
45
|
);
|
|
46
46
|
if (patch.method != null && typeof patch.method !== 'string')
|
|
47
47
|
throw new Errorf(
|
|
48
48
|
'The parameter "method" of "createRequestMock" ' +
|
|
49
|
-
'should be a String, but %v given.',
|
|
49
|
+
'should be a String, but %v was given.',
|
|
50
50
|
patch.method,
|
|
51
51
|
);
|
|
52
52
|
if (patch.secure != null && typeof patch.secure !== 'boolean')
|
|
53
53
|
throw new Errorf(
|
|
54
54
|
'The parameter "secure" of "createRequestMock" ' +
|
|
55
|
-
'should be a Boolean, but %v given.',
|
|
55
|
+
'should be a Boolean, but %v was given.',
|
|
56
56
|
patch.secure,
|
|
57
57
|
);
|
|
58
58
|
if (patch.path != null && typeof patch.path !== 'string')
|
|
59
59
|
throw new Errorf(
|
|
60
60
|
'The parameter "path" of "createRequestMock" ' +
|
|
61
|
-
'should be a String, but %v given.',
|
|
61
|
+
'should be a String, but %v was given.',
|
|
62
62
|
patch.path,
|
|
63
63
|
);
|
|
64
64
|
if (
|
|
@@ -69,20 +69,20 @@ export function createRequestMock(patch) {
|
|
|
69
69
|
) {
|
|
70
70
|
throw new Errorf(
|
|
71
71
|
'The parameter "query" of "createRequestMock" ' +
|
|
72
|
-
'should be a String or Object, but %v given.',
|
|
72
|
+
'should be a String or Object, but %v was given.',
|
|
73
73
|
patch.query,
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
if (
|
|
77
|
-
(patch.
|
|
78
|
-
typeof patch.
|
|
79
|
-
typeof patch.
|
|
80
|
-
Array.isArray(patch.
|
|
77
|
+
(patch.cookies != null &&
|
|
78
|
+
typeof patch.cookies !== 'string' &&
|
|
79
|
+
typeof patch.cookies !== 'object') ||
|
|
80
|
+
Array.isArray(patch.cookies)
|
|
81
81
|
) {
|
|
82
82
|
throw new Errorf(
|
|
83
|
-
'The parameter "
|
|
84
|
-
'should be a String or Object, but %v given.',
|
|
85
|
-
patch.
|
|
83
|
+
'The parameter "cookies" of "createRequestMock" ' +
|
|
84
|
+
'should be a String or Object, but %v was given.',
|
|
85
|
+
patch.cookies,
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
88
|
if (
|
|
@@ -91,25 +91,28 @@ export function createRequestMock(patch) {
|
|
|
91
91
|
) {
|
|
92
92
|
throw new Errorf(
|
|
93
93
|
'The parameter "headers" of "createRequestMock" ' +
|
|
94
|
-
'should be an Object, but %v given.',
|
|
94
|
+
'should be an Object, but %v was given.',
|
|
95
95
|
patch.headers,
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
if (patch.stream != null && !isReadableStream(patch.stream))
|
|
99
99
|
throw new Errorf(
|
|
100
100
|
'The parameter "stream" of "createRequestMock" ' +
|
|
101
|
-
'should be a Stream, but %v given.',
|
|
101
|
+
'should be a Stream, but %v was given.',
|
|
102
102
|
patch.stream,
|
|
103
103
|
);
|
|
104
104
|
if (patch.encoding != null) {
|
|
105
105
|
if (typeof patch.encoding !== 'string')
|
|
106
106
|
throw new Errorf(
|
|
107
107
|
'The parameter "encoding" of "createRequestMock" ' +
|
|
108
|
-
'should be a String, but %v given.',
|
|
108
|
+
'should be a String, but %v was given.',
|
|
109
|
+
patch.encoding,
|
|
110
|
+
);
|
|
111
|
+
if (!CHARACTER_ENCODING_LIST.includes(patch.encoding))
|
|
112
|
+
throw new Errorf(
|
|
113
|
+
'Character encoding %v is not supported.',
|
|
109
114
|
patch.encoding,
|
|
110
115
|
);
|
|
111
|
-
if (!BUFFER_ENCODING_LIST.includes(patch.encoding))
|
|
112
|
-
throw new Errorf('Buffer encoding %v is not supported.', patch.encoding);
|
|
113
116
|
}
|
|
114
117
|
// если передан поток, выполняется
|
|
115
118
|
// проверка на несовместимые опции
|
|
@@ -141,7 +144,7 @@ export function createRequestMock(patch) {
|
|
|
141
144
|
patch.host,
|
|
142
145
|
patch.secure,
|
|
143
146
|
patch.body,
|
|
144
|
-
patch.
|
|
147
|
+
patch.cookies,
|
|
145
148
|
patch.encoding,
|
|
146
149
|
patch.headers,
|
|
147
150
|
);
|
|
@@ -161,7 +164,7 @@ function createRequestStream(secure, body, encoding) {
|
|
|
161
164
|
if (encoding != null && typeof encoding !== 'string')
|
|
162
165
|
throw new Errorf(
|
|
163
166
|
'The parameter "encoding" of "createRequestStream" ' +
|
|
164
|
-
'should be a String, but %v given.',
|
|
167
|
+
'should be a String, but %v was given.',
|
|
165
168
|
encoding,
|
|
166
169
|
);
|
|
167
170
|
encoding = encoding || 'utf-8';
|
|
@@ -198,7 +201,7 @@ function createRequestUrl(path, query) {
|
|
|
198
201
|
if (typeof path !== 'string')
|
|
199
202
|
throw new Errorf(
|
|
200
203
|
'The parameter "path" of "createRequestUrl" ' +
|
|
201
|
-
'should be a String, but %v given.',
|
|
204
|
+
'should be a String, but %v was given.',
|
|
202
205
|
path,
|
|
203
206
|
);
|
|
204
207
|
if (
|
|
@@ -207,7 +210,7 @@ function createRequestUrl(path, query) {
|
|
|
207
210
|
) {
|
|
208
211
|
throw new Errorf(
|
|
209
212
|
'The parameter "query" of "createRequestUrl" ' +
|
|
210
|
-
'should be a String or Object, but %v given.',
|
|
213
|
+
'should be a String or Object, but %v was given.',
|
|
211
214
|
query,
|
|
212
215
|
);
|
|
213
216
|
}
|
|
@@ -227,36 +230,36 @@ function createRequestUrl(path, query) {
|
|
|
227
230
|
* @param {string|null|undefined} host
|
|
228
231
|
* @param {boolean|null|undefined} secure
|
|
229
232
|
* @param {*} body
|
|
230
|
-
* @param {string|object|null|undefined}
|
|
233
|
+
* @param {string|object|null|undefined} cookies
|
|
231
234
|
* @param {import('buffer').BufferEncoding|null|undefined} encoding
|
|
232
235
|
* @param {object|null|undefined} headers
|
|
233
236
|
* @returns {object}
|
|
234
237
|
*/
|
|
235
|
-
function createRequestHeaders(host, secure, body,
|
|
238
|
+
function createRequestHeaders(host, secure, body, cookies, encoding, headers) {
|
|
236
239
|
if (host != null && typeof host !== 'string')
|
|
237
240
|
throw new Errorf(
|
|
238
241
|
'The parameter "host" of "createRequestHeaders" ' +
|
|
239
|
-
'a non-empty String, but %v given.',
|
|
242
|
+
'a non-empty String, but %v was given.',
|
|
240
243
|
host,
|
|
241
244
|
);
|
|
242
245
|
host = host || 'localhost';
|
|
243
246
|
if (secure != null && typeof secure !== 'boolean')
|
|
244
247
|
throw new Errorf(
|
|
245
248
|
'The parameter "secure" of "createRequestHeaders" ' +
|
|
246
|
-
'should be a String, but %v given.',
|
|
249
|
+
'should be a String, but %v was given.',
|
|
247
250
|
secure,
|
|
248
251
|
);
|
|
249
252
|
secure = Boolean(secure);
|
|
250
253
|
if (
|
|
251
|
-
(
|
|
252
|
-
typeof
|
|
253
|
-
typeof
|
|
254
|
-
Array.isArray(
|
|
254
|
+
(cookies != null &&
|
|
255
|
+
typeof cookies !== 'object' &&
|
|
256
|
+
typeof cookies !== 'string') ||
|
|
257
|
+
Array.isArray(cookies)
|
|
255
258
|
) {
|
|
256
259
|
throw new Errorf(
|
|
257
|
-
'The parameter "
|
|
258
|
-
'should be a String or Object, but %v given.',
|
|
259
|
-
|
|
260
|
+
'The parameter "cookies" of "createRequestHeaders" ' +
|
|
261
|
+
'should be a String or Object, but %v was given.',
|
|
262
|
+
cookies,
|
|
260
263
|
);
|
|
261
264
|
}
|
|
262
265
|
if (
|
|
@@ -265,7 +268,7 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
|
|
|
265
268
|
) {
|
|
266
269
|
throw new Errorf(
|
|
267
270
|
'The parameter "headers" of "createRequestHeaders" ' +
|
|
268
|
-
'should be an Object, but %v given.',
|
|
271
|
+
'should be an Object, but %v was given.',
|
|
269
272
|
headers,
|
|
270
273
|
);
|
|
271
274
|
}
|
|
@@ -273,7 +276,7 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
|
|
|
273
276
|
if (encoding != null && typeof encoding !== 'string')
|
|
274
277
|
throw new Errorf(
|
|
275
278
|
'The parameter "encoding" of "createRequestHeaders" ' +
|
|
276
|
-
'should be a String, but %v given.',
|
|
279
|
+
'should be a String, but %v was given.',
|
|
277
280
|
encoding,
|
|
278
281
|
);
|
|
279
282
|
encoding = encoding || 'utf-8';
|
|
@@ -282,13 +285,14 @@ function createRequestHeaders(host, secure, body, cookie, encoding, headers) {
|
|
|
282
285
|
if (secure) obj['x-forwarded-proto'] = 'https';
|
|
283
286
|
// формирование заголовка Cookie
|
|
284
287
|
// из строки или объекта
|
|
285
|
-
if (
|
|
286
|
-
if (typeof
|
|
288
|
+
if (cookies != null) {
|
|
289
|
+
if (typeof cookies === 'string') {
|
|
287
290
|
obj['cookie'] = obj['cookie'] ? obj['cookie'] : '';
|
|
288
|
-
obj['cookie'] += cookie;
|
|
289
|
-
} else if (typeof
|
|
291
|
+
obj['cookie'] += obj['cookie'] ? `; ${cookies}` : cookies;
|
|
292
|
+
} else if (typeof cookies === 'object') {
|
|
290
293
|
obj['cookie'] = obj['cookie'] ? obj['cookie'] : '';
|
|
291
|
-
|
|
294
|
+
const newCookies = createCookiesString(cookies);
|
|
295
|
+
obj['cookie'] += obj['cookie'] ? `; ${newCookies}` : newCookies;
|
|
292
296
|
}
|
|
293
297
|
}
|
|
294
298
|
// установка заголовка "content-type"
|