From c9062f145ee00e7c6ee98c8c8949849dbf525e6d Mon Sep 17 00:00:00 2001 From: Matt Schile Date: Thu, 14 Dec 2023 09:12:13 -0700 Subject: [PATCH] fix: handle malformed URIs in prerequests (#28522) --- .vscode/settings.json | 2 +- cli/CHANGELOG.md | 1 + packages/proxy/lib/http/util/prerequests.ts | 16 ++++++++-- .../test/integration/http_requests_spec.js | 29 +++++++++++++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4b221598aa42..3e90e64819c5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,7 +19,7 @@ "json" ], "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "typescript.tsdk": "node_modules/typescript/lib", diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 1a6cac0810c1..9212ccc1267f 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,6 +5,7 @@ _Released 12/19/2023 (PENDING)_ **Bugfixes:** +- Fixed a regression in [`13.6.1`](https://docs.cypress.io/guides/references/changelog/13.6.1) where a malformed URI would crash Cypress. Fixes [#28521](https://github.com/cypress-io/cypress/issues/28521). - Fixed a regression in [`12.4.0`](https://docs.cypress.io/guides/references/changelog/12.4.0) where erroneous `
` tags were displaying in error messages in the Command Log making them less readable. Fixes [#28452](https://github.com/cypress-io/cypress/issues/28452). ## 13.6.1 diff --git a/packages/proxy/lib/http/util/prerequests.ts b/packages/proxy/lib/http/util/prerequests.ts index 86b2cd7f9f30..8cb6db9e68aa 100644 --- a/packages/proxy/lib/http/util/prerequests.ts +++ b/packages/proxy/lib/http/util/prerequests.ts @@ -94,6 +94,16 @@ class QueueMap { } } +const tryDecodeURI = (url: string) => { + // decodeURI can throw if the url is malformed + // in this case, we just return the original url + try { + return decodeURI(url) + } catch (e) { + return url + } +} + // This class' purpose is to match up incoming "requests" (requests from the browser received by the http proxy) // with "pre-requests" (events received by our browser extension indicating that the browser is about to make a request). // Because these come from different sources, they can be out of sync, arriving in either order. @@ -148,7 +158,7 @@ export class PreRequests { addPending (browserPreRequest: BrowserPreRequest) { metrics.browserPreRequestsReceived++ - const key = `${browserPreRequest.method}-${decodeURI(browserPreRequest.url)}` + const key = `${browserPreRequest.method}-${tryDecodeURI(browserPreRequest.url)}` const pendingRequest = this.pendingRequests.shift(key) if (pendingRequest) { @@ -193,7 +203,7 @@ export class PreRequests { } addPendingUrlWithoutPreRequest (url: string) { - const key = `GET-${decodeURI(url)}` + const key = `GET-${tryDecodeURI(url)}` const pendingRequest = this.pendingRequests.shift(key) if (pendingRequest) { @@ -236,7 +246,7 @@ export class PreRequests { const proxyRequestReceivedTimestamp = performance.now() + performance.timeOrigin metrics.proxyRequestsReceived++ - const key = `${req.method}-${decodeURI(req.proxiedUrl)}` + const key = `${req.method}-${tryDecodeURI(req.proxiedUrl)}` const pendingPreRequest = this.pendingPreRequests.shift(key) if (pendingPreRequest) { diff --git a/packages/server/test/integration/http_requests_spec.js b/packages/server/test/integration/http_requests_spec.js index a41df8146216..9662d99c2a2c 100644 --- a/packages/server/test/integration/http_requests_spec.js +++ b/packages/server/test/integration/http_requests_spec.js @@ -1230,6 +1230,35 @@ describe('Routes', () => { expect(res.body).to.include('hello from bar!') }) }) + + it('handles malformed URIs', function () { + this.timeout(1500) + + nock(this.server.remoteStates.current().origin) + .get('/?foo=%A4') + .reply(200, 'hello from bar!', { + 'Content-Type': 'text/html', + }) + + const requestPromise = this.rp({ + url: 'http://www.github.com/?foo=%A4', + headers: { + 'Accept-Encoding': 'identity', + }, + }) + + this.networkProxy.addPendingBrowserPreRequest({ + requestId: '1', + method: 'GET', + url: 'http://www.github.com/?foo=%A4', + }) + + return requestPromise.then((res) => { + expect(res.statusCode).to.eq(200) + + expect(res.body).to.include('hello from bar!') + }) + }) }) context('gzip', () => {