Releases: httptoolkit/mockttp
Releases · httptoolkit/mockttp
v4.0.0
import * as mockttp from 'mockttp';
const https = await mockttp.generateCACertificate();
const server = getLocal({ https });
server.forPost()
.forHostname("example.com")
.delay(500)
.thenReply(200, "Hello world");
server.forAnyWebSocket()
.withHeaders({ cookie: 'abcd' })
.thenPassThrough({
transformRequest: {
matchReplaceQuery: [/username=(.*)/, 'role=admin&username=$1']
}
});
await server.start();
Notable changes
- Advanced URL rewriting: with a selection of new request transform options to separately rewrite and match/replace with regexes against the protocol, hostname, path & query, for both HTTP requests & websockets.
- Support for multi-step rules, where a step can be non-final, allowing chaining of behaviour. The first new non-final step that's supported is a new
delay(X)
step, which you can add to any rule to wait Xms before running the next step. More to come (open an issue with ideas!) - Added support for inbound SOCKS proxying, enabled with the
socks: true
option. - Added support for unknown-protocol blind data passthrough, with the
passthrough: ['unknown-protocol']
option. With this enabled, non-HTTP traffic will be recognized, and automatically proxied untouched through Mockttp to its destination. This is only possible when a connection destination is provided separately, with an HTTP or SOCKS tunnel (i.e. this isn't supported in direct connections). All proxied data is fully observable via the newraw-passthrough-*
events. - Added support for connection-tagging via proxy authentication (with SOCKS & HTTP proxies). To add a tag to all data on a connection, authenticate with username
metadata
and a password containing JSON like{"tags":["tag1", ...]}
(255 character length limit). The password can be base64 encoded if required. SOCKS proxying also supports a custom authentication method (0xDA
) to attach metadata to a connection without length limits, but this requires custom client support. The resulting data is available in thetags
field of all request events and similar fired by this connection later. - Client-side usage (
getRemote
or browser usage) no longer requires use ofhttp-encoding
,zstd-codec
,brotli-wasm
or similar, simplifying many browser testing use cases. Instead all decoding is handled transparently on the server-side. Automatic encoding can also be disabled completely using the newmessageBodyDecoding: 'none'
Mockttp client option, which will expose only encoded (or no-encoding-required) data and require you to manually handle encoded cases (throwing an error if you try to read encoded data without doing so).
💥 Breaking changes
- The minimum Node version is now Node v20. v18 will still work, for now, but may stop working unpredictably in any future release.
- Proxying:
- Explicitly proxy destinations are now consistently used in preference to
host
/:authority
header values if both are available but don't match. This could previously be inconsistent in some cases, but we now assume if you attempt to proxy to a server, then that's the 'real' destination, and this is reflected in theurl
property and elsewhere. - Proxy-connection & proxy-authorization headers are now always preprocessed and stripped up front. Previously this happened during upstream proxying, so these headers could be visible in events and similar, which is probably not what you expected. This applies even for direct requests (
GET https://google.com
) that don't create a separate tunnel. - When using Node 22.13+, extra default headers will no longer be added automatically to proxied requests. This previously resulted in automatic addition of
transfer-encoding
andconnection
headers. This will no longer be applied by default. If your request is already normal valid HTTP this will not cause a problem. If not (unlikely unless you're building HTTP requests without a proper client) then you will need to fix your request or use a beforeRequest callback to manually do so. - When modifying a proxied request with the various passthrough options, if you modify the body we now enforce that you include valid framing headers, and we set them if you don't. This is probably what you want (if you modify the body, you want to set the right content-length so that it is delivered). This is as cautious as possible, so in practice this should only correct invalid cases that would be invalid HTTP otherwise.
- When redirecting proxied traffic, you can no longer use
thenForwardTo
with abeforeRequest
callback. Internally, forwarding is now part of thetransformRequest
options, which can't be used with the corresponding callback. Instead, return aurl
from yourbeforeRequest
callback directly. - Upstream ECONNRESET errors are now only simulated downstream if
simulateConnectionErrors
is set, like other connection issues (this was previously inconsistent for backward compatibility).
- Explicitly proxy destinations are now consistently used in preference to
- Events:
- TLS event
connectHostname
,connectPort
andhostname
properties have been removed as they were ambiguous. Instead depending on your use case you will want one of:event.destination
for the tunnel target hostname & portevent.tlsMetadata.sniHostname
for the servername specified in the TLS SNI extension.
hostname
has been removed from request & websocket events too, as it wasn't clear where this came from. Instead depending on your use case you will want one of:event.url
to get the effective URL of the requestevent.destination
to get the calculated destination of the request (this will be the tunnel destination if available, or value from the headers if not)event.headers['host']
(HTTP/1.1) orevent.headers[':authority']
(HTTP/2+) to get the host that's being requested in the HTTP request itself
- TLS event
- Remote clients:
- When using a remote client (
getRemote
or usage from a browser), all body content is now decoded on the server side, rather than within the client. This simplifies client setup significantly (e.g. brotli-wasm & associated setup is no longer required) and should be an invisible change in most cases, but could result in small differences in event delivery timing to the client as decoding must complete (or fail) before the event is delivered. - Internal backward compat for very old servers & clients (multiple years) has been removed, so if you are using a modern Mockttp version as a client to control an old Mockttp server you may have issues. Using a Mockttp v4 client to control any previous Mockttp version is not supported.
- When using a remote client (
- TLS Certificates:
generateCACertificate
has moved the subject-related options into a separatesubject: {}
options field.- CA certificate generation has been migrated from node-forge (now unmaintained) to the @peculiar/* libraries, and have been improved to better match modern browser CA certificate standards (i.e. full standards for real root CAs) as far as possible. This may result in various small differences in the CA & site certificates generated. Unless you're examining details of certificates yourself this should not be visible.
- Generated CA certificate key PEMs are now in PKCS#8 format (
BEGIN PRIVATE KEY
, not PKCS#1 (BEGIN RSA PRIVATE KEY
) as previously.
- Manual rule building (e.g.
server.addRequestRules({ matchers: [...], handler: ... })
,setRequestRules
, etc):- Handlers are now steps, and you can have multiple of them. In most cases you will want to replace
handler: X
withsteps: [X]
. - Due to a substantial refactoring in handler classes & their exports, the naming & import pattern has changed. Implementations are no longer exported at all (you shouldn't need them), definitions are exported as
requestSteps
andwebSocketSteps
, and 'Handler' has been replaced with 'Step' in all names. For example, you may want to usemockttp.requestSteps.PassThroughStep
to define a passthrough proxy step. - The
forwarding
option for passthrough rules has been migrated intotransformRequest
as newsetProtocol
,replaceHost
,matchReplaceHost
,matchReplacePath
andmatchReplaceQuery
options, providing far more powerful URL rewriting tools. For most simple cases, you can migrate by simply passing yourforwarding
option asreplaceHost
instead. - Some classes have been fully renamed en route:
SimpleHandler
is nowFixedResponseHandler
SimplePathMatcher
is nowFlexiblePathMatcher
- Handlers are now steps, and you can have multiple of them. In most cases you will want to replace
- Misc:
- The content of the 503 response returned for websocket connections that matched no rules has changed to better match the HTTP request equivalent.
- In all APIs, only real RegExp instances are treated as regular expressions (previously regex compatible objects could have been used - this is a very niche scenario mostly relating to cross-realm data)
- Various long-deprecated aliases & fallbacks have been removed: type aliases (
TlsRequest/HttpsOptions/HttpsPathOptions
are nowTlsHandshakeFailure/CertDataOptions/CertPathOptions
respectively), the callbackstatus
result field (usestatusCode
instead), thetrustAdditionalCAs
option (useadditionalTrustedCAs
instead), and the string format in thetrustedCAs
proxy settings option for upstream proxying.
Full Changelog: v3.17.1...v4.0.0
v3.0.0
💥 Breaking changes:
- Mockttp no longer supports Node.js v12, which is now end-of-life. The new minimum version is Node v14.14.0.
- Lots of previously deprecated APIs were removed:
- All rule definition that didn't start with
.for[...]()
, such asmockServer.get()
,mockServer.post()
andmockServer.anyRequest()
were removed. These were previously deprecated in v2.5.0. These can all be replaced with the equivalentforX
method, e.g.mockServer.forGet()
,mockServer.forPost()
andmockServer.forAnyRequest()
. All rule builder methods now consistently start withmockServer.forX()
. - Standalone servers are now admin servers, and all previously-deprecated references to 'standalone' have been replaced with 'admin', for example
Mockttp.getStandalone()
is nowMockttp.getAdminServer()
. - The admin server's (previously the standalone server's)
activeServerPorts
method has been removed, and themock-server-started/stopping
events have been replaced withmock-session-started/stopping
. - The deprecated
handlers
andMockRuleData
root exports have been removed, they should be replaced withrequestHandlers
andRequestRuleData
. - The deprecated
tlsClientError
mockttp instance subscription event has been removed, it should be replaced withtls-client-error
instead. - The deprecated
ignoreHostCertificateErrors
passthrough rule option was removed, it should be replaced with the newignoreHostHttpsErrors
instead. - The previously deprecated
addRules
andsetRules
methods have been removed, they should be replaced withaddRequestRules
andsetRequestRules
. - The
setFallbackRule
method has been removed, it should be replaced by setting rules with the newpriority: 0
field instead. - The deprecated
thenJSON
request rule builder method has been removed, it should be replaced withthenJson
instead. - The deprecated synchronous body decoding methods have been removed:
body.decodedBuffer
,body.text
,body.json
andbody.formData
. They should be replaced with thebody.getDecodedBuffer()
,.getText()
,.getJson()
and.getFormData()
asynchronous methods instead. - The body property on aborted request event data has been removed (previously it was present but always empty).
- All rule definition that didn't start with
- When returning a result with a
body
orjson
field from a callback (thenCallback
,beforeRequest
orbeforeResponse
), the request or response body will now be automatically encoded to match itscontent-encoding
header. PreviouslytransformRequest/Response
results were automatically encoded but nothing else. To return raw data that should not be encoded automatically, returnrawBody
instead with a Buffer/Uint8Array, and that will be used as-is with no encoding applied. - Mockttp is now considerably stricter about preserving raw header data (i.e. header order, duplicate headers and heading name casing) when reporting and proxying requests. Officially this is not semantically meaningful in HTTP, and should not affect any correct server/client implementations, but in practice some tools may behave differently. For Mockttp users, this means:
- All exposed requests & responses now include both a
header
object (lowercased header string keys to single-string or array-of-string values) and arawHeader
array (an array of [string name, string value] pairs, with the exact order & casing that they were received). - When using passthrough rules, proxied traffic preserves the exact header formatting for upstream requests and returned responses where possible. The one case when this isn't possible is when setting headers with a
transformRequest/Response
object orbeforeRequest/Response
callback. In that case, the headers will be normalized before forwarding, lowercasing header names and potentially changing header order.
- All exposed requests & responses now include both a
- All
.on(event)
subscriptions are now reset when a Mockttp instance resets, either due tomockServer.reset()
or.stop()
and.start()
(previously only rules were reset). - Incoming websockets that don't match any rule are now rejected with a 503 (previously they were automatically proxied by default). This matches the behaviour for unmatched HTTP requests. To continue proxying websocket traffic, define an explicit rule like
mockServer.forAnyWebSocket().thenPassThrough()
.
Other.changes:
- Added forPort and forHostname matchers, for more precise host matching (in addition to forHost, which matches the host header including some implicit header behaviour)
- Added support for multiple fallback rules with
forUnmatchedRequest()
, added support for using matchers on fallback rules, and addedasPriority(n)
to define multiple custom layers of multiple rules at different priorities. - Added
thenRejectConnection
to reject websocket connections with a given HTTP response.
v2.0.0
💥 Breaking changes:
- Some unusual content encodings (notably Brotli) are no longer handled automatically when using the (now deprecated) synchronous properties. If you're using
body.decodedBuffer
,body.text
,body.json
orbody.formData
you should switch to the correspondingbody.getX()
methods instead. These methods decode content asynchronously, improving performance especially with parallel requests, and they support more encodings (including Brotli and Zstandard).
Gzip, deflate, and unencoded content all still work both sync or async, so nothing will break in these common cases, but moving to the async functions is recommended regardless. - Node v10 is no longer officially supported as it's now EOL. It still works right now, but it's no longer tested, and it's likely to stop working without warning in future versions.
Other big changes:
- For common cases, you can now automatically transform proxied content using
transformRequest
andtransformResponse
options, instead of providing your own custombeforeRequest
andbeforeResponse
callbacks. These support completely replacing and/or updating most properties of proxied content, they make your code simpler, and in many cases they're significantly faster. ThebeforeX
options still exist and are fully supported, but they're recommended only for advanced use cases. - Chaining mockttp with upstream proxies is now supported, using the
proxyConfig
option with passthrough rules.