| 'use strict'; |
| |
| // TODO(jsbell): Once ServiceWorker is supported, add arbitrary path coverage. |
| const kPath = location.pathname.replace(/[^/]+$/, ''); |
| |
| // True when running in a document context as opposed to a worker context |
| const kHasDocument = typeof document !== 'undefined'; |
| |
| // True when running on unsecured 'http:' rather than secured 'https:'. |
| const kIsUnsecured = location.protocol !== 'https:'; |
| |
| const kCookieHelperCgi = 'resources/cookie_helper.py'; |
| |
| // Approximate async equivalent to the document.cookie getter but with |
| // important differences: optional additional getAll arguments are |
| // forwarded, and an empty cookie jar returns undefined. |
| // |
| // This is intended primarily for verification against expected cookie |
| // jar contents. It should produce more readable messages using |
| // assert_equals in failing cases than assert_object_equals would |
| // using parsed cookie jar contents and also allows expectations to be |
| // written more compactly. |
| async function getCookieString(...args) { |
| const cookies = await cookieStore.getAll(...args); |
| return cookies.length |
| ? cookies.map(({name, value}) => |
| (name ? (name + '=') : '') + value).join('; ') |
| : undefined; |
| } |
| |
| // Approximate async equivalent to the document.cookie getter but from |
| // the server's point of view. Returns UTF-8 interpretation. Allows |
| // sub-path to be specified. |
| // |
| // Unlike document.cookie, this returns undefined when no cookies are |
| // present. |
| async function getCookieStringHttp(extraPath = null) { |
| const url = |
| kCookieHelperCgi + ((extraPath == null) ? '' : ('/' + extraPath)); |
| const response = await fetch(url, { credentials: 'include' }); |
| const text = await response.text(); |
| assert_equals( |
| response.ok, |
| true, |
| 'CGI should have succeeded in getCookieStringHttp\n' + text); |
| assert_equals( |
| response.headers.get('content-type'), |
| 'text/plain; charset=utf-8', |
| 'CGI did not return UTF-8 text in getCookieStringHttp'); |
| if (text === '') |
| return undefined; |
| assert_equals( |
| text.indexOf('cookie='), |
| 0, |
| 'CGI response did not begin with "cookie=" and was not empty: ' + text); |
| return decodeURIComponent(text.replace(/^cookie=/, '')); |
| } |
| |
| // Approximate async equivalent to the document.cookie getter but from |
| // the server's point of view. Returns binary string |
| // interpretation. Allows sub-path to be specified. |
| // |
| // Unlike document.cookie, this returns undefined when no cookies are |
| // present. |
| async function getCookieBinaryHttp(extraPath = null) { |
| const url = |
| kCookieHelperCgi + |
| ((extraPath == null) ? |
| '' : |
| ('/' + extraPath)) + '?charset=iso-8859-1'; |
| const response = await fetch(url, { credentials: 'include' }); |
| const text = await response.text(); |
| assert_equals( |
| response.ok, |
| true, |
| 'CGI should have succeeded in getCookieBinaryHttp\n' + text); |
| assert_equals( |
| response.headers.get('content-type'), |
| 'text/plain; charset=iso-8859-1', |
| 'CGI did not return ISO 8859-1 text in getCookieBinaryHttp'); |
| if (text === '') |
| return undefined; |
| assert_equals( |
| text.indexOf('cookie='), |
| 0, |
| 'CGI response did not begin with "cookie=" and was not empty: ' + text); |
| return unescape(text.replace(/^cookie=/, '')); |
| } |
| |
| // Approximate async equivalent to the document.cookie setter but from |
| // the server's point of view. |
| async function setCookieStringHttp(setCookie) { |
| const encodedSetCookie = encodeURIComponent(setCookie); |
| const url = kCookieHelperCgi; |
| const headers = new Headers(); |
| headers.set( |
| 'content-type', |
| 'application/x-www-form-urlencoded; charset=utf-8'); |
| const response = await fetch( |
| url, |
| { |
| credentials: 'include', |
| method: 'POST', |
| headers: headers, |
| body: 'set-cookie=' + encodedSetCookie, |
| }); |
| const text = await response.text(); |
| assert_equals( |
| response.ok, |
| true, |
| 'CGI should have succeeded in setCookieStringHttp set-cookie: ' + |
| setCookie + '\n' + text); |
| assert_equals( |
| response.headers.get('content-type'), |
| 'text/plain; charset=utf-8', |
| 'CGI did not return UTF-8 text in setCookieStringHttp'); |
| assert_equals( |
| text, |
| 'set-cookie=' + encodedSetCookie, |
| 'CGI did not faithfully echo the set-cookie value'); |
| } |
| |
| // Approximate async equivalent to the document.cookie setter but from |
| // the server's point of view. This version sets a binary cookie rather |
| // than a UTF-8 one. |
| async function setCookieBinaryHttp(setCookie) { |
| const encodedSetCookie = escape(setCookie).split('/').join('%2F'); |
| const url = kCookieHelperCgi + '?charset=iso-8859-1'; |
| const headers = new Headers(); |
| headers.set( |
| 'content-type', |
| 'application/x-www-form-urlencoded; charset=iso-8859-1'); |
| const response = await fetch(url, { |
| credentials: 'include', |
| method: 'POST', |
| headers: headers, |
| body: 'set-cookie=' + encodedSetCookie |
| }); |
| const text = await response.text(); |
| assert_equals( |
| response.ok, |
| true, |
| 'CGI should have succeeded in setCookieBinaryHttp set-cookie: ' + |
| setCookie + '\n' + text); |
| assert_equals( |
| response.headers.get('content-type'), |
| 'text/plain; charset=iso-8859-1', |
| 'CGI did not return Latin-1 text in setCookieBinaryHttp'); |
| assert_equals( |
| text, |
| 'set-cookie=' + encodedSetCookie, |
| 'CGI did not faithfully echo the set-cookie value'); |
| } |
| |
| // Async document.cookie getter; converts '' to undefined which loses |
| // information in the edge case where a single ''-valued anonymous |
| // cookie is visible. |
| async function getCookieStringDocument() { |
| if (!kHasDocument) |
| throw 'document.cookie not available in this context'; |
| return String(document.cookie || '') || undefined; |
| } |
| |
| // Async document.cookie setter |
| async function setCookieStringDocument(setCookie) { |
| if (!kHasDocument) |
| throw 'document.cookie not available in this context'; |
| document.cookie = setCookie; |
| } |
| |
| // Observe the next 'change' event on the cookieStore. Typical usage: |
| // |
| // const eventPromise = observeNextCookieChangeEvent(); |
| // await /* something that modifies cookies */ |
| // await verifyCookieChangeEvent( |
| // eventPromise, {changed: [{name: 'name', value: 'value'}]}); |
| // |
| function observeNextCookieChangeEvent() { |
| return new Promise(resolve => { |
| cookieStore.addEventListener('change', e => resolve(e), {once: true}); |
| }); |
| } |
| |
| async function verifyCookieChangeEvent(eventPromise, expected, description) { |
| description = description ? description + ': ' : ''; |
| expected = Object.assign({changed:[], deleted:[]}, expected); |
| const event = await eventPromise; |
| assert_equals(event.changed.length, expected.changed.length, |
| description + 'number of changed cookies'); |
| for (let i = 0; i < event.changed.length; ++i) { |
| assert_equals(event.changed[i].name, expected.changed[i].name, |
| description + 'changed cookie name'); |
| assert_equals(event.changed[i].value, expected.changed[i].value, |
| description + 'changed cookie value'); |
| } |
| assert_equals(event.deleted.length, expected.deleted.length, |
| description + 'number of deleted cookies'); |
| for (let i = 0; i < event.deleted.length; ++i) { |
| assert_equals(event.deleted[i].name, expected.deleted[i].name, |
| description + 'deleted cookie name'); |
| assert_equals(event.deleted[i].value, expected.deleted[i].value, |
| description + 'deleted cookie value'); |
| } |
| } |
| |
| // Helper function for promise_test with cookies; cookies |
| // named in these tests are cleared before/after the test |
| // body function is executed. |
| async function cookie_test(func, description) { |
| |
| // Wipe cookies used by tests before and after the test. |
| async function deleteAllCookies() { |
| (await cookieStore.getAll()).forEach(({name, value}) => { |
| cookieStore.delete(name); |
| }); |
| } |
| |
| return promise_test(async t => { |
| await deleteAllCookies(); |
| try { |
| return await func(t); |
| } finally { |
| await deleteAllCookies(); |
| } |
| }, description); |
| } |