-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(FRC): Add Complaince to FRC 7234 until Section 4
Add FRC File and tests for it and implement test until section 4 wip #1
- Loading branch information
Showing
11 changed files
with
325 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
const FRC = { | ||
|
||
allCaches: [ 'public', 'private', 'no-cache', 'only-if-cached' ], | ||
allExpirationPrefix: [ 'max-age', 's-maxage', 'max-stale', 'min-fresh', 'stale-while-revalidate', 'stale-if-error' ], | ||
allOtherCacheConfig: [ 'no-store', 'no-transform' ], | ||
allRevalidations: [ 'must-revalidate', 'proxy-revalidate', 'immutable' ], | ||
|
||
/** | ||
* THis function check to see if there is any unallowed parameter. See that the allowed ones are in these arrays above | ||
* | ||
* @param {Object} cacheObject - An Cache string trasnformed in object | ||
* @returns {Boolean} - Return true if all params are allowed | ||
*/ | ||
hasUnallowedParam(cacheObject) { | ||
let hasError = false; | ||
const allAllowedParams = [ | ||
...FRC.allCaches, | ||
...FRC.allExpirationPrefix, | ||
...FRC.allOtherCacheConfig, | ||
...FRC.allRevalidations | ||
]; | ||
|
||
Object.keys(cacheObject).forEach(config => { | ||
if(!allAllowedParams.includes(config)) { | ||
hasError = { error: `Unallowed paramemeter "${config}" found. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for more details` }; | ||
} | ||
}); | ||
|
||
return hasError; | ||
}, | ||
|
||
/** | ||
* This function check to see if the params are FRC Cpmplaint | ||
* | ||
* @param {Object} cacheObject - An Cache string trasnformed in object | ||
* @returns {Boolean} Return true if the cache config is FRC Complaint | ||
*/ | ||
isFRCComplaint(cacheObject) { | ||
let isComplaint = true; | ||
const hasUnallowedParam = FRC.hasUnallowedParam(cacheObject); | ||
|
||
if(hasUnallowedParam && hasUnallowedParam.error) { | ||
isComplaint = hasUnallowedParam; | ||
} | ||
|
||
if(!FRC.checkIfCacheIsEnabled(cacheObject)) { | ||
isComplaint = { error: 'The params "no-store" or "private" must appear alone' }; | ||
} | ||
|
||
return isComplaint; | ||
}, | ||
|
||
/** | ||
* This function check for complaint with FRC 7234 Section 1.2.1 | ||
* | ||
* @param {Number} cacheTime - An integer representing the time in secons | ||
* @returns {Number} 2147483648 or the params itself | ||
*/ | ||
maxCacheTime(cacheTime) { | ||
if(cacheTime > 2147483648) { // eslint-disable-line no-magic-numbers | ||
return 2147483648; // eslint-disable-line no-magic-numbers | ||
} | ||
|
||
return cacheTime; | ||
}, | ||
|
||
/** | ||
* This function check for complaint with FRC 7234 Section 3 | ||
* Is says that if no-store or private is set, there should be no cache | ||
* | ||
* @param {Object} cacheObject - An Cache string trasnformed in object | ||
* @returns {Boolean} Return true if the varibles appear alone for they are not set | ||
*/ | ||
checkIfCacheIsEnabled(cacheObject) { // eslint-disable-line sort-keys | ||
const allCacheKeys = Object.keys(cacheObject); | ||
|
||
if(allCacheKeys.includes('no-store') && allCacheKeys.length > 1) { | ||
return false; | ||
} | ||
|
||
if(allCacheKeys.includes('private') && allCacheKeys.length > 1) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
}; | ||
|
||
module.exports = FRC; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
const FRC = require('./frc'); | ||
|
||
const Helpers = { | ||
|
||
/** | ||
* Converts a string with comma separation keys and = separetor value in an Object | ||
* Where anything described as "Key=Value" will become { key: value }, anything represented only as "Key" will become { key: true } | ||
* | ||
* Ot only accept numbers as Values and empty valued keys | ||
* If you send anything that ins't valid it will return an error object | ||
* | ||
* @example 'one, two=200, four, five=500' | ||
* // returns { one: true, two: 2000, four: true, five: 500 } | ||
* | ||
* @param {String} cacheString - A String to be converted | ||
* @returns {Object|Error} An Object with the result or a object with an error | ||
*/ | ||
convertStringIntoObject(cacheString) { | ||
const cacheArray = cacheString.split(', '); | ||
const cacheObject = {}; | ||
let hasError = false; | ||
|
||
if(!cacheArray.length || (cacheArray.length === 1 && cacheString.includes(' ')) || typeof cacheString !== 'string') { | ||
return { error: 'Cache string not valid. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for more details' }; | ||
} | ||
|
||
cacheArray.forEach(config => { | ||
if(!config.includes('=')) { | ||
cacheObject[config] = true; | ||
return true; | ||
} | ||
|
||
const expirationConfig = config.split('='); | ||
let expirationNumber = parseInt(expirationConfig[1], 10); | ||
|
||
if(!Helpers.isNumeric(expirationConfig[1])) { | ||
hasError = true; | ||
} | ||
|
||
expirationNumber = FRC.maxCacheTime(expirationNumber); | ||
|
||
cacheObject[expirationConfig[0]] = expirationNumber; | ||
return true; | ||
}); | ||
|
||
if(hasError) { | ||
return { error: 'Expect to find a number for configuration but found something else. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for more details' }; | ||
} | ||
|
||
return cacheObject; | ||
}, | ||
|
||
/** | ||
* Converts an object into strings with comma separation. | ||
* Where anything is described as "Key=Value", Boolean True only as "Key" and Boolean false is not represented | ||
* If you send anything that ins't an object it will return an empty string | ||
* | ||
* @example { one: true, two: 200, three: false, four: true, five: 5000 } | ||
* // returns 'one, two=200, four, five=5000' | ||
* | ||
* @param {Any} objectToConvert - Object to be converted | ||
* @returns {String} An string with the result of the convertion | ||
*/ | ||
convertToString(objectToConvert) { | ||
let finalString = ''; | ||
|
||
if(objectToConvert && typeof objectToConvert !== 'object') { | ||
return finalString; | ||
} | ||
|
||
Object.keys(objectToConvert).forEach(thisParam => { | ||
if(finalString !== '') { | ||
finalString += ', '; | ||
} | ||
|
||
if(objectToConvert[thisParam] === true) { | ||
finalString += `${thisParam}`; | ||
return true; | ||
} | ||
|
||
if(objectToConvert[thisParam] === false) { | ||
return true; | ||
} | ||
|
||
finalString += `${thisParam}=${objectToConvert[thisParam]}`; | ||
}); | ||
|
||
return finalString; | ||
}, | ||
|
||
/** | ||
* This function check to see if there is any duplicated configurations | ||
* | ||
* @param {Object} cacheString - A Cache String | ||
* @returns {Boolean} - Return true if there are not duplicates | ||
*/ | ||
hasDuplicatedConfiguration(cacheString) { // eslint-disable-line sort-keys | ||
const allParamsArray = []; | ||
|
||
cacheString.split(', ').forEach(config => { | ||
allParamsArray.push(config.split('=')[0]); | ||
}); | ||
|
||
const filteredArray = [ ...new Set(allParamsArray) ]; // eslint-disable-line | ||
|
||
return filteredArray.length !== allParamsArray.length; | ||
}, | ||
|
||
/** | ||
* Check to see if the value is a numeric value. It can be a string or anything else if it can be converter to a number | ||
* Also it doesn't allow numbers with floatation point and only greater than zero ones | ||
* | ||
* @param {Any} varToVerify - Value to verify | ||
* @returns {Boolean} True if is a numeric value greater than zero and not decimal | ||
*/ | ||
isNumeric(varToVerify) { | ||
return !isNaN(parseFloat(varToVerify)) && !Array.isArray(varToVerify) && Number.isInteger(Number(varToVerify)) && (Number(varToVerify) === 0 || Number(varToVerify) >= 1); | ||
} | ||
|
||
}; | ||
|
||
module.exports = Helpers; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
const hasUnallowedParam = require('../lib/frc').hasUnallowedParam; | ||
|
||
describe('hasUnallowedParam', () => { | ||
it('should have a global object', () => { | ||
expect(hasUnallowedParam).toBeDefined(); | ||
}); | ||
|
||
it('Should return false if isnt anything wrong', () => { | ||
expect(hasUnallowedParam({ 'max-age': 36000, public: true })).toEqual(false); | ||
expect(hasUnallowedParam({ 'no-store': true })).toEqual(false); | ||
}); | ||
|
||
it('Should return error without = and without number value', () => { | ||
expect(hasUnallowedParam({ publics: true })).toEqual({ error: 'Unallowed paramemeter "publics" found. Check https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control for more details' }); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const isFRCComplaint = require('../lib/frc').isFRCComplaint; | ||
|
||
describe('isFRCComplaint', () => { | ||
it('should have a global object', () => { | ||
expect(isFRCComplaint).toBeDefined(); | ||
}); | ||
|
||
it('Should return true', () => { | ||
expect(isFRCComplaint({ 'max-age': 36000, public: true })).toEqual(true); | ||
expect(isFRCComplaint({ 'no-store': true })).toEqual(true); | ||
expect(isFRCComplaint({ private: true })).toEqual(true); | ||
}); | ||
|
||
it('Should return error because no-store and private inst alone', () => { | ||
expect(isFRCComplaint({ 'max-age': 3600, private: true })).toEqual({ error: 'The params "no-store" or "private" must appear alone' }); | ||
expect(isFRCComplaint({ 'max-age': 3600, 'no-store': true })).toEqual({ error: 'The params "no-store" or "private" must appear alone' }); | ||
expect(isFRCComplaint({ 'no-store': true, private: true })).toEqual({ error: 'The params "no-store" or "private" must appear alone' }); | ||
}); | ||
}); |
Oops, something went wrong.