From d035ea0107a6954dbdfb2692042ecbb9fb1bdfc4 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 09:37:02 -0700 Subject: [PATCH 1/7] Fixed issue where storage wasn't passing cookies when using firebase studio --- packages/storage/src/platform/browser/connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/storage/src/platform/browser/connection.ts b/packages/storage/src/platform/browser/connection.ts index 77a2e42809b..3469ad8d16c 100644 --- a/packages/storage/src/platform/browser/connection.ts +++ b/packages/storage/src/platform/browser/connection.ts @@ -70,7 +70,7 @@ abstract class XhrConnection if (this.sent_) { throw internalError('cannot .send() more than once'); } - if (isCloudWorkstation(url) && isUsingEmulator) { + if (isCloudWorkstation(new URL(url).hostname) && isUsingEmulator) { this.xhr_.withCredentials = true; } this.sent_ = true; From d0f56900e49fbbb9bb6f0c17c3589e512f5b5082 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 09:39:43 -0700 Subject: [PATCH 2/7] Fixed test --- packages/storage/test/browser/connection.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/storage/test/browser/connection.test.ts b/packages/storage/test/browser/connection.test.ts index 2a0320d0c02..ccac8816151 100644 --- a/packages/storage/test/browser/connection.test.ts +++ b/packages/storage/test/browser/connection.test.ts @@ -20,7 +20,7 @@ import { SinonFakeXMLHttpRequest, useFakeXMLHttpRequest } from 'sinon'; import { ErrorCode } from '../../src/implementation/connection'; import { XhrBytesConnection } from '../../src/platform/browser/connection'; -describe('Connections', () => { +describe.only('Connections', () => { it('XhrConnection.send() should not reject on network errors', async () => { const fakeXHR = useFakeXMLHttpRequest(); const connection = new XhrBytesConnection(); @@ -31,11 +31,11 @@ describe('Connections', () => { expect(connection.getErrorCode()).to.equal(ErrorCode.NETWORK_ERROR); fakeXHR.restore(); }); - it('XhrConnection.send() should send credentials when using cloud workstation', async () => { + it.only('XhrConnection.send() should send credentials when using cloud workstation', async () => { const fakeXHR = useFakeXMLHttpRequest(); const connection = new XhrBytesConnection(); const sendPromise = connection.send( - 'https://abc.cloudworkstations.dev', + 'https://abc.cloudworkstations.dev/test', 'GET', true ); From e3c6171e67f2aa90ed8644f1b306610288dc0c62 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 09:40:18 -0700 Subject: [PATCH 3/7] Create brown-pens-confess.md --- .changeset/brown-pens-confess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/brown-pens-confess.md diff --git a/.changeset/brown-pens-confess.md b/.changeset/brown-pens-confess.md new file mode 100644 index 00000000000..23463d367b9 --- /dev/null +++ b/.changeset/brown-pens-confess.md @@ -0,0 +1,5 @@ +--- +"@firebase/storage": patch +--- + +Fixed issue where Storage on Firebase Studio throws CORS errors. From 2151b75033a62cf0ff7a714b0e4bdf159da21ce2 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 09:56:05 -0700 Subject: [PATCH 4/7] Removed onlys --- packages/storage/test/browser/connection.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/storage/test/browser/connection.test.ts b/packages/storage/test/browser/connection.test.ts index ccac8816151..4cb4d4cb919 100644 --- a/packages/storage/test/browser/connection.test.ts +++ b/packages/storage/test/browser/connection.test.ts @@ -20,7 +20,7 @@ import { SinonFakeXMLHttpRequest, useFakeXMLHttpRequest } from 'sinon'; import { ErrorCode } from '../../src/implementation/connection'; import { XhrBytesConnection } from '../../src/platform/browser/connection'; -describe.only('Connections', () => { +describe('Connections', () => { it('XhrConnection.send() should not reject on network errors', async () => { const fakeXHR = useFakeXMLHttpRequest(); const connection = new XhrBytesConnection(); @@ -31,7 +31,7 @@ describe.only('Connections', () => { expect(connection.getErrorCode()).to.equal(ErrorCode.NETWORK_ERROR); fakeXHR.restore(); }); - it.only('XhrConnection.send() should send credentials when using cloud workstation', async () => { + it('XhrConnection.send() should send credentials when using cloud workstation', async () => { const fakeXHR = useFakeXMLHttpRequest(); const connection = new XhrBytesConnection(); const sendPromise = connection.send( From b68d8b1bb6a7fbcb15f79c36c5f6bca69a85b4c8 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 11:58:08 -0700 Subject: [PATCH 5/7] Updated firebase/util to check for hostname --- .changeset/brown-pens-confess.md | 1 + common/api-review/util.api.md | 2 +- packages/storage/src/platform/browser/connection.ts | 2 +- packages/util/src/url.ts | 6 +++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.changeset/brown-pens-confess.md b/.changeset/brown-pens-confess.md index 23463d367b9..038b177796e 100644 --- a/.changeset/brown-pens-confess.md +++ b/.changeset/brown-pens-confess.md @@ -1,5 +1,6 @@ --- "@firebase/storage": patch +"@firebase/util": patch --- Fixed issue where Storage on Firebase Studio throws CORS errors. diff --git a/common/api-review/util.api.md b/common/api-review/util.api.md index f263f450da3..4ac51fda550 100644 --- a/common/api-review/util.api.md +++ b/common/api-review/util.api.md @@ -270,7 +270,7 @@ export function isBrowserExtension(): boolean; export function isCloudflareWorker(): boolean; // @public -export function isCloudWorkstation(host: string): boolean; +export function isCloudWorkstation(url: string): boolean; // Warning: (ae-missing-release-tag) "isElectron" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/storage/src/platform/browser/connection.ts b/packages/storage/src/platform/browser/connection.ts index 3469ad8d16c..77a2e42809b 100644 --- a/packages/storage/src/platform/browser/connection.ts +++ b/packages/storage/src/platform/browser/connection.ts @@ -70,7 +70,7 @@ abstract class XhrConnection if (this.sent_) { throw internalError('cannot .send() more than once'); } - if (isCloudWorkstation(new URL(url).hostname) && isUsingEmulator) { + if (isCloudWorkstation(url) && isUsingEmulator) { this.xhr_.withCredentials = true; } this.sent_ = true; diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts index e41d26594c2..0d2b9ad6034 100644 --- a/packages/util/src/url.ts +++ b/packages/util/src/url.ts @@ -19,7 +19,11 @@ * Checks whether host is a cloud workstation or not. * @public */ -export function isCloudWorkstation(host: string): boolean { +export function isCloudWorkstation(url: string): boolean { + const host = + url.startsWith('http://') || url.startsWith('https://') + ? new URL(url).hostname + : url; return host.endsWith('.cloudworkstations.dev'); } From 0e5af66d9f43a5bce376caa8c5a876b01e38f85a Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 12:00:43 -0700 Subject: [PATCH 6/7] added comments' --- packages/util/src/url.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts index 0d2b9ad6034..27db6f0a79e 100644 --- a/packages/util/src/url.ts +++ b/packages/util/src/url.ts @@ -20,6 +20,10 @@ * @public */ export function isCloudWorkstation(url: string): boolean { + // `isCloudWorkstation` is called without protocol in certain connect*Emulator functions + // In HTTP request builders, it's called with the protocol. + // If called with protocol prefix, it's a valid URL, so we extract the hostname + // If called without, we assume the string is the hostname. const host = url.startsWith('http://') || url.startsWith('https://') ? new URL(url).hostname From 0baef5e42807ce323c43b5d42e1220f0174233c8 Mon Sep 17 00:00:00 2001 From: Maneesh Tewani Date: Fri, 20 Jun 2025 12:50:13 -0700 Subject: [PATCH 7/7] Added a try catch just in case new URL throws --- packages/util/src/url.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/util/src/url.ts b/packages/util/src/url.ts index 27db6f0a79e..6de92584979 100644 --- a/packages/util/src/url.ts +++ b/packages/util/src/url.ts @@ -24,11 +24,15 @@ export function isCloudWorkstation(url: string): boolean { // In HTTP request builders, it's called with the protocol. // If called with protocol prefix, it's a valid URL, so we extract the hostname // If called without, we assume the string is the hostname. - const host = - url.startsWith('http://') || url.startsWith('https://') - ? new URL(url).hostname - : url; - return host.endsWith('.cloudworkstations.dev'); + try { + const host = + url.startsWith('http://') || url.startsWith('https://') + ? new URL(url).hostname + : url; + return host.endsWith('.cloudworkstations.dev'); + } catch { + return false; + } } /**