Back to Cypress

@packages/network-interception

packages/network-interception/README.md

16.0.09.3 KB
Original Source

@packages/network-interception

Transport-agnostic center for Cypress network interception: port interfaces, the NetworkInterceptionCore orchestrator, the policy registry, and the shared types behind cy.intercept.

The package holds the interception rules — route matching, subscription planning, handler merge, injection-level and request-logging decisions, config policies. It holds none of the I/O. Everything transport-specific (MITM proxy middleware, CDP Fetch, driver IPC, cookie jar, Test Replay capture) lives behind an interface and is injected at a composition root.

@packages/network-interception must not import from @packages/proxy or @packages/net-stubbing. The dependency arrow only points inward.


Why ports and adapters

Interception logic used to live inline in @packages/proxy and @packages/net-stubbing middleware, hard-wired to the MITM proxy. Cypress now runs the same matching, handler, and policy behavior over two different transports, so that logic had to stop depending on how bytes move.

The codebase uses hexagonal architecture (ports and adapters): keep the rules in a transport-agnostic center, isolate I/O behind interfaces, plug in a different implementation per transport.

Hex termRoleIn this monorepo
PortContract at the edge of the interception "inside"For* types in lib/ports/
AdapterImplements a port by delegating to transport-specific code*Adapter classes under packages/*/lib/adapters/
Driving port (primary)Outside actors call into interceptionForInterceptRegistration, ForNetworkPolicyRegistration
Driven port (secondary)Interception calls out for I/OForRequestInterception, ForCookieState, …
CoreDomain orchestration, no transport importsNetworkInterceptionCore (lib/core/)
Composition rootConstructs and injects adapters + corecreateProxyRuntime() / createCdpFetchRuntime() (packages/server/lib/network-runtime.ts)

What lives here

lib/core/ — the pure center

ModuleResponsibility
route-matching.tsmatchRoutes, doesRouteMatch, getMatchableForRequest, CORS-preflight matching
matcher-fields.tsWhich RouteMatcher fields are string matchers
plan-subscriptions.tsWhich events each matched route subscribes to
merge-handler-result.tsMerge driver handler results back into the request/response
document-preparation.tsInjection-level and framebusting-removal decisions; shared content-type / Accept / service-worker predicates
request-logging.tsWhether a request shows up in the command log
http-intercept.tsHttpIntercept — the transport-agnostic middleware onion
network-interception-core.tsNetworkInterceptionCore — delegates decisions to the pure modules and I/O to driven ports

Everything else

PathContents
lib/ports/driving-ports.tsForInterceptRegistration, ForNetworkPolicyRegistration
lib/ports/driven-ports.tsThe six I/O ports plus the ForBrowserNetworkAutomation stub
lib/ports/http-interception.tsHttpRequest / HttpResponse, TransportCodecPort, InterceptMiddleware
lib/registry/NetworkPolicyRegistry — the default ForNetworkPolicyRegistration
lib/policies/NetworkPolicy shape, the config policy factories, registerDefaultNetworkPolicies()
lib/types/external-types.tsPublic API. Copied verbatim to cli/types/net-stubbing.d.ts by cli/scripts/sync-typedefs.ts — changes here ship to users
lib/types/internal-types.tsNetEvent driver↔server protocol, serializable prop lists
lib/runtime.tsNetworkInterceptionRuntime facade (implemented by the proxy runtime)

Ports and their adapters

Driving — outside calls in

PortAdapterPackage
ForInterceptRegistrationDriverInterceptRegistrationAdapternet-stubbing
ForNetworkPolicyRegistrationConfiguratorNetworkPolicyAdapterserver

Driven — the core calls out

PortAdapter(s)Responsibility
ForRequestInterceptionProxyRequestInterceptionAdapterPre-request correlation, blocked-host termination
ForResponseInterceptionProxyResponseInterceptionAdapterResponse intercept continuation
ForDocumentPreparationProxyDocumentPreparationAdapterInjection level, HTML inject, security stripping
ForNetworkCaptureProxyNetworkCaptureAdapterTest Replay / protocol capture
ForCookieStateProxyCookieStateAdapterCookie jar attach and Set-Cookie capture
ForCommandLogProxyCommandLogAdapter, DriverCommandLogAdapterCommand-log entries
ForBrowserNetworkAutomation(none — see Known gaps)Reserved for browser network session hooks

Middleware never calls an adapter directly; it calls this.networkInterceptionCore.* and the core routes to the injected port.


One core, two transports

Cypress intercepts browser traffic either through the HTTP/1 MITM proxy or in the browser itself over CDP Fetch. isBrowserNetworkMode() (packages/server/lib/util/network-mode.ts) picks: Chromium-family browsers take the CDP path by default; forceHttp1, Firefox, WebKit, and Electron stay on the proxy.

Both paths run the same HttpIntercept middleware onion over the same core. What differs is the codec — a TransportCodecPort translating a transport's native request/response to and from the neutral HttpRequest / HttpResponse shape. Two codec roles are in play:

RolePurpose
Transport codecPassed to new HttpIntercept(codec); adapts whatever the transport hands in
Pipeline codecPassed to createLegacyProxyPipeline(codec); builds the legacy middleware context
InterceptTransport codecPipeline codec
Express / MITM proxynetworkProxy.codechttp-codec.ts (proxy)same
CDP FetchcreateCdpFetchCodec()cdp-fetch-codec.ts (server)createSyntheticProxyCodec()synthetic-proxy-codec.ts (proxy)

In browser-network mode both intercepts exist: the CDP one handles browser traffic, while the Express one still serves internal routes and studio / cy-prompt forwards. They share middleware stages but stay distinct intercepts.

Because the CDP path drives NetworkProxy through a synthetic Express context, the legacy middleware stack — cookies, blocked hosts, rewriter, net-stubbing — runs unchanged on both transports.

Composition roots

Both live in packages/server/lib/network-runtime.ts and are selected by server-base.ts. They share the same spine:

ConfiguratorNetworkPolicyAdapter      (driving port)
registerDefaultNetworkPolicies()
createProxyNetworkInterception()      (core + 6 driven-port adapters)
NetworkProxy                          (legacy middleware stack)
HttpIntercept(codec)                  (middleware onion)

createProxyRuntime() builds one intercept over the proxy codec and returns a NetworkInterceptionRuntime. createCdpFetchRuntime() builds the two intercepts above plus a CdpFetchTransport, and adds start / stop / attachExtraTarget for popup and service-worker sessions.


Policies

Config-derived rules (blockHosts, experimentalCspAllowList, modifyObstructiveCode) are registered as NetworkPolicy objects at startup by registerDefaultNetworkPolicies() and evaluated by NetworkPolicyRegistry.

The request phase is live: proxy request middleware calls core.endRequestIfBlocked(), which runs the registry for phase: 'request'; a policy that calls ctx.end() stops the chain, and blocked-hosts puts its match in ctx.state for the adapter to turn into a 503.


Known gaps

  • Response-phase policies never execute. runPolicies is only ever called with phase: 'request', so csp-allow-list and document-rewrite are registered but unreachable, and their apply is a no-op. CSP allow-listing and document rewriting are still enforced directly in proxy response middleware. The 'error' phase has neither a policy nor a caller.
  • ForBrowserNetworkAutomation is an empty stub. It was reserved for the browser-network path, but that path shipped through the TransportCodecPort seam instead, so nothing implements or supplies it.
  • forwardToOrigin is unreachable. The port, the core method, and ProxyRequestInterceptionAdapter.forwardToOrigin are all in place, but the proxy calls sendRequestOutgoing directly from http-codec.ts instead of going through the core.

Background

The ports-and-adapters refactor landed as an eight-PR stack tracked in #33919 (closed). That issue is the design rationale; this file describes the result. Adapter-side notes live in packages/net-stubbing/lib/adapters/README.md and packages/server/lib/adapters/README.md.


Development

bash
yarn workspace @packages/network-interception test
yarn workspace @packages/net-stubbing test
yarn workspace @packages/proxy test
yarn workspace @packages/server test-unit -- network-runtime_spec

Behavioral coverage for cy.intercept itself lives in packages/driver/cypress/e2e/commands/net_stubbing.cy.ts, not in this package.