diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 7e4a0fe01f45..0724e43ebce2 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -8,6 +8,7 @@ _Released 5/21/2024 (PENDING)_ - Fixed an issue where orphaned Electron processes were inadvertently terminating the browser's CRI client. Fixes [#28397](https://github.com/cypress-io/cypress/issues/28397). Fixed in [#29515](https://github.com/cypress-io/cypress/pull/29515). - Fixed an issue where Cypress would use the wrong URL to upload Test Replay recordings when it wasn't able to determine the upload URL. It now displays an error when the upload URL cannot be determined, rather than a "Request Entity Too Large" error. Addressed in [#29512](https://github.com/cypress-io/cypress/pull/29512). - Fixed an issue where Cypress was unable to search in the Specs list for files or folders containing numbers. Fixes [#29034](https://github.com/cypress-io/cypress/issues/29034). +- Fixed an issue setting the `x-cypress-file-path` header when there are invalid header characters in the file path. Fixes [#25839](https://github.com/cypress-io/cypress/issues/25839). - Fixed the display of some command assertions. Fixed in [#29517](https://github.com/cypress-io/cypress/pull/29517). **Dependency Updates:** diff --git a/packages/server/lib/file_server.js b/packages/server/lib/file_server.js index da04be9c4ee4..ca5bcb5dd60f 100644 --- a/packages/server/lib/file_server.js +++ b/packages/server/lib/file_server.js @@ -34,7 +34,7 @@ const onRequest = function (req, res, expectedToken, fileServerFolder) { // %20 with white space const file = decodeURI(url.parse(path.join(...args)).pathname) - res.setHeader('x-cypress-file-path', file) + res.setHeader('x-cypress-file-path', encodeURI(file)) return send(req, url.parse(req.url).pathname, { root: path.resolve(fileServerFolder), diff --git a/packages/server/lib/server-base.ts b/packages/server/lib/server-base.ts index 01df2eae3696..b9f6b78bf004 100644 --- a/packages/server/lib/server-base.ts +++ b/packages/server/lib/server-base.ts @@ -880,7 +880,7 @@ export class ServerBase { if (fp) { // if so we know this is a local file request - details.filePath = fp + details.filePath = decodeURI(fp) } debug('setting details resolving url %o', details) diff --git a/packages/server/test/integration/http_requests_spec.js b/packages/server/test/integration/http_requests_spec.js index 9662d99c2a2c..229574dd2be2 100644 --- a/packages/server/test/integration/http_requests_spec.js +++ b/packages/server/test/integration/http_requests_spec.js @@ -3851,13 +3851,13 @@ describe('Routes', () => { }) context('file requests', () => { - beforeEach(function () { + function setupProject ({ fileServerFolder }) { Fixtures.scaffold() return this.setup('/index.html', { projectRoot: Fixtures.projectPath('no-server'), config: { - fileServerFolder: 'dev', + fileServerFolder, specPattern: 'my-tests/**/*', supportFile: false, }, @@ -3883,6 +3883,12 @@ describe('Routes', () => { expect(res.headers['last-modified']).to.exist }) }) + } + + beforeEach(function () { + this.setupProject = setupProject.bind(this) + + return this.setupProject({ fileServerFolder: 'dev' }) }) it('sets etag', function () { @@ -3953,7 +3959,23 @@ describe('Routes', () => { }) .then((res) => { expect(res.statusCode).to.eq(200) + expect(res.headers).to.have.property('x-cypress-file-path', encodeURI(`${Fixtures.projectPath('no-server')}/dev/a space/foo.txt`)) + expect(res.body).to.eq('foo') + }) + }) + it('can serve files with special characters in the fileServerFolder path', async function () { + await this.setupProject({ fileServerFolder: `dev/_ :;.,"'!(){}[]@<>=-+*$&\`|~^ĵ符` }) + + return this.rp({ + url: `${this.proxy}/foo.txt`, + headers: { + 'Accept-Encoding': 'identity', + }, + }) + .then((res) => { + expect(res.statusCode).to.eq(200) + expect(res.headers).to.have.property('x-cypress-file-path', encodeURI(`${Fixtures.projectPath('no-server')}/dev/_ :;.,"'!(){}[]@<>=-+*$&\`|~^ĵ符/foo.txt`)) expect(res.body).to.eq('foo') }) }) diff --git a/packages/server/test/unit/config_spec.js b/packages/server/test/unit/config_spec.js index 69ead5c1a0f4..ed61141ae684 100644 --- a/packages/server/test/unit/config_spec.js +++ b/packages/server/test/unit/config_spec.js @@ -368,6 +368,12 @@ describe('lib/config', () => { return this.expectValidationFails('the value was: true') }) }) + + it('passes if a string contains encoded special characters', function () { + this.setup({ fileServerFolder: encodeURI('/specialCharacters/无法解析的特殊字符') }) + + return this.expectValidationPasses() + }) }) context('fixturesFolder', () => { diff --git "a/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/foo.txt" "b/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/foo.txt" new file mode 100644 index 000000000000..19102815663d --- /dev/null +++ "b/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/foo.txt" @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git "a/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/index.html" "b/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/index.html" new file mode 100644 index 000000000000..96fb9b796268 --- /dev/null +++ "b/system-tests/projects/no-server/dev/_ :;.,\"'!(){}[]@<>=-+*$&`|~^\304\265\347\254\246/index.html" @@ -0,0 +1,7 @@ + + + + + index.html content + +