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

Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
Co-authored-by: Bill Glesias <bglesias@gmail.com>
This commit is contained in:
Austin Bourgerie
2023-03-27 11:47:43 -04:00
committed by GitHub
parent 5f48d3cc25
commit 2452dee969
5 changed files with 102 additions and 1 deletions

View File

@@ -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).
**Misc:**

View File

@@ -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()
})
})
})
})

View File

@@ -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>`)
})

View File

@@ -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)
}

View File

@@ -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
})
})
})