cdn-cache-check
Version:
Makes HTTP requests to URLs and parses response headers to determine caching behaviour
297 lines (255 loc) • 8.44 kB
JavaScript
const debug = require('debug')('cdn-cache-check-configuration');
debug('Entry: [%s]', __filename);
// The name of the configuration file
const configFile = 'configuration.json'
// Command line options parser
const argv = require('yargs').help(false).argv;
// Initialise console colours
const chalk = require('chalk');
// Initialise default settings
let defaultSettings = {};
try {
defaultSettings = require('./configuration.json'); // Load the defaults
} catch (error) {
debug('An error occurred loading the %s file: %O', configFile, error);
// The configuration file didn't load. Return a bare and very basic config
defaultSettings = {
method: 'get',
headersCollection: 'default',
serviceDetection: true,
IPScan: true,
headersCollections: [
{
default: [
'x-cache',
'cache-control',
'server',
'content-encoding',
'vary',
'age',
],
},
],
ApexDomains: {},
options: {
exportToCSV: true,
openAfterExport: false,
headers: {
'user-agent': 'ccc/{version} {OS}/{OSRelease}',
Connection: 'close',
},
httpOptions: {
timeout: 6000,
response_timeout: 6000,
read_timeout: 6000,
follow: 5,
compressed: true,
},
verbose: false,
},
};
}
function getSettings() {
debug('Entry::getSettings()');
// Load the defaults
let settings = defaultSettings;
debug('Loaded default settings: %O', settings);
try {
// Check command line parameters for overrides...
debug('Looking for command line switches that override default settings');
// Header Collection
if (argv.headers) {
// ** We should validate the specified collection actually exists **
settings.headersCollection = argv.headers;
debug(
'Using the specified Headers Collection: %s',
settings.headersCollection,
);
} else {
debug(
'Using the default Headers Collection: %s',
settings.headersCollection,
);
}
// Load the headers collections into the Settings object
settings.headerCollection = this.getHeaderCollection(
settings.headersCollection,
settings,
);
// Extract HTTP Method
if (argv.method) {
// Create array of supported HTTP methods
const HTTPMethods = [
'get',
'head',
'options',
'put',
'patch',
'delete',
'trace',
'connect',
];
if (HTTPMethods.includes(argv.method.toLowerCase())) {
settings.method = argv.method.toLowerCase();
debug('Setting HTTP method to: %s', settings.method);
} else {
console.log(
chalk.blue(
'Warning: %s is not a supported HTTP method. Using %s instead.',
argv.method.toUpperCase(),
settings.method.toUpperCase(),
),
);
}
}
// Number of HTTP redirects to follow
if (argv.follow !== undefined) {
// Validate that an integer was specified
if (Number.isInteger(argv.follow)) {
settings.options.httpOptions.follow = argv.follow;
debug(
'The number of HTTP redirects to follow is set to %s',
settings.options.httpOptions.follow,
);
if (settings.options.httpOptions.follow === 0) {
console.log(chalk.blue('HTTP redirects will not be followed'));
}
} else {
console.log(
chalk.yellow(
'Warning: Ignoring "--follow %s" because "follow" must be an integer specifying the number of chained HTTP redirects to follow. Using the default %s instead',
),
argv.follow,
settings.options.httpOptions.follow,
);
}
}
// Check for list-response-headers argument
if (argv.listResponseHeaders) {
settings.listResponseHeaders = true;
// We can switch off the CDN detection output because we're just listing response headers
settings.serviceDetection = false;
} else {
settings.listResponseHeaders = false;
}
// Check for '--open' argument
if (argv.open) {
settings.options.openAfterExport = true;
}
// Check for '--verbose' argument
if (argv.verbose) {
settings.options.verbose = true;
}
// Check for '--export false' argument
if (argv.export) {
if (typeof argv.export === 'string') {
if (argv.export.toLowerCase() === 'false') {
settings.options.exportToCSV = false;
// Switch off openAfterExport because we're not exporting anything
settings.options.openAfterExport = true;
}
}
}
// Check for '--ipscan false' argument
if (argv.ipscan) {
if (typeof argv.ipscan === 'string') {
if (argv.ipscan.toLowerCase() === 'false') {
settings.IPScan = false;
}
}
}
// Use a client specific customised user-agent string
// settings.options.headers['user-agent'] = this.getUserAgent();
settings.options.httpOptions.user_agent = this.getUserAgent();
debug('Using the user-agent: %s', settings.options.httpOptions.user_agent);
return settings;
} catch (error) {
console.error(`${chalk.redBright('An error occurred in getSettings()')} - ${error.message}`);
debug(error);
return settings;
}
}
function getHeaderCollection(collectionName, settings) {
debug('getHeaderCollection() is retrieving a collection named [%s]', collectionName);
// Iterate through each header collection definition
for (let i = 0; i < settings.headersCollections.length; i++) {
// Get the current (i) collection name, which will be the first (index 0) key name in the array
let currentCollection = Object.keys(settings.headersCollections[i])[0];
// Check if its name matches the supplied one
if (collectionName.toLowerCase() === currentCollection.toLowerCase()) {
// Return the array of headers
let headerCollection = settings.headersCollections[i][currentCollection];
debug('Returning header collection [%s]: %O', collectionName, headerCollection);
return (headerCollection);
}
}
// If we get here then no matches were found.
// Perhaps return something that will collect all headers - return (['*']);
console.log(
chalk.blue('WARNING: The requested header collection ') +
collectionName +
chalk.blue(' does not exist'),
);
return [];
}
function getHeaderCollections() {
debug('getHeaderCollections():: Entry');
// Extract the headersCollections array
let headersCollections = defaultSettings.headersCollections;
debug('Returning: %O', headersCollections);
return headersCollections;
}
function displayHeaderCollections(headerCollections) {
debug('displayHeaderCollections():: Entry');
// Initialise prettyJson object, to format output
let prettyJson = require('prettyjson');
// Output the formatted json contained within each array element
headerCollections.forEach((element) => console.log(prettyJson.render(element)));
}
function getUserAgent() {
try {
// Load package.json for the version number etc
const npmPackage = require('./package.json');
// Load O/S module to get client specifics
const os = require('os');
// Extract default user-agent string from default config
let userAgent = defaultSettings.options.headers['user-agent'];
// Replace embedded variables with platform specifics
userAgent = userAgent.replace('{version}', npmPackage.version);
userAgent = userAgent.replace('{OS}', os.type());
userAgent = userAgent.replace('{OSRelease}', os.release());
return userAgent;
} catch (error) {
debug('getUserAgent() caught an error: %O', error);
return global.CCC_DEFAULT_USERAGENT;
}
}
function displayConfigFileLocation() { // Display config file location
// Platform independent new line character and path separator
const EOL = require('os').EOL;
const pathSeparator = require('path').sep;
// Configuration file exists in the same directory as the main application __dirname
let configFilePath = `${__dirname}${pathSeparator}${configFile}`;
console.log(EOL + chalk.grey('Config file:') + chalk.yellowBright(configFilePath));
}
function initResponseObject() {
let defaultResponseObject = {
error: false,
statusCode: 0,
request: {},
response: {},
redirectCount: 0,
ipAddress: null,
ipFamily: null
};
return (defaultResponseObject);
}
module.exports = {
displayConfigFileLocation,
displayHeaderCollections,
getHeaderCollection,
getSettings,
getUserAgent,
getHeaderCollections,
initResponseObject
};