Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: only update content-length header if one was present in spy #25920

Merged
merged 13 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ _Released 03/28/2023 (PENDING)_

- Fixed a compatibility issue so that component test projects can use [Vite](https://vitejs.dev/) version 4.2.0 and greater. Fixes [#26138](https://github.com/cypress-io/cypress/issues/26138).
- Changed the way that Git hashes are loaded so that non-relevant runs are excluded from the Debug page. Fixes [#26058](https://github.com/cypress-io/cypress/issues/26058).
- Fixed an issue where [`cy.intercept()`](https://docs.cypress.io/api/commands/intercept) added an additional `content-length` header to spied requests that did not set a `content-length` header on the original request. Fixes [#24407](https://github.com/cypress-io/cypress/issues/24407).
AtofStryker marked this conversation as resolved.
Show resolved Hide resolved

**Misc:**

Expand Down
16 changes: 16 additions & 0 deletions packages/driver/cypress/e2e/commands/net_stubbing.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2627,6 +2627,22 @@ describe('network stubbing', { retries: 15 }, function () {
$.post('/post-only', 'baz')
})
})

// @see https://github.com/cypress-io/cypress/issues/24407
it('does not calculate content-length on spied request if one does not exist on the initial request (if merging)', { retries: 0 }, function (done) {
cy.intercept('/verify-content-length-is-absent*', function (req) {
// modify the intercepted request to trigger a request merge in net_stubbing
req.headers['foo'] = 'bar'
// send the modified request and skip any other
// matching request handlers
req.continue()
}).then(async () => {
const isContentLengthHeaderAbsent = await $.get('/verify-content-length-is-absent')

expect(isContentLengthHeaderAbsent).to.be.true
done()
})
})
})
})

Expand Down
4 changes: 4 additions & 0 deletions packages/driver/cypress/plugins/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ const createApp = (port) => {
return res.send(`<html><body>it worked!<br>request body:<br>${JSON.stringify(req.body)}</body></html>`)
})

app.get('/verify-content-length-is-absent', (req, res) => {
return res.send(req.headers['content-length'] === undefined)
})

app.get('/dump-headers', (req, res) => {
return res.send(`<html><body>request headers:<br>${JSON.stringify(req.headers)}</body></html>`)
})
Expand Down
2 changes: 1 addition & 1 deletion packages/net-stubbing/lib/server/middleware/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export const InterceptRequest: RequestMiddleware = async function () {
request.req.body = req.body

const mergeChanges = (before: CyHttpMessages.IncomingRequest, after: CyHttpMessages.IncomingRequest) => {
if (before.headers['content-length'] === after.headers['content-length']) {
if ('content-length' in before.headers && before.headers['content-length'] === after.headers['content-length']) {
// user did not purposely override content-length, let's set it
after.headers['content-length'] = String(Buffer.from(after.body).byteLength)
}
Expand Down
80 changes: 80 additions & 0 deletions packages/net-stubbing/test/unit/middleware-request-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { expect } from 'chai'
import sinon from 'sinon'
import { InterceptRequest } from '../../lib/server/middleware/request'
import { state as NetStubbingState } from '../../lib/server/state'

describe('request', () => {
context('InterceptedRequest', () => {
// @see https://github.com/cypress-io/cypress/issues/24407
it('does not set the content-length header if the header was not there to begin with on the original request', async () => {
const socket = {
toDriver: sinon.stub(),
}
const state = NetStubbingState()

const beforeRequestData = {
body: 'stubbed_body',
proxiedUrl: 'https://foobar.com',
url: 'https://foobar.com',
}

const afterRequestData = {
...beforeRequestData,
body: '',
headers: {},
}

// using a ES6 proxy to intercept the promise assignment on pendingEventHandlers.
// this way, we can resolve the event immediately
const pendingEventProxy = new Proxy(state.pendingEventHandlers, {
get (target, prop, receiver) {
// @ts-expect-error
return Reflect.get(...arguments)
},
set (obj, prop, value) {
// @ts-expect-error
const setProp = Reflect.set(...arguments)

// invoke the promise function immediately
if (typeof value === 'function') {
value({
changedData: afterRequestData,
stopPropagation: false,
})
}

return setProp
},
})

state.pendingEventHandlers = pendingEventProxy

const request = {
req: {
...beforeRequestData,
headers: {},
matchingRoutes: [
{
id: '1',
hasInterceptor: true,
routeMatcher: {},
},
],
pipe: sinon.stub(),
},
res: {
once: sinon.stub(),
},
socket,
debug: sinon.stub(),
netStubbingState: state,
next: sinon.stub(),
onError: sinon.stub(),
onResponse: sinon.stub(),
}

await InterceptRequest.call(request)
expect(request.req.headers['content-length']).to.be.undefined
})
})
})