diff --git a/src/cookies.ts b/src/cookies.ts index f4c9b7e..f8b6f28 100644 --- a/src/cookies.ts +++ b/src/cookies.ts @@ -155,6 +155,7 @@ export class Cookies { if (opts.partitioned) { if ( !this.secure || + !userAgent || (userAgent && !this.isPartitionedCompatible(userAgent)) ) { // ignore partitioned when not secure or incompatible clients @@ -162,6 +163,13 @@ export class Cookies { } } + if (opts.priority) { + if (!userAgent || (userAgent && !this.isPriorityCompatible(userAgent))) { + // ignore priority when not secure or incompatible clients + opts.priority = undefined; + } + } + const cookie = new Cookie(name, value, opts); // if user not set secure, reset secure to ctx.secure @@ -213,6 +221,16 @@ export class Cookies { return this.uaParseResult; } + + protected isPriorityCompatible(userAgent: string) { + // Chrome >= 81.0.0.0 + // https://developer.chrome.com/blog/new-in-devtools-81?hl=zh-cn#cookiepriority + const result = this.parseChromiumAndMajorVersion(userAgent); + if (result.chromium && result.majorVersion) { + return result.majorVersion >= 81; + } + return false; + } } const patternCache = new Map(); diff --git a/src/interface.ts b/src/interface.ts index ad225d9..1b71d85 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -64,10 +64,12 @@ export interface CookieSetOptions { signed?: boolean; /** * a string indicating the cookie priority. This can be set to 'low', 'medium', or 'high'. + * only supported in chrome 81+. + * https://developer.chrome.com/blog/new-in-devtools-81?hl=zh-cn#cookiepriority */ - priority?: 'low' | 'medium' | 'high'; + priority?: 'low' | 'medium' | 'high' | 'Low' | 'Medium' | 'High'; /** - * a boolean indicating whether to partition the cookie in Chrome for the CHIPS Update,false by default. + * a boolean indicating whether to partition the cookie in Chrome for the CHIPS Update,false by default. * If this is true, Cookies from embedded sites will be partitioned and only readable from the same top level site from which it was created. */ partitioned?: boolean; diff --git a/test/cookies.test.ts b/test/cookies.test.ts index fac8d42..5a05c91 100644 --- a/test/cookies.test.ts +++ b/test/cookies.test.ts @@ -394,9 +394,48 @@ describe('test/cookies.test.ts', () => { assert.ok(cookies.secure); assert.ok(cookies1.secure === false); assert.ok(cookies2.secure === true); - }) + }); + + describe('opts.priority', () => { + + it('should test priority options when ua is empty', () => { + const cookies = CreateCookie(); + cookies.set('foo', 'bar', { priority: 'High' }); + assert(!cookies.ctx.response.headers['set-cookie'][0].includes('priority=High')); + }); + + it('should test priority options when ua is chrome low version', () => { + const cookies = CreateCookie({ + headers: { + 'user-agent': 'Mozilla/5.0 (Linux; Android 4.4.4; SM-G530H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.108 Mobile Safari/537.36', + }, + }); + cookies.set('foo', 'bar', { priority: 'High' }); + assert(!cookies.ctx.response.headers['set-cookie'][0].includes('priority=High')); + }); + + + it('should test priority options when ua is chrome high version', () => { + const cookies = CreateCookie({ + headers: { + 'user-agent': 'Mozilla/5.0 (Linux; Android 4.4.4; SM-G530H Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.2987.108 Mobile Safari/537.36', + }, + }); + cookies.set('foo', 'bar', { priority: 'High' }); + assert(cookies.ctx.response.headers['set-cookie'][0].includes('priority=High')); + }); + }); describe('opts.partitioned', () => { + + it('should test partitioned options when ua is empty', () => { + const cookies = CreateCookie({ + secure: true, + }, { secure: true }); + cookies.set('foo', 'bar', { signed: true, partitioned: true }); + assert(!cookies.ctx.response.headers['set-cookie'][0].includes('partitioned')); + }); + it('should not send partitioned property on incompatible clients', () => { const userAgents = [ 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML%2C like Gecko) Chrome/64.0.3282.140 Safari/537.36', @@ -494,7 +533,8 @@ describe('test/cookies.test.ts', () => { assert(opts.secure === undefined); assert(cookies.ctx.response.headers['set-cookie'].join(';').match(/foo=hello/)); for (const str of cookies.ctx.response.headers['set-cookie']) { - assert(str.includes('; path=/; secure; httponly; partitioned')); + assert(str.includes('path=/; secure; httponly')); + assert(!str.includes('; path=/; secure; httponly; partitioned')); } });