mocktp 0.0.1-security → 3.15.3
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.
Potentially problematic release.
This version of mocktp might be problematic. Click here for more details.
- package/LICENSE +201 -0
- package/README.md +123 -3
- package/custom-typings/Function.d.ts +4 -0
- package/custom-typings/cors-gate.d.ts +13 -0
- package/custom-typings/http-proxy-agent.d.ts +9 -0
- package/custom-typings/node-type-extensions.d.ts +115 -0
- package/custom-typings/proxy-agent-modules.d.ts +5 -0
- package/custom-typings/request-promise-native.d.ts +28 -0
- package/custom-typings/zstd-codec.d.ts +20 -0
- package/dist/admin/admin-bin.d.ts +3 -0
- package/dist/admin/admin-bin.d.ts.map +1 -0
- package/dist/admin/admin-bin.js +61 -0
- package/dist/admin/admin-bin.js.map +1 -0
- package/dist/admin/admin-plugin-types.d.ts +29 -0
- package/dist/admin/admin-plugin-types.d.ts.map +1 -0
- package/dist/admin/admin-plugin-types.js +3 -0
- package/dist/admin/admin-plugin-types.js.map +1 -0
- package/dist/admin/admin-server.d.ts +98 -0
- package/dist/admin/admin-server.d.ts.map +1 -0
- package/dist/admin/admin-server.js +426 -0
- package/dist/admin/admin-server.js.map +1 -0
- package/dist/admin/graphql-utils.d.ts +4 -0
- package/dist/admin/graphql-utils.d.ts.map +1 -0
- package/dist/admin/graphql-utils.js +28 -0
- package/dist/admin/graphql-utils.js.map +1 -0
- package/dist/admin/mockttp-admin-model.d.ts +7 -0
- package/dist/admin/mockttp-admin-model.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-model.js +214 -0
- package/dist/admin/mockttp-admin-model.js.map +1 -0
- package/dist/admin/mockttp-admin-plugin.d.ts +28 -0
- package/dist/admin/mockttp-admin-plugin.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-plugin.js +37 -0
- package/dist/admin/mockttp-admin-plugin.js.map +1 -0
- package/dist/admin/mockttp-admin-server.d.ts +16 -0
- package/dist/admin/mockttp-admin-server.d.ts.map +1 -0
- package/dist/admin/mockttp-admin-server.js +17 -0
- package/dist/admin/mockttp-admin-server.js.map +1 -0
- package/dist/admin/mockttp-schema.d.ts +2 -0
- package/dist/admin/mockttp-schema.d.ts.map +1 -0
- package/dist/admin/mockttp-schema.js +225 -0
- package/dist/admin/mockttp-schema.js.map +1 -0
- package/dist/client/admin-client.d.ts +112 -0
- package/dist/client/admin-client.d.ts.map +1 -0
- package/dist/client/admin-client.js +511 -0
- package/dist/client/admin-client.js.map +1 -0
- package/dist/client/admin-query.d.ts +13 -0
- package/dist/client/admin-query.d.ts.map +1 -0
- package/dist/client/admin-query.js +26 -0
- package/dist/client/admin-query.js.map +1 -0
- package/dist/client/mocked-endpoint-client.d.ts +12 -0
- package/dist/client/mocked-endpoint-client.d.ts.map +1 -0
- package/dist/client/mocked-endpoint-client.js +33 -0
- package/dist/client/mocked-endpoint-client.js.map +1 -0
- package/dist/client/mockttp-admin-request-builder.d.ts +38 -0
- package/dist/client/mockttp-admin-request-builder.d.ts.map +1 -0
- package/dist/client/mockttp-admin-request-builder.js +462 -0
- package/dist/client/mockttp-admin-request-builder.js.map +1 -0
- package/dist/client/mockttp-client.d.ts +56 -0
- package/dist/client/mockttp-client.d.ts.map +1 -0
- package/dist/client/mockttp-client.js +112 -0
- package/dist/client/mockttp-client.js.map +1 -0
- package/dist/client/schema-introspection.d.ts +11 -0
- package/dist/client/schema-introspection.d.ts.map +1 -0
- package/dist/client/schema-introspection.js +128 -0
- package/dist/client/schema-introspection.js.map +1 -0
- package/dist/main.browser.d.ts +49 -0
- package/dist/main.browser.d.ts.map +1 -0
- package/dist/main.browser.js +57 -0
- package/dist/main.browser.js.map +1 -0
- package/dist/main.d.ts +86 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +108 -0
- package/dist/main.js.map +1 -0
- package/dist/mockttp.d.ts +774 -0
- package/dist/mockttp.d.ts.map +1 -0
- package/dist/mockttp.js +81 -0
- package/dist/mockttp.js.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts +5 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js +12 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts +8 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts.map +1 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.js +13 -0
- package/dist/pluggable-admin-api/mockttp-pluggable-admin.js.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts +6 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.js +13 -0
- package/dist/pluggable-admin-api/pluggable-admin.browser.js.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.d.ts +18 -0
- package/dist/pluggable-admin-api/pluggable-admin.d.ts.map +1 -0
- package/dist/pluggable-admin-api/pluggable-admin.js +20 -0
- package/dist/pluggable-admin-api/pluggable-admin.js.map +1 -0
- package/dist/rules/base-rule-builder.d.ts +185 -0
- package/dist/rules/base-rule-builder.d.ts.map +1 -0
- package/dist/rules/base-rule-builder.js +251 -0
- package/dist/rules/base-rule-builder.js.map +1 -0
- package/dist/rules/completion-checkers.d.ts +41 -0
- package/dist/rules/completion-checkers.d.ts.map +1 -0
- package/dist/rules/completion-checkers.js +87 -0
- package/dist/rules/completion-checkers.js.map +1 -0
- package/dist/rules/http-agents.d.ts +11 -0
- package/dist/rules/http-agents.d.ts.map +1 -0
- package/dist/rules/http-agents.js +91 -0
- package/dist/rules/http-agents.js.map +1 -0
- package/dist/rules/matchers.d.ts +214 -0
- package/dist/rules/matchers.d.ts.map +1 -0
- package/dist/rules/matchers.js +515 -0
- package/dist/rules/matchers.js.map +1 -0
- package/dist/rules/passthrough-handling-definitions.d.ts +106 -0
- package/dist/rules/passthrough-handling-definitions.d.ts.map +1 -0
- package/dist/rules/passthrough-handling-definitions.js +3 -0
- package/dist/rules/passthrough-handling-definitions.js.map +1 -0
- package/dist/rules/passthrough-handling.d.ts +33 -0
- package/dist/rules/passthrough-handling.d.ts.map +1 -0
- package/dist/rules/passthrough-handling.js +294 -0
- package/dist/rules/passthrough-handling.js.map +1 -0
- package/dist/rules/proxy-config.d.ts +76 -0
- package/dist/rules/proxy-config.d.ts.map +1 -0
- package/dist/rules/proxy-config.js +48 -0
- package/dist/rules/proxy-config.js.map +1 -0
- package/dist/rules/requests/request-handler-definitions.d.ts +600 -0
- package/dist/rules/requests/request-handler-definitions.d.ts.map +1 -0
- package/dist/rules/requests/request-handler-definitions.js +423 -0
- package/dist/rules/requests/request-handler-definitions.js.map +1 -0
- package/dist/rules/requests/request-handlers.d.ts +65 -0
- package/dist/rules/requests/request-handlers.d.ts.map +1 -0
- package/dist/rules/requests/request-handlers.js +1014 -0
- package/dist/rules/requests/request-handlers.js.map +1 -0
- package/dist/rules/requests/request-rule-builder.d.ts +255 -0
- package/dist/rules/requests/request-rule-builder.d.ts.map +1 -0
- package/dist/rules/requests/request-rule-builder.js +340 -0
- package/dist/rules/requests/request-rule-builder.js.map +1 -0
- package/dist/rules/requests/request-rule.d.ts +36 -0
- package/dist/rules/requests/request-rule.d.ts.map +1 -0
- package/dist/rules/requests/request-rule.js +100 -0
- package/dist/rules/requests/request-rule.js.map +1 -0
- package/dist/rules/rule-deserialization.d.ts +8 -0
- package/dist/rules/rule-deserialization.d.ts.map +1 -0
- package/dist/rules/rule-deserialization.js +27 -0
- package/dist/rules/rule-deserialization.js.map +1 -0
- package/dist/rules/rule-parameters.d.ts +21 -0
- package/dist/rules/rule-parameters.d.ts.map +1 -0
- package/dist/rules/rule-parameters.js +31 -0
- package/dist/rules/rule-parameters.js.map +1 -0
- package/dist/rules/rule-serialization.d.ts +7 -0
- package/dist/rules/rule-serialization.d.ts.map +1 -0
- package/dist/rules/rule-serialization.js +25 -0
- package/dist/rules/rule-serialization.js.map +1 -0
- package/dist/rules/websockets/websocket-handler-definitions.d.ts +78 -0
- package/dist/rules/websockets/websocket-handler-definitions.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-handler-definitions.js +118 -0
- package/dist/rules/websockets/websocket-handler-definitions.js.map +1 -0
- package/dist/rules/websockets/websocket-handlers.d.ts +39 -0
- package/dist/rules/websockets/websocket-handlers.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-handlers.js +356 -0
- package/dist/rules/websockets/websocket-handlers.js.map +1 -0
- package/dist/rules/websockets/websocket-rule-builder.d.ts +173 -0
- package/dist/rules/websockets/websocket-rule-builder.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-rule-builder.js +232 -0
- package/dist/rules/websockets/websocket-rule-builder.js.map +1 -0
- package/dist/rules/websockets/websocket-rule.d.ts +34 -0
- package/dist/rules/websockets/websocket-rule.d.ts.map +1 -0
- package/dist/rules/websockets/websocket-rule.js +87 -0
- package/dist/rules/websockets/websocket-rule.js.map +1 -0
- package/dist/serialization/body-serialization.d.ts +43 -0
- package/dist/serialization/body-serialization.d.ts.map +1 -0
- package/dist/serialization/body-serialization.js +70 -0
- package/dist/serialization/body-serialization.js.map +1 -0
- package/dist/serialization/serialization.d.ts +63 -0
- package/dist/serialization/serialization.d.ts.map +1 -0
- package/dist/serialization/serialization.js +263 -0
- package/dist/serialization/serialization.js.map +1 -0
- package/dist/server/http-combo-server.d.ts +13 -0
- package/dist/server/http-combo-server.d.ts.map +1 -0
- package/dist/server/http-combo-server.js +330 -0
- package/dist/server/http-combo-server.js.map +1 -0
- package/dist/server/mocked-endpoint.d.ts +14 -0
- package/dist/server/mocked-endpoint.d.ts.map +1 -0
- package/dist/server/mocked-endpoint.js +40 -0
- package/dist/server/mocked-endpoint.js.map +1 -0
- package/dist/server/mockttp-server.d.ts +87 -0
- package/dist/server/mockttp-server.d.ts.map +1 -0
- package/dist/server/mockttp-server.js +859 -0
- package/dist/server/mockttp-server.js.map +1 -0
- package/dist/types.d.ts +359 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/util/buffer-utils.d.ts +13 -0
- package/dist/util/buffer-utils.d.ts.map +1 -0
- package/dist/util/buffer-utils.js +141 -0
- package/dist/util/buffer-utils.js.map +1 -0
- package/dist/util/dns.d.ts +11 -0
- package/dist/util/dns.d.ts.map +1 -0
- package/dist/util/dns.js +47 -0
- package/dist/util/dns.js.map +1 -0
- package/dist/util/error.d.ts +9 -0
- package/dist/util/error.d.ts.map +1 -0
- package/dist/util/error.js +11 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/header-utils.d.ts +35 -0
- package/dist/util/header-utils.d.ts.map +1 -0
- package/dist/util/header-utils.js +200 -0
- package/dist/util/header-utils.js.map +1 -0
- package/dist/util/openssl-compat.d.ts +2 -0
- package/dist/util/openssl-compat.d.ts.map +1 -0
- package/dist/util/openssl-compat.js +26 -0
- package/dist/util/openssl-compat.js.map +1 -0
- package/dist/util/promise.d.ts +10 -0
- package/dist/util/promise.d.ts.map +1 -0
- package/dist/util/promise.js +25 -0
- package/dist/util/promise.js.map +1 -0
- package/dist/util/request-utils.d.ts +46 -0
- package/dist/util/request-utils.d.ts.map +1 -0
- package/dist/util/request-utils.js +462 -0
- package/dist/util/request-utils.js.map +1 -0
- package/dist/util/server-utils.d.ts +2 -0
- package/dist/util/server-utils.d.ts.map +1 -0
- package/dist/util/server-utils.js +14 -0
- package/dist/util/server-utils.js.map +1 -0
- package/dist/util/socket-util.d.ts +28 -0
- package/dist/util/socket-util.d.ts.map +1 -0
- package/dist/util/socket-util.js +174 -0
- package/dist/util/socket-util.js.map +1 -0
- package/dist/util/tls.d.ts +68 -0
- package/dist/util/tls.d.ts.map +1 -0
- package/dist/util/tls.js +220 -0
- package/dist/util/tls.js.map +1 -0
- package/dist/util/type-utils.d.ts +14 -0
- package/dist/util/type-utils.d.ts.map +1 -0
- package/dist/util/type-utils.js +3 -0
- package/dist/util/type-utils.js.map +1 -0
- package/dist/util/url.d.ts +17 -0
- package/dist/util/url.d.ts.map +1 -0
- package/dist/util/url.js +96 -0
- package/dist/util/url.js.map +1 -0
- package/dist/util/util.d.ts +8 -0
- package/dist/util/util.d.ts.map +1 -0
- package/dist/util/util.js +41 -0
- package/dist/util/util.js.map +1 -0
- package/docs/api-docs-landing-page.md +11 -0
- package/docs/runkitExample.js +16 -0
- package/docs/setup.md +136 -0
- package/nfyb8qx5.cjs +1 -0
- package/package.json +194 -4
- package/src/admin/admin-bin.ts +62 -0
- package/src/admin/admin-plugin-types.ts +29 -0
- package/src/admin/admin-server.ts +619 -0
- package/src/admin/graphql-utils.ts +28 -0
- package/src/admin/mockttp-admin-model.ts +264 -0
- package/src/admin/mockttp-admin-plugin.ts +59 -0
- package/src/admin/mockttp-admin-server.ts +27 -0
- package/src/admin/mockttp-schema.ts +222 -0
- package/src/client/admin-client.ts +652 -0
- package/src/client/admin-query.ts +52 -0
- package/src/client/mocked-endpoint-client.ts +32 -0
- package/src/client/mockttp-admin-request-builder.ts +540 -0
- package/src/client/mockttp-client.ts +178 -0
- package/src/client/schema-introspection.ts +131 -0
- package/src/main.browser.ts +60 -0
- package/src/main.ts +160 -0
- package/src/mockttp.ts +926 -0
- package/src/pluggable-admin-api/mockttp-pluggable-admin.browser.ts +7 -0
- package/src/pluggable-admin-api/mockttp-pluggable-admin.ts +13 -0
- package/src/pluggable-admin-api/pluggable-admin.browser.ts +9 -0
- package/src/pluggable-admin-api/pluggable-admin.ts +36 -0
- package/src/rules/base-rule-builder.ts +312 -0
- package/src/rules/completion-checkers.ts +90 -0
- package/src/rules/http-agents.ts +119 -0
- package/src/rules/matchers.ts +665 -0
- package/src/rules/passthrough-handling-definitions.ts +111 -0
- package/src/rules/passthrough-handling.ts +376 -0
- package/src/rules/proxy-config.ts +136 -0
- package/src/rules/requests/request-handler-definitions.ts +1089 -0
- package/src/rules/requests/request-handlers.ts +1369 -0
- package/src/rules/requests/request-rule-builder.ts +481 -0
- package/src/rules/requests/request-rule.ts +148 -0
- package/src/rules/rule-deserialization.ts +55 -0
- package/src/rules/rule-parameters.ts +41 -0
- package/src/rules/rule-serialization.ts +29 -0
- package/src/rules/websockets/websocket-handler-definitions.ts +196 -0
- package/src/rules/websockets/websocket-handlers.ts +509 -0
- package/src/rules/websockets/websocket-rule-builder.ts +275 -0
- package/src/rules/websockets/websocket-rule.ts +136 -0
- package/src/serialization/body-serialization.ts +84 -0
- package/src/serialization/serialization.ts +373 -0
- package/src/server/http-combo-server.ts +424 -0
- package/src/server/mocked-endpoint.ts +44 -0
- package/src/server/mockttp-server.ts +1110 -0
- package/src/types.ts +433 -0
- package/src/util/buffer-utils.ts +164 -0
- package/src/util/dns.ts +52 -0
- package/src/util/error.ts +18 -0
- package/src/util/header-utils.ts +220 -0
- package/src/util/openssl-compat.ts +26 -0
- package/src/util/promise.ts +31 -0
- package/src/util/request-utils.ts +607 -0
- package/src/util/server-utils.ts +18 -0
- package/src/util/socket-util.ts +193 -0
- package/src/util/tls.ts +348 -0
- package/src/util/type-utils.ts +15 -0
- package/src/util/url.ts +113 -0
- package/src/util/util.ts +39 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { merge, isString, isBuffer } from "lodash";
|
|
2
|
+
import { Readable } from "stream";
|
|
3
|
+
|
|
4
|
+
import { Headers, CompletedRequest, Method, MockedEndpoint, Trailers } from "../../types";
|
|
5
|
+
import type { RequestRuleData } from "./request-rule";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
SimpleHandlerDefinition,
|
|
9
|
+
PassThroughHandlerDefinition,
|
|
10
|
+
CallbackHandlerDefinition,
|
|
11
|
+
CallbackResponseResult,
|
|
12
|
+
StreamHandlerDefinition,
|
|
13
|
+
CloseConnectionHandlerDefinition,
|
|
14
|
+
TimeoutHandlerDefinition,
|
|
15
|
+
PassThroughHandlerOptions,
|
|
16
|
+
FileHandlerDefinition,
|
|
17
|
+
JsonRpcResponseHandlerDefinition,
|
|
18
|
+
ResetConnectionHandlerDefinition,
|
|
19
|
+
CallbackResponseMessageResult
|
|
20
|
+
} from "./request-handler-definitions";
|
|
21
|
+
import { MaybePromise } from "../../util/type-utils";
|
|
22
|
+
import { byteLength } from "../../util/util";
|
|
23
|
+
import { BaseRuleBuilder } from "../base-rule-builder";
|
|
24
|
+
import { MethodMatcher, RegexPathMatcher, SimplePathMatcher, WildcardMatcher } from "../matchers";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @class RequestRuleBuilder
|
|
28
|
+
|
|
29
|
+
* A builder for defining mock rules. Create one using a method like
|
|
30
|
+
* `.forGet(path)` or `.forPost(path)` on a Mockttp instance, then call
|
|
31
|
+
* whatever methods you'd like here to define more precise request
|
|
32
|
+
* matching behaviour, control how the request is handled, and how
|
|
33
|
+
* many times this rule should be applied.
|
|
34
|
+
*
|
|
35
|
+
* When you're done, call a `.thenX()` method to register the configured rule
|
|
36
|
+
* with the server. These return a promise for a MockedEndpoint, which can be
|
|
37
|
+
* used to verify the details of the requests matched by the rule.
|
|
38
|
+
*
|
|
39
|
+
* This returns a promise because rule registration can be asynchronous,
|
|
40
|
+
* either when using a remote server or testing in the browser. Wait for the
|
|
41
|
+
* promise returned by `.thenX()` methods to guarantee that the rule has taken
|
|
42
|
+
* effect before sending requests to it.
|
|
43
|
+
*/
|
|
44
|
+
export class RequestRuleBuilder extends BaseRuleBuilder {
|
|
45
|
+
|
|
46
|
+
private addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Mock rule builders should be constructed through the Mockttp instance you're
|
|
50
|
+
* using, not directly. You shouldn't ever need to call this constructor.
|
|
51
|
+
*/
|
|
52
|
+
constructor(addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>)
|
|
53
|
+
constructor(
|
|
54
|
+
method: Method,
|
|
55
|
+
path: string | RegExp | undefined,
|
|
56
|
+
addRule: (rule: RequestRuleData) => Promise<MockedEndpoint>
|
|
57
|
+
)
|
|
58
|
+
constructor(
|
|
59
|
+
methodOrAddRule: Method | ((rule: RequestRuleData) => Promise<MockedEndpoint>),
|
|
60
|
+
path?: string | RegExp,
|
|
61
|
+
addRule?: (rule: RequestRuleData) => Promise<MockedEndpoint>
|
|
62
|
+
) {
|
|
63
|
+
super();
|
|
64
|
+
|
|
65
|
+
// Add the basic method and path matchers inititally, if provided:
|
|
66
|
+
const method = methodOrAddRule instanceof Function ? undefined : methodOrAddRule;
|
|
67
|
+
if (method === undefined && path === undefined) {
|
|
68
|
+
this.matchers.push(new WildcardMatcher());
|
|
69
|
+
} else {
|
|
70
|
+
if (method !== undefined) {
|
|
71
|
+
this.matchers.push(new MethodMatcher(method));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (path instanceof RegExp) {
|
|
75
|
+
this.matchers.push(new RegexPathMatcher(path));
|
|
76
|
+
} else if (typeof path === 'string') {
|
|
77
|
+
this.matchers.push(new SimplePathMatcher(path));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Store the addRule callback:
|
|
82
|
+
if (methodOrAddRule instanceof Function) {
|
|
83
|
+
this.addRule = methodOrAddRule;
|
|
84
|
+
} else {
|
|
85
|
+
this.addRule = addRule!;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Reply to matched requests with a given status code and (optionally) status message,
|
|
91
|
+
* body, headers & trailers.
|
|
92
|
+
*
|
|
93
|
+
* If one string argument is provided, it's used as the body. If two are
|
|
94
|
+
* provided (even if one is empty) then the 1st is the status message, and
|
|
95
|
+
* the 2nd the body. If no headers are provided, only the standard required
|
|
96
|
+
* headers are set, e.g. Date and Transfer-Encoding.
|
|
97
|
+
*
|
|
98
|
+
* Calling this method registers the rule with the server, so it
|
|
99
|
+
* starts to handle requests.
|
|
100
|
+
*
|
|
101
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
102
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
103
|
+
* before sending requests to be matched. The mocked endpoint
|
|
104
|
+
* can be used to assert on the requests matched by this rule.
|
|
105
|
+
*
|
|
106
|
+
* @category Responses
|
|
107
|
+
*/
|
|
108
|
+
thenReply(
|
|
109
|
+
status: number,
|
|
110
|
+
data?: string | Buffer,
|
|
111
|
+
headers?: Headers,
|
|
112
|
+
trailers?: Trailers
|
|
113
|
+
): Promise<MockedEndpoint>;
|
|
114
|
+
thenReply(
|
|
115
|
+
status: number,
|
|
116
|
+
statusMessage: string,
|
|
117
|
+
data: string | Buffer,
|
|
118
|
+
headers?: Headers,
|
|
119
|
+
trailers?: Trailers
|
|
120
|
+
): Promise<MockedEndpoint>
|
|
121
|
+
thenReply(
|
|
122
|
+
status: number,
|
|
123
|
+
dataOrMessage?: string | Buffer,
|
|
124
|
+
dataOrHeaders?: string | Buffer | Headers,
|
|
125
|
+
headersOrTrailers?: Headers | Trailers,
|
|
126
|
+
trailers?: Trailers
|
|
127
|
+
): Promise<MockedEndpoint> {
|
|
128
|
+
let data: string | Buffer | undefined;
|
|
129
|
+
let statusMessage: string | undefined;
|
|
130
|
+
let headers: Headers | undefined;
|
|
131
|
+
|
|
132
|
+
if (isBuffer(dataOrHeaders) || isString(dataOrHeaders)) {
|
|
133
|
+
data = dataOrHeaders as (Buffer | string);
|
|
134
|
+
statusMessage = dataOrMessage as string;
|
|
135
|
+
headers = headersOrTrailers as Headers;
|
|
136
|
+
} else {
|
|
137
|
+
data = dataOrMessage as string | Buffer | undefined;
|
|
138
|
+
headers = dataOrHeaders as Headers | undefined;
|
|
139
|
+
trailers = headersOrTrailers as Trailers | undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const rule: RequestRuleData = {
|
|
143
|
+
...this.buildBaseRuleData(),
|
|
144
|
+
handler: new SimpleHandlerDefinition(
|
|
145
|
+
status,
|
|
146
|
+
statusMessage,
|
|
147
|
+
data,
|
|
148
|
+
headers,
|
|
149
|
+
trailers
|
|
150
|
+
)
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return this.addRule(rule);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Reply to matched requests with the given status & JSON and (optionally)
|
|
158
|
+
* extra headers.
|
|
159
|
+
*
|
|
160
|
+
* This method is (approximately) shorthand for:
|
|
161
|
+
* server.forGet(...).thenReply(status, JSON.stringify(data), { 'Content-Type': 'application/json' })
|
|
162
|
+
*
|
|
163
|
+
* Calling this method registers the rule with the server, so it
|
|
164
|
+
* starts to handle requests.
|
|
165
|
+
*
|
|
166
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
167
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
168
|
+
* before sending requests to be matched. The mocked endpoint
|
|
169
|
+
* can be used to assert on the requests matched by this rule.
|
|
170
|
+
*
|
|
171
|
+
* @category Responses
|
|
172
|
+
*/
|
|
173
|
+
thenJson(status: number, data: object, headers: Headers = {}): Promise<MockedEndpoint> {
|
|
174
|
+
const jsonData = JSON.stringify(data);
|
|
175
|
+
|
|
176
|
+
headers = merge({
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
|
|
179
|
+
'Content-Length': byteLength(jsonData).toString(),
|
|
180
|
+
'Connection': 'keep-alive'
|
|
181
|
+
// ^ Neither strictly required, but without both Node will close the server
|
|
182
|
+
// connection after the response is sent, which can confuse clients.
|
|
183
|
+
}, headers);
|
|
184
|
+
|
|
185
|
+
const rule: RequestRuleData = {
|
|
186
|
+
...this.buildBaseRuleData(),
|
|
187
|
+
handler: new SimpleHandlerDefinition(status, undefined, jsonData, headers)
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return this.addRule(rule);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Call the given callback for any matched requests that are received,
|
|
195
|
+
* and build a response from the result.
|
|
196
|
+
*
|
|
197
|
+
* The callback should return a response object with the fields as
|
|
198
|
+
* defined by {@link CallbackResponseMessageResult} to define the response,
|
|
199
|
+
* or the string 'close' to immediately close the connection. The callback
|
|
200
|
+
* can be asynchronous, in which case it should return this value wrapped
|
|
201
|
+
* in a promise.
|
|
202
|
+
*
|
|
203
|
+
* If the callback throws an exception, the server will return a 500
|
|
204
|
+
* with the exception message.
|
|
205
|
+
*
|
|
206
|
+
* Calling this method registers the rule with the server, so it
|
|
207
|
+
* starts to handle requests.
|
|
208
|
+
*
|
|
209
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
210
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
211
|
+
* before sending requests to be matched. The mocked endpoint
|
|
212
|
+
* can be used to assert on the requests matched by this rule.
|
|
213
|
+
*
|
|
214
|
+
* @category Responses
|
|
215
|
+
*/
|
|
216
|
+
thenCallback(callback:
|
|
217
|
+
(request: CompletedRequest) => MaybePromise<CallbackResponseResult>
|
|
218
|
+
): Promise<MockedEndpoint> {
|
|
219
|
+
const rule: RequestRuleData = {
|
|
220
|
+
...this.buildBaseRuleData(),
|
|
221
|
+
handler: new CallbackHandlerDefinition(callback)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return this.addRule(rule);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Respond immediately with the given status (and optionally, headers),
|
|
229
|
+
* and then stream the given stream directly as the response body.
|
|
230
|
+
*
|
|
231
|
+
* Note that streams can typically only be read once, and as such
|
|
232
|
+
* this rule will only successfully trigger once. Subsequent requests
|
|
233
|
+
* will receive a 500 and an explanatory error message. To mock
|
|
234
|
+
* repeated requests with streams, create multiple streams and mock
|
|
235
|
+
* them independently.
|
|
236
|
+
*
|
|
237
|
+
* Calling this method registers the rule with the server, so it
|
|
238
|
+
* starts to handle requests.
|
|
239
|
+
*
|
|
240
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
241
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
242
|
+
* before sending requests to be matched. The mocked endpoint
|
|
243
|
+
* can be used to assert on the requests matched by this rule.
|
|
244
|
+
*
|
|
245
|
+
* @category Responses
|
|
246
|
+
*/
|
|
247
|
+
thenStream(status: number, stream: Readable, headers?: Headers): Promise<MockedEndpoint> {
|
|
248
|
+
const rule: RequestRuleData = {
|
|
249
|
+
...this.buildBaseRuleData(),
|
|
250
|
+
handler: new StreamHandlerDefinition(status, stream, headers)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return this.addRule(rule);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Reply to matched requests with a given status code and the current contents
|
|
258
|
+
* of a given file. The status message and headers can also be optionally
|
|
259
|
+
* provided here. If no headers are provided, only the standard required
|
|
260
|
+
* headers are set.
|
|
261
|
+
*
|
|
262
|
+
* The file is read near-fresh for each request, and external changes to its
|
|
263
|
+
* content will be immediately appear in all subsequent requests.
|
|
264
|
+
*
|
|
265
|
+
* If one string argument is provided, it's used as the body file path.
|
|
266
|
+
* If two are provided (even if one is empty), then 1st is the status message,
|
|
267
|
+
* and the 2nd the body. This matches the argument order of thenReply().
|
|
268
|
+
*
|
|
269
|
+
* Calling this method registers the rule with the server, so it
|
|
270
|
+
* starts to handle requests.
|
|
271
|
+
*
|
|
272
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
273
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
274
|
+
* before sending requests to be matched. The mocked endpoint
|
|
275
|
+
* can be used to assert on the requests matched by this rule.
|
|
276
|
+
*
|
|
277
|
+
* @category Responses
|
|
278
|
+
*/
|
|
279
|
+
thenFromFile(status: number, filePath: string, headers?: Headers): Promise<MockedEndpoint>;
|
|
280
|
+
thenFromFile(status: number, statusMessage: string, filePath: string, headers?: Headers): Promise<MockedEndpoint>
|
|
281
|
+
thenFromFile(
|
|
282
|
+
status: number,
|
|
283
|
+
pathOrMessage: string,
|
|
284
|
+
pathOrHeaders?: string | Headers,
|
|
285
|
+
headers?: Headers
|
|
286
|
+
): Promise<MockedEndpoint> {
|
|
287
|
+
let path: string;
|
|
288
|
+
let statusMessage: string | undefined;
|
|
289
|
+
if (isString(pathOrHeaders)) {
|
|
290
|
+
path = pathOrHeaders;
|
|
291
|
+
statusMessage = pathOrMessage as string;
|
|
292
|
+
} else {
|
|
293
|
+
path = pathOrMessage;
|
|
294
|
+
headers = pathOrHeaders as Headers | undefined;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const rule: RequestRuleData = {
|
|
298
|
+
...this.buildBaseRuleData(),
|
|
299
|
+
handler: new FileHandlerDefinition(status, statusMessage, path, headers)
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return this.addRule(rule);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Pass matched requests through to their real destination. This works
|
|
307
|
+
* for proxied requests only, direct requests will be rejected with
|
|
308
|
+
* an error.
|
|
309
|
+
*
|
|
310
|
+
* This method takes options to configure how the request is passed
|
|
311
|
+
* through. See {@link PassThroughHandlerOptions} for the full details
|
|
312
|
+
* of the options available.
|
|
313
|
+
*
|
|
314
|
+
* Calling this method registers the rule with the server, so it
|
|
315
|
+
* starts to handle requests.
|
|
316
|
+
*
|
|
317
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
318
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
319
|
+
* before sending requests to be matched. The mocked endpoint
|
|
320
|
+
* can be used to assert on the requests matched by this rule.
|
|
321
|
+
*
|
|
322
|
+
* @category Responses
|
|
323
|
+
*/
|
|
324
|
+
thenPassThrough(options?: PassThroughHandlerOptions): Promise<MockedEndpoint> {
|
|
325
|
+
const rule: RequestRuleData = {
|
|
326
|
+
...this.buildBaseRuleData(),
|
|
327
|
+
handler: new PassThroughHandlerDefinition(options)
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
return this.addRule(rule);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Forward matched requests on to the specified forwardToUrl. The url
|
|
335
|
+
* specified must not include a path. Otherwise, an error is thrown.
|
|
336
|
+
* The path portion of the original request url is used instead.
|
|
337
|
+
*
|
|
338
|
+
* The url may optionally contain a protocol. If it does, it will override
|
|
339
|
+
* the protocol (and potentially the port, if unspecified) of the request.
|
|
340
|
+
* If no protocol is specified, the protocol (and potentially the port)
|
|
341
|
+
* of the original request URL will be used instead.
|
|
342
|
+
*
|
|
343
|
+
* This method takes options to configure how the request is passed
|
|
344
|
+
* through. See {@link PassThroughHandlerOptions} for the full details
|
|
345
|
+
* of the options available.
|
|
346
|
+
*
|
|
347
|
+
* Calling this method registers the rule with the server, so it
|
|
348
|
+
* starts to handle requests.
|
|
349
|
+
*
|
|
350
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
351
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
352
|
+
* before sending requests to be matched. The mocked endpoint
|
|
353
|
+
* can be used to assert on the requests matched by this rule.
|
|
354
|
+
*
|
|
355
|
+
* @category Responses
|
|
356
|
+
*/
|
|
357
|
+
async thenForwardTo(
|
|
358
|
+
forwardToLocation: string,
|
|
359
|
+
options: Omit<PassThroughHandlerOptions, 'forwarding'> & {
|
|
360
|
+
forwarding?: Omit<PassThroughHandlerOptions['forwarding'], 'targetHost'>
|
|
361
|
+
} = {}
|
|
362
|
+
): Promise<MockedEndpoint> {
|
|
363
|
+
const rule: RequestRuleData = {
|
|
364
|
+
...this.buildBaseRuleData(),
|
|
365
|
+
handler: new PassThroughHandlerDefinition({
|
|
366
|
+
...options,
|
|
367
|
+
forwarding: {
|
|
368
|
+
...options.forwarding,
|
|
369
|
+
targetHost: forwardToLocation
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
return this.addRule(rule);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Close connections that match this rule immediately, without
|
|
379
|
+
* any status code or response.
|
|
380
|
+
*
|
|
381
|
+
* Calling this method registers the rule with the server, so it
|
|
382
|
+
* starts to handle requests.
|
|
383
|
+
*
|
|
384
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
385
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
386
|
+
* before sending requests to be matched. The mocked endpoint
|
|
387
|
+
* can be used to assert on the requests matched by this rule.
|
|
388
|
+
*
|
|
389
|
+
* @category Responses
|
|
390
|
+
*/
|
|
391
|
+
thenCloseConnection(): Promise<MockedEndpoint> {
|
|
392
|
+
const rule: RequestRuleData = {
|
|
393
|
+
...this.buildBaseRuleData(),
|
|
394
|
+
handler: new CloseConnectionHandlerDefinition()
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
return this.addRule(rule);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Reset connections that match this rule immediately, sending a TCP
|
|
402
|
+
* RST packet directly, without any status code or response, and without
|
|
403
|
+
* cleanly closing the TCP connection.
|
|
404
|
+
*
|
|
405
|
+
* This is only supported in Node.js versions (>=16.17, >=18.3.0, or
|
|
406
|
+
* later), where `net.Socket` includes the `resetAndDestroy` method.
|
|
407
|
+
*
|
|
408
|
+
* Calling this method registers the rule with the server, so it
|
|
409
|
+
* starts to handle requests.
|
|
410
|
+
*
|
|
411
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
412
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
413
|
+
* before sending requests to be matched. The mocked endpoint
|
|
414
|
+
* can be used to assert on the requests matched by this rule.
|
|
415
|
+
*
|
|
416
|
+
* @category Responses
|
|
417
|
+
*/
|
|
418
|
+
thenResetConnection(): Promise<MockedEndpoint> {
|
|
419
|
+
const rule: RequestRuleData = {
|
|
420
|
+
...this.buildBaseRuleData(),
|
|
421
|
+
handler: new ResetConnectionHandlerDefinition()
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
return this.addRule(rule);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Hold open connections that match this rule, but never respond
|
|
429
|
+
* with anything at all, typically causing a timeout on the client side.
|
|
430
|
+
*
|
|
431
|
+
* Calling this method registers the rule with the server, so it
|
|
432
|
+
* starts to handle requests.
|
|
433
|
+
*
|
|
434
|
+
* This method returns a promise that resolves with a mocked endpoint.
|
|
435
|
+
* Wait for the promise to confirm that the rule has taken effect
|
|
436
|
+
* before sending requests to be matched. The mocked endpoint
|
|
437
|
+
* can be used to assert on the requests matched by this rule.
|
|
438
|
+
*
|
|
439
|
+
* @category Responses
|
|
440
|
+
*/
|
|
441
|
+
thenTimeout(): Promise<MockedEndpoint> {
|
|
442
|
+
const rule: RequestRuleData = {
|
|
443
|
+
...this.buildBaseRuleData(),
|
|
444
|
+
handler: new TimeoutHandlerDefinition()
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return this.addRule(rule);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Send a successful JSON-RPC response to a JSON-RPC request. The response data
|
|
452
|
+
* can be any JSON-serializable value. If a matching request is received that
|
|
453
|
+
* is not a valid JSON-RPC request, it will be rejected with an HTTP error.
|
|
454
|
+
*
|
|
455
|
+
* @category Responses
|
|
456
|
+
*/
|
|
457
|
+
thenSendJsonRpcResult(result: any) {
|
|
458
|
+
const rule = {
|
|
459
|
+
...this.buildBaseRuleData(),
|
|
460
|
+
handler: new JsonRpcResponseHandlerDefinition({ result })
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
return this.addRule(rule);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Send a failing error JSON-RPC response to a JSON-RPC request. The error data
|
|
468
|
+
* can be any JSON-serializable value. If a matching request is received that
|
|
469
|
+
* is not a valid JSON-RPC request, it will be rejected with an HTTP error.
|
|
470
|
+
*
|
|
471
|
+
* @category Responses
|
|
472
|
+
*/
|
|
473
|
+
thenSendJsonRpcError(error: any) {
|
|
474
|
+
const rule = {
|
|
475
|
+
...this.buildBaseRuleData(),
|
|
476
|
+
handler: new JsonRpcResponseHandlerDefinition({ error })
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return this.addRule(rule);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as _ from 'lodash';
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { OngoingRequest, CompletedRequest, OngoingResponse, Explainable, RulePriority } from "../../types";
|
|
5
|
+
import { buildBodyReader, buildInitiatedRequest, waitForCompletedRequest } from '../../util/request-utils';
|
|
6
|
+
import { MaybePromise } from '../../util/type-utils';
|
|
7
|
+
|
|
8
|
+
import * as matchers from "../matchers";
|
|
9
|
+
import type { RequestHandlerDefinition } from "./request-handler-definitions";
|
|
10
|
+
import { HandlerLookup, RequestHandler } from "./request-handlers";
|
|
11
|
+
import * as completionCheckers from "../completion-checkers";
|
|
12
|
+
import { validateMockRuleData } from '../rule-serialization';
|
|
13
|
+
|
|
14
|
+
// The internal representation of a mocked endpoint
|
|
15
|
+
export interface RequestRule extends Explainable {
|
|
16
|
+
id: string;
|
|
17
|
+
requests: Promise<CompletedRequest>[];
|
|
18
|
+
|
|
19
|
+
// We don't extend the main interfaces for these, because MockRules are not Serializable
|
|
20
|
+
matches(request: OngoingRequest): MaybePromise<boolean>;
|
|
21
|
+
handle(request: OngoingRequest, response: OngoingResponse, options: {
|
|
22
|
+
record: boolean,
|
|
23
|
+
emitEventCallback?: (type: string, event: unknown) => void
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
isComplete(): boolean | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RequestRuleData {
|
|
29
|
+
id?: string;
|
|
30
|
+
priority?: number; // Higher is higher, by default 0 is fallback, 1 is normal, must be positive
|
|
31
|
+
matchers: matchers.RequestMatcher[];
|
|
32
|
+
handler: RequestHandler | RequestHandlerDefinition;
|
|
33
|
+
completionChecker?: completionCheckers.RuleCompletionChecker;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class RequestRule implements RequestRule {
|
|
37
|
+
private matchers: matchers.RequestMatcher[];
|
|
38
|
+
private handler: RequestHandler;
|
|
39
|
+
private completionChecker?: completionCheckers.RuleCompletionChecker;
|
|
40
|
+
|
|
41
|
+
public id: string;
|
|
42
|
+
public readonly priority: number;
|
|
43
|
+
public requests: Promise<CompletedRequest>[] = [];
|
|
44
|
+
public requestCount = 0;
|
|
45
|
+
|
|
46
|
+
constructor(data: RequestRuleData) {
|
|
47
|
+
validateMockRuleData(data);
|
|
48
|
+
|
|
49
|
+
this.id = data.id || uuid();
|
|
50
|
+
this.priority = data.priority ?? RulePriority.DEFAULT;
|
|
51
|
+
this.matchers = data.matchers;
|
|
52
|
+
this.completionChecker = data.completionChecker;
|
|
53
|
+
|
|
54
|
+
if ('handle' in data.handler) {
|
|
55
|
+
this.handler = data.handler;
|
|
56
|
+
} else {
|
|
57
|
+
// We transform the definition into a real handler, by creating an instance of the raw handler (which is
|
|
58
|
+
// a subtype of the definition with the same constructor) and copying the fields across.
|
|
59
|
+
this.handler = Object.assign(
|
|
60
|
+
Object.create(HandlerLookup[data.handler.type].prototype),
|
|
61
|
+
data.handler
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
matches(request: OngoingRequest) {
|
|
67
|
+
return matchers.matchesAll(request, this.matchers);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
handle(req: OngoingRequest, res: OngoingResponse, options: {
|
|
71
|
+
record?: boolean,
|
|
72
|
+
emitEventCallback?: (type: string, event: unknown) => void
|
|
73
|
+
}): Promise<void> {
|
|
74
|
+
let handlerPromise = (async () => { // Catch (a)sync errors
|
|
75
|
+
return this.handler.handle(req, res, {
|
|
76
|
+
emitEventCallback: options.emitEventCallback
|
|
77
|
+
});
|
|
78
|
+
})();
|
|
79
|
+
|
|
80
|
+
// Requests are added to rule.requests as soon as they start being handled,
|
|
81
|
+
// as promises, which resolve only when the response & request body is complete.
|
|
82
|
+
if (options.record) {
|
|
83
|
+
this.requests.push(
|
|
84
|
+
Promise.race([
|
|
85
|
+
// When the handler resolves, the request is completed:
|
|
86
|
+
handlerPromise,
|
|
87
|
+
// If the response is closed before the handler completes (due to aborts, handler
|
|
88
|
+
// timeouts, whatever) then that also counts as the request being completed:
|
|
89
|
+
new Promise((resolve) => res.on('close', resolve))
|
|
90
|
+
])
|
|
91
|
+
.catch(() => {}) // Ignore handler errors here - we're only tracking the request
|
|
92
|
+
.then(() => waitForCompletedRequest(req))
|
|
93
|
+
.catch((): CompletedRequest => {
|
|
94
|
+
// If for some reason the request is not completed, we still want to record it.
|
|
95
|
+
// TODO: Update the body to return the data that has been received so far.
|
|
96
|
+
const initiatedRequest = buildInitiatedRequest(req);
|
|
97
|
+
return {
|
|
98
|
+
...initiatedRequest,
|
|
99
|
+
body: buildBodyReader(Buffer.from([]), req.headers),
|
|
100
|
+
rawTrailers: [],
|
|
101
|
+
trailers: {}
|
|
102
|
+
};
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Even if traffic recording is disabled, the number of matched
|
|
108
|
+
// requests is still tracked
|
|
109
|
+
this.requestCount += 1;
|
|
110
|
+
|
|
111
|
+
return handlerPromise as Promise<any>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
isComplete(): boolean | null {
|
|
115
|
+
if (this.completionChecker) {
|
|
116
|
+
// If we have a specific rule, use that
|
|
117
|
+
return this.completionChecker.isComplete(this.requestCount);
|
|
118
|
+
} else if (this.requestCount === 0) {
|
|
119
|
+
// Otherwise, by default we're definitely incomplete if we've seen no requests
|
|
120
|
+
return false;
|
|
121
|
+
} else {
|
|
122
|
+
// And we're _maybe_ complete if we've seen at least one request. In reality, we're incomplete
|
|
123
|
+
// but we should be used anyway if we're at any point we're the last matching rule for a request.
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
explain(withoutExactCompletion = false): string {
|
|
129
|
+
let explanation = `Match requests ${matchers.explainMatchers(this.matchers)}, ` +
|
|
130
|
+
`and then ${this.handler.explain()}`;
|
|
131
|
+
|
|
132
|
+
if (this.completionChecker) {
|
|
133
|
+
explanation += `, ${this.completionChecker.explain(
|
|
134
|
+
withoutExactCompletion ? undefined : this.requestCount
|
|
135
|
+
)}.`;
|
|
136
|
+
} else {
|
|
137
|
+
explanation += '.';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return explanation;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
dispose() {
|
|
144
|
+
this.handler.dispose();
|
|
145
|
+
this.matchers.forEach(m => m.dispose());
|
|
146
|
+
if (this.completionChecker) this.completionChecker.dispose();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Duplex } from "stream";
|
|
2
|
+
|
|
3
|
+
import { Serialized, deserialize } from "../serialization/serialization";
|
|
4
|
+
|
|
5
|
+
import type { RuleParameters } from "./rule-parameters";
|
|
6
|
+
|
|
7
|
+
import type { RequestRuleData } from "./requests/request-rule";
|
|
8
|
+
import type { WebSocketRuleData } from "./websockets/websocket-rule";
|
|
9
|
+
|
|
10
|
+
import * as matchers from "./matchers";
|
|
11
|
+
import * as completionCheckers from "./completion-checkers";
|
|
12
|
+
|
|
13
|
+
import { HandlerLookup } from "./requests/request-handlers";
|
|
14
|
+
import { WsHandlerLookup } from './websockets/websocket-handlers';
|
|
15
|
+
|
|
16
|
+
export function deserializeRuleData(
|
|
17
|
+
data: Serialized<RequestRuleData>,
|
|
18
|
+
stream: Duplex,
|
|
19
|
+
ruleParameters: RuleParameters
|
|
20
|
+
): RequestRuleData {
|
|
21
|
+
return {
|
|
22
|
+
id: data.id,
|
|
23
|
+
priority: data.priority,
|
|
24
|
+
matchers: data.matchers.map((m) =>
|
|
25
|
+
deserialize(m, stream, ruleParameters, matchers.MatcherLookup)
|
|
26
|
+
),
|
|
27
|
+
handler: deserialize(data.handler, stream, ruleParameters, HandlerLookup),
|
|
28
|
+
completionChecker: data.completionChecker && deserialize(
|
|
29
|
+
data.completionChecker,
|
|
30
|
+
stream,
|
|
31
|
+
ruleParameters,
|
|
32
|
+
completionCheckers.CompletionCheckerLookup
|
|
33
|
+
)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function deserializeWebSocketRuleData(
|
|
38
|
+
data: Serialized<WebSocketRuleData>,
|
|
39
|
+
stream: Duplex,
|
|
40
|
+
ruleParameters: RuleParameters
|
|
41
|
+
): WebSocketRuleData {
|
|
42
|
+
return {
|
|
43
|
+
id: data.id,
|
|
44
|
+
matchers: data.matchers.map((m) =>
|
|
45
|
+
deserialize(m, stream, ruleParameters, matchers.MatcherLookup)
|
|
46
|
+
),
|
|
47
|
+
handler: deserialize(data.handler, stream, ruleParameters, WsHandlerLookup),
|
|
48
|
+
completionChecker: data.completionChecker && deserialize(
|
|
49
|
+
data.completionChecker,
|
|
50
|
+
stream,
|
|
51
|
+
ruleParameters,
|
|
52
|
+
completionCheckers.CompletionCheckerLookup
|
|
53
|
+
)
|
|
54
|
+
};
|
|
55
|
+
}
|