mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-13 02:40:22 -05:00
458db1cd02
* docs: revise contributor advice for node.js setup (#26652)
* feat: initial release of cypress/vite-plugin-cypress-esm (#26663)
* chore: release @cypress/vite-plugin-cypress-esm-v1.0.0
[skip ci]
* chore: upgrade Lerna to v5 and use Nx (#26660)
* dependency(deps): update dependency engine.io to v6.4.2 [security] (#26664)
* dependency(deps): update dependency engine.io to v6.4.2 [security]
* updating changelog
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Matt Schile <mschile@cypress.io>
* fix: updated CYPRESS_DOWNLOAD_PATH_TEMPLATE regex to allow multiple replacements (#25531)
* feat: Component Testing banner (#26625)
Co-authored-by: elevatebart <bart@cypress.io>
* chore: Update v8 snapshot cache (#26647)
Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
* chore: 12.12.0 release updates (#26697)
* chore: cypress[26674] updated github workflows to use checklout@v3 and stop using set-output and move to file use (#26696)
* fix: move types condition to the front (#26630)
* fix: move `types` condition to the front
* chore: update changelog
* optimize deps for vite
* update config
* try optimizeDeps.include
* missing dep
---------
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
* fix: revert #26452 (Yarn Plug n Play compat regression) (#26735)
* Revert "fix: correctly resolve dependencies for CT onboarding when using Yarn Plug n Play (#26452)"
This reverts commit 7a33f5c1a8.
* changelog
* changelog
* chore: fixing PR link in releaseData.json (#26734)
* chore: update stalebot config (#26745)
* misc: ACI empty state slideshows (#26692)
Co-authored-by: Stokes Player <stokes@cypress.io>
* fix: do not cache module resolution during launchpad dependency detection (#26726)
Co-authored-by: Mike Plummer <mikep@cypress.io>
* fix: Vite esm plugin issues (#26714)
* chore: Update v8 snapshot cache (#26707)
Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
* chore: adding in repo token to explicitly use that while running commands [skip ci] (#26746)
* chore(dependency): update dependency @percy/cypress to ^3.1.2 🌟 (#26717)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Chris Breiding <chrisbreiding@users.noreply.github.com>
* chore: Remove console.log (#26756)
* chore: put types condition first in the syncing script (#26743)
Co-authored-by: Chris Breiding <chrisbreiding@users.noreply.github.com>
* test: create lists files after folders when in same directory in specs list (#26723)
Co-authored-by: Chris Breiding <chrisbreiding@users.noreply.github.com>
* chore: update vm2 to 3.9.19 (#26772)
* chore: add telemetry to the proxy (#26695)
* chore: set up instrumentation and instrument middleware
* chore: set up console exporter
* chore: add parent span option to telemetry package
* chore: set up telemetry verbose mode
* chore: instrument the network proxy - part 1
* chore: make sure to terminate spans when request is aborted
* fix telemetry, create/end the request middle prior to sending the outbound request
* avoid telemetry ts build step, create entrypoint into packages/telemetry using TS conventions
* allow env vars to be "true" or "1"
* when creating child span, inherit their attributes directly from the parent
* create custom honeycomb exporter and span processor to log traces
* remove duplicate code that's already called in this.setRootContext
* cleanup
* more clean up
* update honeycomb network:proxy attributes, update console.log message
* yarn lock
* chore: remove performance API in middleware
* chore: end response on correct event
* recursively gather parent attributes on close
* added key and some clean up
* github action detector, move verbose into index, verbose log commands
* some tests
* clean up honeycomb exporter
* some renaming
* testing console trace link exporter
* Don't lose the top span when running in verbose.
* link to the right place for prod/dev
* changes to verbose to make sure it is read in the browser
* Apply suggestions from code review
* pass parent attributes between telemetry instances
* default to false
* 'fix' build issues
* src not dist
* add back on start span
* once more with feeling
* Fix some tests
* try this i guess
* revert auto build
* Apply suggestions from code review
Co-authored-by: Bill Glesias <bglesias@gmail.com>
* support failed commands
* Address PR comments
* Address PR Comments
* error handling
* handle all the errors
---------
Co-authored-by: Bill Glesias <bglesias@gmail.com>
Co-authored-by: Brian Mann <brian.mann86@gmail.com>
* chore: update triage workflow to add comment to contributor prs (#26493)
Co-authored-by: Ben M <benm@cypress.io>
* chore: telemetry pr cleanup (#26776)
* fix: fix UI flash when switching to debug page (#26761)
* chore: add Nx Cloud (#26712)
* chore: add empty nx.json [run ci]
* chore: add nx cloud runner [run ci]
* chore: add nx-cloud dep [run ci]
* chore: update local nx cloud accessToken to be read-only
* feat: update git related messages for runs and debug (#26758)
* feat(app): update DebugError copy
* feat: set isUsingGit project flag and consume in DebugContainer
* feat(app): update not using git icon for DebugError
* feat(app): displays alert on runs page when not using git
* feat(app): add component for when no runs for current branch
* feat(app): add warning for no runs for branch on runs container
* chore: add feat to CHANGELOG
* chore: remove logged status value
* chore: resolve import from merge conflict
* test(app): stub branch name for e2e runs spec
* chore: add line break in changelog entry
* chore: cleanup PR
* chore: fix i18n import for DebugBranchError
* chore: add utm and update Warning links to inline
* chore: capitalize Git in i18n
* ref: warning liink
* test: add i18n to tests
* test(app): change utm_source assertions
* chore: cleanup pr
* chore: remove unused prop
* test(app): remove no git warning when moving to runs page in e2e
* chore: change template logic
* chore: remove duplicate RUNS_TAB_MEDIUM const
* Changed Debug test assertion and reordered new components for Debug
---------
Co-authored-by: Stokes Player <stokes.player@gmail.com>
* chore: rename video processing events to capture/compress (#26800)
* chore: change processing nomenclature to compressing when printing the run.
* chore: rename 'capturing of' to 'capturing'
* chore: rename upload results to upload screenshots & videos (#26811)
* chore: rename upload results to upload screenshots & videos
* run ci
* chore: capture versions of relevant dependencies with `x-dependencies` header (#26814)
* chore: update changlelog script to handle revert pr ref (#26801)
* fix: Correct typescript scaffold dependency (#26815)
* fix: correct typescript scaffold dependency (#26204)
* add changelog
* Update change log for PR comment
Co-authored-by: Mike Plummer <mike-plummer@users.noreply.github.com>
---------
Co-authored-by: Mike Plummer <mike-plummer@users.noreply.github.com>
Co-authored-by: Mark Noonan <mark@cypress.io>
* chore: 12.13.0 prep (#26833)
* chore: 12.13.0 release (#26834)
* chore: 12.13.0 changelog fix
* remove pending, bump version
* fix typo
* chore: release @cypress/vite-plugin-cypress-esm-v1.0.1
[skip ci]
* chore: Implement runSpec mutation (#26782)
* chore: replace gitter badge with discord on readme (#26771)
* chore: add GraphQL mutation for sending system notifications via Electron (#26773)
* fix: upgrade typescript from 4.7.4 to 4.9.5 (#26826)
Snyk has created this PR to upgrade typescript from 4.7.4 to 4.9.5.
See this package in npm:
See this project in Snyk:
https://app.snyk.io/org/cypress-opensource/project/d5b36925-e6ee-455d-9649-6560a9aca413?utm_source=github&utm_medium=referral&page=upgrade-pr
* test: fix 2 broken tests for Windows (#26854)
* Update stale_issues_and_pr_cleanup.yml
Upped the number of operations per run. Have been manually doing that so this job can get through all the issues in the repo with no problems.
* chore(dep): [Snyk] Upgrade vite from 2.9.13 to 2.9.15 (#26830)
Co-authored-by: Ben M <benm@cypress.io>
* Update triage_add_to_project.yml
* chore: fix minor background color styling in debug results component (#26887)
* Update stale_issues_and_pr_cleanup.yml
stalebot was incorrectly configured to run in debug mode. I have updated the default to run in normal mode when running scheduled
* chore: Deprecate @cypress/xpath package (#26893)
* chore: add telemetry realworld app (#26896)
* chore: capture telemetry for realworld app maybe
* idk what i was doing
* setup record key and telemetry
* testing
* override project id
* some times we just need a little context.
* Adding tests
* Adding comment
* chore(deps): update dependency find-process to v1.4.7 🌟 (#26906)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
* chore(deps): update dependency firefox-profile to v4.3.2 🌟 (#26912)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
* chore: add browser state action for debug (#26884)
* chore: add browser state action for debug (#26763)
* Address PR comments
- remove unneeded async and test context
- genericize openProject function
* Revert route change, update spec description
* chore: replace gift devDep with simple-git (#26728)
* chore: replace arg devDep with minimist; remove unused shx devDep (#26727)
* chore: enable caching for lint task (#26791)
* chore: remove old performance reporting (#26920)
* chore: remove old performance reporting
* remove libhoney dep
* try this
* build and build snapshots if deps are out of date
* foiled by a comma
* freaking comma
* no snapshots maybe ugh
* ignore engines instead
* don't need this
* remove rename support file step
* chore: update Snyk to scan all projects (#26867)
* SEC-544 chore: [Snyk] Update Snyk flag in Git actn
* Update snyk_sca_scan.yaml
Removed --debug switch from the test command
---------
Co-authored-by: brady-cypressio <90723145+brady-cypressio@users.noreply.github.com>
* chore: skip problematic component tests that fail on contributor PRs (#26924)
* chore: omit unused circle variables that cause contributor PR issues (#26935)
* chore: make git message warnings remain dismissable (#26812)
* feat: make git message warnings remain dismissable
* chore: update CHANGELOG
* chore: update CHANGELOG
* chore: remove unneeded code
* chore: update BannerId types
* chore: fix queryies
* chore: clean up PR
* chore: move TrackedWarning to frontend-shared
* chore: update import
* ref: move TrackedWarning to TrackedBanner
* chore: udpate CHANGELOG
* fix: update TrackedBanner to parse markdown message
* chore: set TrackedBanner default message prop
* chore: update RunsContainer
* chore: add missing tests and update alert type
---------
Co-authored-by: Stokes Player <stokes@cypress.io>
* chore: replace fast-glob with globby; remove unneeded getenv dep (#26730)
* fix: update angular dep min versions (#26908)
* fix: update angular dep min versions
* chore: update CHANGELOG
* chore: add line break to changelog
* chore: update changelog pending release date
* chore: remove whitespace
* fix: upgrade typescript from 4.2.3 to 4.9.5 (#26858)
Snyk has created this PR to upgrade typescript from 4.2.3 to 4.9.5.
See this package in npm:
See this project in Snyk:
https://app.snyk.io/org/cypress-opensource/project/5fdaebf8-b115-41d1-a2d9-857261769179?utm_source=github&utm_medium=referral&page=upgrade-pr
Co-authored-by: Bill Glesias <bglesias@gmail.com>
* chore: Update v8 snapshot cache (#26762)
Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
* feat: Implement testing type switch promos (#26894)
* feat: Implement testing type switch promos
* Add tests, changelog entry
* Add tests
* Fix button styling
* Styling fixes, add framework links
* Add missing testId
* run ci
* Fix spec
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
* Fix styling issues
* Resolve code review findings
* Fix issue with yarn.lock
* Fix extra padding at bottom of promo
* Add tests for utm params
* Add test for switching testing type when both configured
* Fix changelog version
* Address review comments
* Widen promo when no image defined
* Prevent flash of promo before query resolves
* Reduce top margin
* reduce size of text box to match latest figma
* update button style to match figma
* increase width at which we collapse sidenav
* add short versions of the headings
* remove skeletons from header
* avoid extra height
* adjustments for column alignment
* fix flaky test
* update tests for responsive text changes
* update changelog
* restore spacing between header items
* avoid occasional flash of promo on page load
* update text handling
* fix types and tests
* Update packages/app/src/specs/SpecsList.vue
Co-authored-by: Stokes Player <stokes@cypress.io>
* updated final e2e bullet
* fix question mark icon flashing
* text formatting
* remove superfluous snapshot [skip ci]
---------
Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: marktnoonan <mark@cypress.io>
Co-authored-by: astone123 <adams@cypress.io>
Co-authored-by: Stokes Player <stokes@cypress.io>
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
* chore: release internal-scripts-v1.0.0
[skip ci]
* chore: fix changelog links (#26948)
* chore: 12.14.0 release (#26950)
* chore: Update Chrome (stable) to 114.0.5735.106 and Chrome (beta) to 115.0.5790.13 (#26650)
* chore: bump cache version (#26952)
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
* chore: move release date (#26958)
* chore(deps): update dependency @antfu/utils to ^0.7.0 [security] (#26923)
* chore: fix base error styling (#26954)
* chore: remove low value percy snapshots (#26934)
* chore: remove low value percy snapshots
* chore: remove more low value percy snapshots [run ci]
* chore: remove more low value percy snapshots
* remove additional snapshots
* reduce snapshots
* fix types
---------
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
* chore: changelog updates (#26964)
* chore: stabilize side navigation bar during loading and switching testing types (#26953)
* fix: log video path if exists, regardless of compression (#26813)
* chore: print the video path whether or not compression is on or fails
* chore: fix video replacement regex
* chore: add bugfix entry
* feat: allow users to pass true to videoCompression config and only a… (#26810)
* chore: allow users to pass true to videoCompression config and only allow valudes 1-51 inclusively to be passed in
* run ci
* chore: allow zero to be option for CRF as we will coerve it to false and skip compression to have a lossless video, which has the same effect
* Update cli/CHANGELOG.md
* chore: update videoCompression types
* chore: update changelog
* Update cli/CHANGELOG.md
* Update cli/types/cypress.d.ts
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
* Update packages/config/src/validation.ts
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
* chore: update config snapshots
* Update packages/config/test/validation.spec.ts
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
* chore: add system test on videoCompression=true coersion
* chore: document 0 as being false and not a valid CRF option for cypress video compression and make CRF valid values 1-51
* chore: fix types
* chore: fix types
* chore: fix change to log as feature and not bugfix
* chore: fix server side unit tests
---------
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
* chore: trigger mac/linux/windows binary builds and v8 snapshot cache update tests
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
* chore: fix possible bad merge from mismatched snapshot in CLOUD_AUTO_CANCEL_MISMATCH test
* chore: fix possible bad merge from mismatched snapshot in record_spec system test
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
* chore: updating v8 snapshot cache
---------
Co-authored-by: Mike McCready <66998419+MikeMcC399@users.noreply.github.com>
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Adam Stone-Lord <adams@cypress.io>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Matt Schile <mschile@cypress.io>
Co-authored-by: Mahdi Khashan <58775404+mahdikhashan@users.noreply.github.com>
Co-authored-by: Mike Plummer <mike-plummer@users.noreply.github.com>
Co-authored-by: elevatebart <bart@cypress.io>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: cypress-bot[bot] <+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
Co-authored-by: Ben M <benm@cypress.io>
Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Stokes Player <stokes@cypress.io>
Co-authored-by: Mike Plummer <mikep@cypress.io>
Co-authored-by: Chris Breiding <chrisbreiding@users.noreply.github.com>
Co-authored-by: Luis Furtado <46112985+luis-furtado@users.noreply.github.com>
Co-authored-by: Matt Henkes <mjhenkes@gmail.com>
Co-authored-by: Brian Mann <brian.mann86@gmail.com>
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
Co-authored-by: Jordan <jordan@jpdesigning.com>
Co-authored-by: Stokes Player <stokes.player@gmail.com>
Co-authored-by: Dave Kasper <dave.m.kasper@gmail.com>
Co-authored-by: Mark Noonan <mark@cypress.io>
Co-authored-by: Ely Lucas <ely@meta-tek.net>
Co-authored-by: Snyk bot <snyk-bot@snyk.io>
Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
Co-authored-by: cypresschris <96069059+cypresschris@users.noreply.github.com>
Co-authored-by: brady-cypressio <90723145+brady-cypressio@users.noreply.github.com>
540 lines
16 KiB
TypeScript
540 lines
16 KiB
TypeScript
import _ from 'lodash'
|
|
import { blocked, cors } from '@packages/network'
|
|
import { InterceptRequest, SetMatchingRoutes } from '@packages/net-stubbing'
|
|
import { telemetry } from '@packages/telemetry'
|
|
import { isVerboseTelemetry as isVerbose } from '.'
|
|
import {
|
|
addCookieJarCookiesToRequest, getSameSiteContext, shouldAttachAndSetCookies,
|
|
} from './util/cookies'
|
|
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
|
|
const debug = null
|
|
|
|
export type RequestMiddleware = HttpMiddleware<{
|
|
outgoingReq: any
|
|
}>
|
|
|
|
const LogRequest: RequestMiddleware = function () {
|
|
this.debug('proxying request %o', {
|
|
req: _.pick(this.req, 'method', 'proxiedUrl', 'headers'),
|
|
})
|
|
|
|
this.next()
|
|
}
|
|
|
|
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']
|
|
const requestIsXhrOrFetch = this.req.headers['x-cypress-is-xhr-or-fetch']
|
|
|
|
span?.setAttributes({
|
|
isAUTFrame: this.req.isAUTFrame,
|
|
})
|
|
|
|
if (this.req.headers['x-cypress-is-aut-frame']) {
|
|
delete this.req.headers['x-cypress-is-aut-frame']
|
|
}
|
|
|
|
if (this.req.headers['x-cypress-is-xhr-or-fetch']) {
|
|
this.debug(`found x-cypress-is-xhr-or-fetch header. Deleting x-cypress-is-xhr-or-fetch header.`)
|
|
delete this.req.headers['x-cypress-is-xhr-or-fetch']
|
|
}
|
|
|
|
if (!doesTopNeedToBeSimulated(this) ||
|
|
// this should be unreachable, as the x-cypress-is-xhr-or-fetch header is only attached if
|
|
// the resource type is 'xhr' or 'fetch or 'true' (in the case of electron|extension).
|
|
// This is only needed for defensive purposes.
|
|
(requestIsXhrOrFetch !== 'true' && requestIsXhrOrFetch !== 'xhr' && requestIsXhrOrFetch !== 'fetch')) {
|
|
this.next()
|
|
|
|
return
|
|
}
|
|
|
|
this.debug(`looking up credentials for ${this.req.proxiedUrl}`)
|
|
const { requestedWith, credentialStatus } = this.requestedWithAndCredentialManager.get(this.req.proxiedUrl, requestIsXhrOrFetch !== 'true' ? requestIsXhrOrFetch : undefined)
|
|
|
|
this.debug(`credentials calculated for ${requestedWith}:${credentialStatus}`)
|
|
|
|
this.req.requestedWith = requestedWith
|
|
this.req.credentialsLevel = credentialStatus
|
|
|
|
span?.setAttributes({
|
|
calculatedResourceType: this.req.resourceType,
|
|
credentialsLevel: credentialStatus,
|
|
})
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const MaybeSimulateSecHeaders: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'maybe:simulate:sec:headers', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
span?.setAttributes({
|
|
experimentalModifyObstructiveThirdPartyCode: this.config.experimentalModifyObstructiveThirdPartyCode,
|
|
})
|
|
|
|
if (!this.config.experimentalModifyObstructiveThirdPartyCode) {
|
|
span?.end()
|
|
this.next()
|
|
|
|
return
|
|
}
|
|
|
|
// Do NOT disclose destination to an iframe and simulate if iframe was top
|
|
if (this.req.isAUTFrame && this.req.headers['sec-fetch-dest'] === 'iframe') {
|
|
const secFetchDestModifiedTo = 'document'
|
|
|
|
span?.setAttributes({
|
|
secFetchDestModifiedFrom: this.req.headers['sec-fetch-dest'],
|
|
secFetchDestModifiedTo,
|
|
})
|
|
|
|
this.req.headers['sec-fetch-dest'] = secFetchDestModifiedTo
|
|
}
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const MaybeAttachCrossOriginCookies: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'maybe:attach:cross:origin:cookies', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const doesTopNeedSimulation = doesTopNeedToBeSimulated(this)
|
|
|
|
span?.setAttributes({
|
|
doesTopNeedToBeSimulated: doesTopNeedSimulation,
|
|
resourceType: this.req.resourceType,
|
|
})
|
|
|
|
if (!doesTopNeedSimulation) {
|
|
span?.end()
|
|
|
|
return this.next()
|
|
}
|
|
|
|
// Top needs to be simulated since the AUT is in a cross origin state. Get the "requested with" and credentials and see what cookies need to be attached
|
|
const currentAUTUrl = this.getAUTUrl()
|
|
const shouldCookiesBeAttachedToRequest = shouldAttachAndSetCookies(this.req.proxiedUrl, currentAUTUrl, this.req.requestedWith, this.req.credentialsLevel, this.req.isAUTFrame)
|
|
|
|
span?.setAttributes({
|
|
currentAUTUrl,
|
|
shouldCookiesBeAttachedToRequest,
|
|
})
|
|
|
|
this.debug(`should cookies be attached to request?: ${shouldCookiesBeAttachedToRequest}`)
|
|
if (!shouldCookiesBeAttachedToRequest) {
|
|
span?.end()
|
|
|
|
return this.next()
|
|
}
|
|
|
|
const sameSiteContext = getSameSiteContext(
|
|
currentAUTUrl,
|
|
this.req.proxiedUrl,
|
|
this.req.isAUTFrame,
|
|
)
|
|
|
|
span?.setAttributes({
|
|
sameSiteContext,
|
|
currentAUTUrl,
|
|
isAUTFrame: this.req.isAUTFrame,
|
|
})
|
|
|
|
const applicableCookiesInCookieJar = this.getCookieJar().getCookies(this.req.proxiedUrl, sameSiteContext)
|
|
const cookiesOnRequest = (this.req.headers['cookie'] || '').split('; ')
|
|
|
|
const existingCookiesInJar = applicableCookiesInCookieJar.join('; ')
|
|
const addedCookiesFromHeader = cookiesOnRequest.join('; ')
|
|
|
|
this.debug('existing cookies on request from cookie jar: %s', existingCookiesInJar)
|
|
this.debug('add cookies to request from header: %s', addedCookiesFromHeader)
|
|
|
|
// if the cookie header is empty (i.e. ''), set it to undefined for expected behavior
|
|
this.req.headers['cookie'] = addCookieJarCookiesToRequest(applicableCookiesInCookieJar, cookiesOnRequest) || undefined
|
|
|
|
span?.setAttributes({
|
|
existingCookiesInJar,
|
|
addedCookiesFromHeader,
|
|
cookieHeader: this.req.headers['cookie'],
|
|
})
|
|
|
|
this.debug('cookies being sent with request: %s', this.req.headers['cookie'])
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const CorrelateBrowserPreRequest: RequestMiddleware = async function () {
|
|
const span = telemetry.startSpan({ name: 'correlate:prerequest', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const shouldCorrelatePreRequests = this.shouldCorrelatePreRequests()
|
|
|
|
span?.setAttributes({
|
|
shouldCorrelatePreRequest: shouldCorrelatePreRequests,
|
|
})
|
|
|
|
if (!this.shouldCorrelatePreRequests()) {
|
|
span?.end()
|
|
|
|
return this.next()
|
|
}
|
|
|
|
const copyResourceTypeAndNext = () => {
|
|
this.req.resourceType = this.req.browserPreRequest?.resourceType
|
|
|
|
span?.setAttributes({
|
|
resourceType: this.req.resourceType,
|
|
})
|
|
|
|
span?.end()
|
|
|
|
return this.next()
|
|
}
|
|
|
|
if (this.req.headers['x-cypress-resolving-url']) {
|
|
this.debug('skipping prerequest for resolve:url')
|
|
delete this.req.headers['x-cypress-resolving-url']
|
|
const requestId = `cy.visit-${Date.now()}`
|
|
|
|
this.req.browserPreRequest = {
|
|
requestId,
|
|
method: this.req.method,
|
|
url: this.req.proxiedUrl,
|
|
// @ts-ignore
|
|
headers: this.req.headers,
|
|
resourceType: 'document',
|
|
originalResourceType: 'document',
|
|
}
|
|
|
|
this.res.on('close', () => {
|
|
this.socket.toDriver('request:event', 'response:received', {
|
|
requestId,
|
|
headers: this.res.getHeaders(),
|
|
status: this.res.statusCode,
|
|
})
|
|
})
|
|
|
|
return copyResourceTypeAndNext()
|
|
}
|
|
|
|
this.debug('waiting for prerequest')
|
|
this.getPreRequest(((browserPreRequest) => {
|
|
this.req.browserPreRequest = browserPreRequest
|
|
copyResourceTypeAndNext()
|
|
}))
|
|
}
|
|
|
|
function shouldLog (req: CypressIncomingRequest) {
|
|
// 1. Any matching `cy.intercept()` should cause `req` to be logged by default, unless `log: false` is passed explicitly.
|
|
if (req.matchingRoutes?.length) {
|
|
const lastMatchingRoute = req.matchingRoutes[0]
|
|
|
|
if (!lastMatchingRoute.staticResponse) {
|
|
// No StaticResponse is set, therefore the request must be logged.
|
|
return true
|
|
}
|
|
|
|
if (lastMatchingRoute.staticResponse.log !== undefined) {
|
|
return Boolean(lastMatchingRoute.staticResponse.log)
|
|
}
|
|
}
|
|
|
|
// 2. Otherwise, only log if it is an XHR or fetch.
|
|
return req.resourceType === 'fetch' || req.resourceType === 'xhr'
|
|
}
|
|
|
|
const SendToDriver: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'send:to:driver', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const shouldLogReq = shouldLog(this.req)
|
|
|
|
if (shouldLogReq && this.req.browserPreRequest) {
|
|
this.socket.toDriver('request:event', 'incoming:request', this.req.browserPreRequest)
|
|
}
|
|
|
|
span?.setAttributes({
|
|
shouldLogReq,
|
|
hasBrowserPreRequest: !!this.req.browserPreRequest,
|
|
})
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const MaybeEndRequestWithBufferedResponse: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'maybe:end:with:buffered:response', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const buffer = this.buffers.take(this.req.proxiedUrl)
|
|
|
|
span?.setAttributes({
|
|
hasBuffer: !!buffer,
|
|
})
|
|
|
|
if (buffer) {
|
|
this.debug('ending request with buffered response')
|
|
|
|
// NOTE: Only inject fullCrossOrigin here if the super domain origins do not match in order to keep parity with cypress application reloads
|
|
this.res.wantsInjection = buffer.urlDoesNotMatchPolicyBasedOnDomain ? 'fullCrossOrigin' : 'full'
|
|
|
|
span?.setAttributes({
|
|
wantsInjection: this.res.wantsInjection,
|
|
})
|
|
|
|
span?.end()
|
|
this.reqMiddlewareSpan?.end()
|
|
|
|
return this.onResponse(buffer.response, buffer.stream)
|
|
}
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const RedirectToClientRouteIfUnloaded: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'redirect:to:client:route:if:unloaded', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const hasAppUnloaded = this.req.cookies['__cypress.unload']
|
|
|
|
span?.setAttributes({
|
|
hasAppUnloaded,
|
|
})
|
|
|
|
// if we have an unload header it means our parent app has been navigated away
|
|
// directly and we need to automatically redirect to the clientRoute
|
|
if (hasAppUnloaded) {
|
|
span?.setAttributes({
|
|
redirectedTo: this.config.clientRoute,
|
|
})
|
|
|
|
this.res.redirect(this.config.clientRoute)
|
|
|
|
span?.end()
|
|
|
|
return this.end()
|
|
}
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const EndRequestsToBlockedHosts: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'end:requests:to:block:hosts', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
const { blockHosts } = this.config
|
|
|
|
span?.setAttributes({
|
|
areBlockHostsConfigured: !!blockHosts,
|
|
})
|
|
|
|
if (blockHosts) {
|
|
const matches = blocked.matches(this.req.proxiedUrl, blockHosts)
|
|
|
|
span?.setAttributes({
|
|
didUrlMatchBlockedHosts: !!matches,
|
|
})
|
|
|
|
if (matches) {
|
|
this.res.set('x-cypress-matched-blocked-host', matches)
|
|
this.debug('blocking request %o', { matches })
|
|
|
|
this.res.status(503).end()
|
|
|
|
span?.end()
|
|
|
|
return this.end()
|
|
}
|
|
}
|
|
|
|
this.next()
|
|
}
|
|
|
|
const StripUnsupportedAcceptEncoding: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'strip:unsupported:accept:encoding', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
// Cypress can only support plaintext or gzip, so make sure we don't request anything else
|
|
const acceptEncoding = this.req.headers['accept-encoding']
|
|
|
|
span?.setAttributes({
|
|
acceptEncodingHeaderPresent: !!acceptEncoding,
|
|
})
|
|
|
|
if (acceptEncoding) {
|
|
const doesAcceptHeadingIncludeGzip = acceptEncoding.includes('gzip')
|
|
|
|
span?.setAttributes({
|
|
doesAcceptHeadingIncludeGzip,
|
|
})
|
|
|
|
if (doesAcceptHeadingIncludeGzip) {
|
|
this.req.headers['accept-encoding'] = 'gzip'
|
|
} else {
|
|
delete this.req.headers['accept-encoding']
|
|
}
|
|
}
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
function reqNeedsBasicAuthHeaders (req, { auth, origin }: Cypress.RemoteState) {
|
|
//if we have auth headers, this request matches our origin, protection space, and the user has not supplied auth headers
|
|
return auth && !req.headers['authorization'] && cors.urlMatchesOriginProtectionSpace(req.proxiedUrl, origin)
|
|
}
|
|
|
|
const MaybeSetBasicAuthHeaders: RequestMiddleware = function () {
|
|
const span = telemetry.startSpan({ name: 'maybe:set:basic:auth:headers', parentSpan: this.reqMiddlewareSpan, isVerbose })
|
|
|
|
// get the remote state for the proxied url
|
|
const remoteState = this.remoteStates.get(this.req.proxiedUrl)
|
|
|
|
const doesReqNeedBasicAuthHeaders = remoteState?.auth && reqNeedsBasicAuthHeaders(this.req, remoteState)
|
|
|
|
span?.setAttributes({
|
|
doesReqNeedBasicAuthHeaders,
|
|
})
|
|
|
|
if (remoteState?.auth && doesReqNeedBasicAuthHeaders) {
|
|
const { auth } = remoteState
|
|
const base64 = Buffer.from(`${auth.username}:${auth.password}`).toString('base64')
|
|
|
|
this.req.headers['authorization'] = `Basic ${base64}`
|
|
}
|
|
|
|
span?.end()
|
|
this.next()
|
|
}
|
|
|
|
const SendRequestOutgoing: RequestMiddleware = function () {
|
|
// end the request middleware span here before we make
|
|
// our outbound request so we can see that outside
|
|
// of the internal cypress middleware handlers
|
|
this.reqMiddlewareSpan?.end()
|
|
|
|
// the actual req/resp time outbound from the proxy server
|
|
const span = telemetry.startSpan({
|
|
name: 'outgoing:request:ttfb',
|
|
parentSpan: this.handleHttpRequestSpan,
|
|
isVerbose,
|
|
})
|
|
|
|
const requestOptions = {
|
|
browserPreRequest: this.req.browserPreRequest,
|
|
timeout: this.req.responseTimeout,
|
|
strictSSL: false,
|
|
followRedirect: this.req.followRedirect || false,
|
|
retryIntervals: [],
|
|
url: this.req.proxiedUrl,
|
|
time: !!span, // include timingPhases
|
|
}
|
|
|
|
const requestBodyBuffered = !!this.req.body
|
|
|
|
const { strategy, origin, fileServer } = this.remoteStates.current()
|
|
|
|
span?.setAttributes({
|
|
requestBodyBuffered,
|
|
strategy,
|
|
})
|
|
|
|
if (strategy === 'file' && requestOptions.url.startsWith(origin)) {
|
|
this.req.headers['x-cypress-authorization'] = this.getFileServerToken()
|
|
|
|
requestOptions.url = requestOptions.url.replace(origin, fileServer as string)
|
|
}
|
|
|
|
if (requestBodyBuffered) {
|
|
_.assign(requestOptions, _.pick(this.req, 'method', 'body', 'headers'))
|
|
}
|
|
|
|
const req = this.request.create(requestOptions)
|
|
const socket = this.req.socket
|
|
|
|
const onSocketClose = () => {
|
|
this.debug('request aborted')
|
|
// if the request is aborted, close out the middleware span and http span. the response middleware did not run
|
|
|
|
this.reqMiddlewareSpan?.setAttributes({
|
|
requestAborted: true,
|
|
})
|
|
|
|
this.reqMiddlewareSpan?.end()
|
|
this.handleHttpRequestSpan?.end()
|
|
|
|
req.abort()
|
|
}
|
|
|
|
req.on('error', this.onError)
|
|
req.on('response', (incomingRes) => {
|
|
if (span) {
|
|
const { timings } = incomingRes.request
|
|
|
|
if (!timings.socket) {
|
|
timings.socket = 0
|
|
}
|
|
|
|
if (!timings.lookup) {
|
|
timings.lookup = timings.socket
|
|
}
|
|
|
|
if (!timings.connect) {
|
|
timings.connect = timings.lookup
|
|
}
|
|
|
|
if (!timings.response) {
|
|
timings.response = timings.connect
|
|
}
|
|
|
|
span.setAttributes({
|
|
'request.timing.socket': timings.socket,
|
|
'request.timing.dns': timings.lookup - timings.socket,
|
|
'request.timing.tcp': timings.connect - timings.lookup,
|
|
'request.timing.firstByte': timings.response - timings.connect,
|
|
'request.timing.totalUntilFirstByte': timings.response,
|
|
// download and total are not available yet
|
|
})
|
|
|
|
span.end()
|
|
}
|
|
|
|
this.onResponse(incomingRes, req)
|
|
})
|
|
|
|
// NOTE: this is an odd place to remove this listener
|
|
this.req.res?.on('finish', () => {
|
|
socket.removeListener('close', onSocketClose)
|
|
})
|
|
|
|
this.req.socket.on('close', onSocketClose)
|
|
|
|
if (!requestBodyBuffered) {
|
|
// pipe incoming request body, headers to new request
|
|
this.req.pipe(req)
|
|
}
|
|
|
|
this.outgoingReq = req
|
|
}
|
|
|
|
export default {
|
|
LogRequest,
|
|
ExtractCypressMetadataHeaders,
|
|
MaybeSimulateSecHeaders,
|
|
MaybeAttachCrossOriginCookies,
|
|
MaybeEndRequestWithBufferedResponse,
|
|
CorrelateBrowserPreRequest,
|
|
SetMatchingRoutes,
|
|
SendToDriver,
|
|
InterceptRequest,
|
|
RedirectToClientRouteIfUnloaded,
|
|
EndRequestsToBlockedHosts,
|
|
StripUnsupportedAcceptEncoding,
|
|
MaybeSetBasicAuthHeaders,
|
|
SendRequestOutgoing,
|
|
}
|