diff --git a/front_end/sdk/Cookie.js b/front_end/sdk/Cookie.js index 9051a129df..796171e43e 100644 --- a/front_end/sdk/Cookie.js +++ b/front_end/sdk/Cookie.js @@ -219,6 +219,57 @@ export class Cookie { getCookieLine() { return this._cookieLine; } + + /** + * @param {string} securityOrigin + * @returns {boolean} + */ + matchesSecurityOrigin(securityOrigin) { + const hostname = new URL(securityOrigin).hostname; + return Cookie.isDomainMatch(this.domain(), hostname); + } + + /** + * @param {string} domain + * @param {string} hostname + * @returns {boolean} + */ + static isDomainMatch(domain, hostname) { + // This implementation mirrors + // https://source.chromium.org/search?q=net::cookie_util::IsDomainMatch() + // + // Can domain match in two ways; as a domain cookie (where the cookie + // domain begins with ".") or as a host cookie (where it doesn't). + + // Some consumers of the CookieMonster expect to set cookies on + // URLs like http://.strange.url. To retrieve cookies in this instance, + // we allow matching as a host cookie even when the domain_ starts with + // a period. + if (hostname === domain) { + return true; + } + + // Domain cookie must have an initial ".". To match, it must be + // equal to url's host with initial period removed, or a suffix of + // it. + + // Arguably this should only apply to "http" or "https" cookies, but + // extension cookie tests currently use the funtionality, and if we + // ever decide to implement that it should be done by preventing + // such cookies from being set. + if (!domain || domain[0] !== '.') { + return false; + } + + // The host with a "." prefixed. + if (domain.substr(1) === hostname) { + return true; + } + + // A pure suffix of the host (ok since we know the domain already + // starts with a ".") + return hostname.length > domain.length && hostname.endsWith(domain); + } } /** diff --git a/front_end/sdk/CookieModel.js b/front_end/sdk/CookieModel.js index c3c1b0b9cf..e10e031d9b 100644 --- a/front_end/sdk/CookieModel.js +++ b/front_end/sdk/CookieModel.js @@ -69,7 +69,7 @@ export class CookieModel extends SDKModel { const cookies = await this.getCookiesForDomain(domain || null); if (securityOrigin) { const cookiesToDelete = cookies.filter(cookie => { - return securityOrigin.endsWith(cookie.domain()); + return cookie.matchesSecurityOrigin(securityOrigin); }); await this.deleteCookies(cookiesToDelete); } else { diff --git a/test/e2e/application/storage_test.ts b/test/e2e/application/storage_test.ts index 98fa18e111..76140fff43 100644 --- a/test/e2e/application/storage_test.ts +++ b/test/e2e/application/storage_test.ts @@ -38,7 +38,6 @@ describe('The Application Tab', async () => { return data.length ? data : undefined; }); - assert.sameDeepMembers(dataGridRowValuesBefore, [ { name: 'third_party', diff --git a/test/e2e/resources/application/cross-origin-cookies.html b/test/e2e/resources/application/cross-origin-cookies.html index fcecf2eb79..adf40ad47c 100644 --- a/test/e2e/resources/application/cross-origin-cookies.html +++ b/test/e2e/resources/application/cross-origin-cookies.html @@ -7,6 +7,7 @@ document.cookie = 'foo=bar;path=/'; document.cookie = 'foo2=bar;path=/'; + // Load cross origin resource by switching the hostname to 127.0.0.1 const url = new URL('./set-cookies.rawresponse', document.location); const image = new Image(); image.src = url.toString().replace('localhost', '127.0.0.1'); diff --git a/test/e2e/resources/recorder/oop-iframe.html b/test/e2e/resources/recorder/oop-iframe.html new file mode 100644 index 0000000000..5333b46c02 --- /dev/null +++ b/test/e2e/resources/recorder/oop-iframe.html @@ -0,0 +1,7 @@ + +