mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-09 08:40:32 -06:00
fix: "bypass" proxying network requests from extra browser tabs/windows (#28188)
Co-authored-by: Ryan Manuel <ryanm@cypress.io> Co-authored-by: Matt Schile <mschile@cypress.io>
This commit is contained in:
@@ -106,6 +106,7 @@ const READONLY_MIDDLEWARE_KEYS: (keyof HttpMiddlewareThis<{}>)[] = [
|
||||
'onResponse',
|
||||
'onError',
|
||||
'skipMiddleware',
|
||||
'onlyRunMiddleware',
|
||||
]
|
||||
|
||||
export type HttpMiddlewareThis<T> = HttpMiddlewareCtx<T> & ServerCtx & Readonly<{
|
||||
@@ -119,6 +120,7 @@ export type HttpMiddlewareThis<T> = HttpMiddlewareCtx<T> & ServerCtx & Readonly<
|
||||
onResponse: (incomingRes: IncomingMessage, resStream: Readable) => void
|
||||
onError: (error: Error) => void
|
||||
skipMiddleware: (name: string) => void
|
||||
onlyRunMiddleware: (names: string[]) => void
|
||||
}>
|
||||
|
||||
export function _runStage (type: HttpStages, ctx: any, onError: Function) {
|
||||
@@ -220,9 +222,12 @@ export function _runStage (type: HttpStages, ctx: any, onError: Function) {
|
||||
_end()
|
||||
},
|
||||
onError: _onError,
|
||||
skipMiddleware: (name) => {
|
||||
skipMiddleware: (name: string) => {
|
||||
ctx.middleware[type] = _.omit(ctx.middleware[type], name)
|
||||
},
|
||||
onlyRunMiddleware: (names: string[]) => {
|
||||
ctx.middleware[type] = _.pick(ctx.middleware[type], names)
|
||||
},
|
||||
...ctx,
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { doesTopNeedToBeSimulated } from './util/top-simulation'
|
||||
|
||||
import type { HttpMiddleware } from './'
|
||||
import type { CypressIncomingRequest } from '../types'
|
||||
|
||||
// do not use a debug namespace in this file - use the per-request `this.debug` instead
|
||||
// available as cypress-verbose:proxy:http
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@@ -31,15 +32,30 @@ const ExtractCypressMetadataHeaders: RequestMiddleware = function () {
|
||||
const span = telemetry.startSpan({ name: 'extract:cypress:metadata:headers', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
||||
|
||||
this.req.isAUTFrame = !!this.req.headers['x-cypress-is-aut-frame']
|
||||
|
||||
span?.setAttributes({
|
||||
isAUTFrame: this.req.isAUTFrame,
|
||||
})
|
||||
this.req.isFromExtraTarget = !!this.req.headers['x-cypress-is-from-extra-target']
|
||||
|
||||
if (this.req.headers['x-cypress-is-aut-frame']) {
|
||||
delete this.req.headers['x-cypress-is-aut-frame']
|
||||
}
|
||||
|
||||
span?.setAttributes({
|
||||
isAUTFrame: this.req.isAUTFrame,
|
||||
isFromExtraTarget: this.req.isFromExtraTarget,
|
||||
})
|
||||
|
||||
// we only want to intercept requests from the main target and not ones from
|
||||
// extra tabs or windows, so run the bare minimum request/response middleware
|
||||
// to send the request/response directly through
|
||||
if (this.req.isFromExtraTarget) {
|
||||
this.debug('request for [%s %s] is from an extra target', this.req.method, this.req.proxiedUrl)
|
||||
|
||||
delete this.req.headers['x-cypress-is-from-extra-target']
|
||||
|
||||
this.onlyRunMiddleware([
|
||||
'SendRequestOutgoing',
|
||||
])
|
||||
}
|
||||
|
||||
span?.end()
|
||||
this.next()
|
||||
}
|
||||
|
||||
@@ -167,6 +167,27 @@ const LogResponse: ResponseMiddleware = function () {
|
||||
this.next()
|
||||
}
|
||||
|
||||
const FilterNonProxiedResponse: ResponseMiddleware = function () {
|
||||
// if the request is from an extra target (i.e. not the main Cypress tab, but
|
||||
// an extra tab/window), we want to skip any manipulation of the response and
|
||||
// only run the middleware necessary to get it back to the browser
|
||||
if (this.req.isFromExtraTarget) {
|
||||
this.debug('response for [%s %s] is from extra target', this.req.method, this.req.proxiedUrl)
|
||||
|
||||
this.onlyRunMiddleware([
|
||||
'AttachPlainTextStreamFn',
|
||||
'PatchExpressSetHeader',
|
||||
'MaybeSendRedirectToClient',
|
||||
'CopyResponseStatusCode',
|
||||
'MaybeEndWithEmptyBody',
|
||||
'GzipBody',
|
||||
'SendResponseBodyToClient',
|
||||
])
|
||||
}
|
||||
|
||||
this.next()
|
||||
}
|
||||
|
||||
const AttachPlainTextStreamFn: ResponseMiddleware = function () {
|
||||
this.makeResStreamPlainText = function () {
|
||||
const span = telemetry.startSpan({ name: 'make:res:stream:plain:text', parentSpan: this.resMiddlewareSpan, isVerbose })
|
||||
@@ -869,6 +890,7 @@ const SendResponseBodyToClient: ResponseMiddleware = function () {
|
||||
|
||||
export default {
|
||||
LogResponse,
|
||||
FilterNonProxiedResponse,
|
||||
AttachPlainTextStreamFn,
|
||||
InterceptResponse,
|
||||
PatchExpressSetHeader,
|
||||
|
||||
@@ -18,6 +18,7 @@ export type CypressIncomingRequest = Request & {
|
||||
followRedirect?: boolean
|
||||
isAUTFrame: boolean
|
||||
credentialsLevel?: RequestCredentialLevel
|
||||
isFromExtraTarget: boolean
|
||||
/**
|
||||
* Resource type from browserPreRequest. Copied to req so intercept matching can work.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user