diff --git a/packages/request-utils/src/index.ts b/packages/request-utils/src/index.ts index efc2650f9c2..0ea46450352 100644 --- a/packages/request-utils/src/index.ts +++ b/packages/request-utils/src/index.ts @@ -518,6 +518,12 @@ export function parseCacheControl(header: string): CacheControlValue { let isParsingKey = true; let cacheControlValue: CacheControlValue = {}; + function parseCacheControlValue(stringToParse: string): number { + const parsedValue = Number.parseInt(stringToParse); + assert(`Invalid Cache-Control value, expected a number but got - ${stringToParse}`, !Number.isNaN(parsedValue)); + return parsedValue; + } + for (let i = 0; i < header.length; i++) { let char = header.charAt(i); if (char === ',') { @@ -527,7 +533,7 @@ export function parseCacheControl(header: string): CacheControlValue { i === 0 || header.charAt(i - 1) !== '=' ); isParsingKey = true; - cacheControlValue[key] = NUMERIC_KEYS.has(key) ? Number.parseInt(value) : true; + cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true; key = ''; value = ''; continue; @@ -543,7 +549,7 @@ export function parseCacheControl(header: string): CacheControlValue { } if (i === header.length - 1) { - cacheControlValue[key] = NUMERIC_KEYS.has(key) ? Number.parseInt(value) : true; + cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true; } } diff --git a/tests/builders/tests/unit/parse-cache-control-test.ts b/tests/builders/tests/unit/parse-cache-control-test.ts new file mode 100644 index 00000000000..a4ab7a181cb --- /dev/null +++ b/tests/builders/tests/unit/parse-cache-control-test.ts @@ -0,0 +1,69 @@ +import { module, test } from 'qunit'; + +import { parseCacheControl } from '@ember-data/request-utils'; +import { test as debug } from '@ember-data/unpublished-test-infra/test-support/test-in-debug'; + +module('parseCacheControl', function (hooks) { + test('should parse a single Cache-Control directive', function (assert) { + const header = 'max-age=3600'; + const result = parseCacheControl(header); + assert.deepEqual(result, { 'max-age': 3600 }); + }); + + test('should parse multiple Cache-Control directives', function (assert) { + const header = 'max-age=3600, must-revalidate'; + const result = parseCacheControl(header); + assert.deepEqual(result, { 'max-age': 3600, 'must-revalidate': true }); + }); + + test('should parse Cache-Control directives with multiple delta-seconds values', function (assert) { + const header = 'max-age=3600, s-maxage=7200'; + const result = parseCacheControl(header); + assert.deepEqual(result, { 'max-age': 3600, 's-maxage': 7200 }); + }); + + test('should parse Cache-Control directives with a single token value', function (assert) { + const header = 'no-cache'; + const result = parseCacheControl(header); + assert.deepEqual(result, { 'no-cache': true }); + }); + + test('should parse Cache-Control directives with multiple token values', function (assert) { + const header = 'no-cache, no-store'; + const result = parseCacheControl(header); + assert.deepEqual(result, { 'no-cache': true, 'no-store': true }); + }); + + test('should parse Cache-Control directives with a single byte-range-set value', function (assert) { + const header = + 'max-age=3600, no-transform, only-if-cached, public, must-revalidate, proxy-revalidate, no-cache, s-maxage=7200, stale-while-revalidate=3600, stale-if-error=7200, immutable'; + const result = parseCacheControl(header); + assert.deepEqual(result, { + 'max-age': 3600, + 'no-transform': true, + 'only-if-cached': true, + public: true, + 'must-revalidate': true, + 'proxy-revalidate': true, + 'no-cache': true, + 's-maxage': 7200, + 'stale-while-revalidate': 3600, + 'stale-if-error': 7200, + immutable: true, + }); + }); + + debug('throws when Cache-Control has invalid directives', async function (assert) { + await assert.expectAssertion(() => { + const header = 'max-age=,'; + parseCacheControl(header); + }, /Assertion Failed: Invalid Cache-Control value, expected a value after "=" but got ","/); + }); + + debug('throws when Cache-Control has invalid value type', async function (assert) { + await assert.expectAssertion(() => { + const header = 'max-age="3600"'; + parseCacheControl(header); + }, /Assertion Failed: Invalid Cache-Control value, expected a number but got - "3600"/); + }); +});