diff --git a/packages/database/CHANGELOG.md b/packages/database/CHANGELOG.md index d2d6d5b62a0..19219c0d2db 100644 --- a/packages/database/CHANGELOG.md +++ b/packages/database/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - [feature] Added ServerValue.increment() to support atomic field value increments without transactions. +- [fixed] Fixed Realtime Database URL parsing bug to support domains with more than 3 components. # Released - [fixed] Fixed an issue that caused large numeric values with leading zeros to diff --git a/packages/database/src/core/util/libs/parser.ts b/packages/database/src/core/util/libs/parser.ts index bb789c08fb7..0ef62fd11ba 100644 --- a/packages/database/src/core/util/libs/parser.ts +++ b/packages/database/src/core/util/libs/parser.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2017 Google Inc. + * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,7 +72,7 @@ export const parseRepoInfo = function( const parsedUrl = parseDatabaseURL(dataURL), namespace = parsedUrl.namespace; - if (parsedUrl.domain === 'firebase') { + if (parsedUrl.domain === 'firebase.com') { fatal( parsedUrl.host + ' is no longer supported. ' + @@ -171,20 +171,21 @@ export const parseDatabaseURL = function( secure = scheme === 'https' || scheme === 'wss'; port = parseInt(host.substring(colonInd + 1), 10); } else { - colonInd = dataURL.length; + colonInd = host.length; } - const parts = host.split('.'); - if (parts.length === 3) { + const hostWithoutPort = host.slice(0, colonInd); + if (hostWithoutPort.toLowerCase() === 'localhost') { + domain = 'localhost'; + } else if (hostWithoutPort.split('.').length <= 2) { + domain = hostWithoutPort; + } else { + // Interpret the subdomain of a 3 or more component URL as the namespace name. + const dotInd = host.indexOf('.'); + subdomain = host.substring(0, dotInd).toLowerCase(); + domain = host.substring(dotInd + 1); // Normalize namespaces to lowercase to share storage / connection. - domain = parts[1]; - subdomain = parts[0].toLowerCase(); - // We interpret the subdomain of a 3 component URL as the namespace name. namespace = subdomain; - } else if (parts.length === 2) { - domain = parts[0]; - } else if (parts[0].slice(0, colonInd).toLowerCase() === 'localhost') { - domain = 'localhost'; } // Always treat the value of the `ns` as the namespace name if it is present. if ('ns' in queryParams) { diff --git a/packages/database/test/database.test.ts b/packages/database/test/database.test.ts index 0cc9f6c9d83..1187032eb32 100644 --- a/packages/database/test/database.test.ts +++ b/packages/database/test/database.test.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2017 Google Inc. + * Copyright 2017 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -62,18 +62,49 @@ describe('Database Tests', () => { expect(db.ref().toString()).to.equal('https://foo.bar.com/'); }); + it('Can get database with multi-region URL', () => { + const db = defaultApp.database('http://foo.euw1.firebasedatabase.app'); + expect(db).to.be.ok; + expect(db.repo_.repoInfo_.namespace).to.equal('foo'); + expect(db.ref().toString()).to.equal( + 'https://foo.euw1.firebasedatabase.app/' + ); + }); + + it('Can get database with upper case URL', () => { + const db = defaultApp.database('http://fOO.EUW1.firebaseDATABASE.app'); + expect(db).to.be.ok; + expect(db.repo_.repoInfo_.namespace).to.equal('foo'); + expect(db.ref().toString()).to.equal( + 'https://foo.euw1.firebasedatabase.app/' + ); + }); + + it('Can get database with localhost URL', () => { + const db = defaultApp.database('http://localhost'); + expect(db).to.be.ok; + expect(db.ref().toString()).to.equal('https://localhost/'); + }); + it('Can get database with localhost URL and port', () => { const db = defaultApp.database('http://localhost:80'); expect(db).to.be.ok; expect(db.ref().toString()).to.equal('http://localhost:80/'); }); - it('Can get database with localhost URL', () => { - const db = defaultApp.database('http://localhost'); + it('Can get database with a upper case localhost URL', () => { + const db = defaultApp.database('http://LOCALHOST'); expect(db).to.be.ok; expect(db.ref().toString()).to.equal('https://localhost/'); }); + it('Can get database with a upper case localhost URL and ns', () => { + const db = defaultApp.database('http://LOCALHOST?ns=foo'); + expect(db).to.be.ok; + expect(db.repo_.repoInfo_.namespace).to.equal('foo'); + expect(db.ref().toString()).to.equal('https://localhost/'); + }); + it('Can read ns query param', () => { const db = defaultApp.database('http://localhost:80/?ns=foo&unused=true'); expect(db).to.be.ok; @@ -111,10 +142,19 @@ describe('Database Tests', () => { }).to.throw(/Database initialized multiple times/i); }); + it('Databases with legacy domain', () => { + expect(() => { + defaultApp.database('http://foo.firebase.com/'); + }).to.throw(/is no longer supported/i); + }); + it('Databases with invalid custom URLs', () => { expect(() => { defaultApp.database('not-a-url'); }).to.throw(/Cannot parse Firebase url/i); + expect(() => { + defaultApp.database('http://foo.com'); + }).to.throw(/Cannot parse Firebase url/i); expect(() => { defaultApp.database('http://fblocal.com'); }).to.throw(/Cannot parse Firebase url/i);