Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
const normalizedRangeHeader = rangeHeader.trim().toLowerCase();
if (!normalizedRangeHeader.startsWith('bytes=')) {
throw new WorkboxError('unit-must-be-bytes', {normalizedRangeHeader});
}
// Specifying multiple ranges separate by commas is valid syntax, but this
// library only attempts to handle a single, contiguous sequence of bytes.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#Syntax
if (normalizedRangeHeader.includes(',')) {
throw new WorkboxError('single-range-only', {normalizedRangeHeader});
}
const rangeParts = /(\d*)-(\d*)/.exec(normalizedRangeHeader);
// We need either at least one of the start or end values.
if (!rangeParts || !(rangeParts[1] || rangeParts[2])) {
throw new WorkboxError('invalid-range-values', {normalizedRangeHeader});
}
return {
start: rangeParts[1] === '' ? undefined : Number(rangeParts[1]),
end: rangeParts[2] === '' ? undefined : Number(rangeParts[2]),
};
}
constructor(cacheName: string, config: CacheExpirationConfig = {}) {
if (process.env.NODE_ENV !== 'production') {
assert!.isType(cacheName, 'string', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
paramName: 'cacheName',
});
if (!(config.maxEntries || config.maxAgeSeconds)) {
throw new WorkboxError('max-entries-or-age-required', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
});
}
if (config.maxEntries) {
assert!.isType(config.maxEntries, 'number', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
paramName: 'config.maxEntries',
});
// TODO: Assert is positive
}
}
}
const isValidResponse = cacheWillUpdatePlugin ?
// Use a callback if provided. It returns a truthy value if valid.
// NOTE: invoke the method on the plugin instance so the `this` context
// is correct.
await cacheWillUpdatePlugin.cacheWillUpdate!({event, request, response}) :
// Otherwise, default to considering any response status under 400 valid.
// This includes, by default, considering opaque responses valid.
response.status < 400;
// Consider this a failure, leading to the `install` handler failing, if
// we get back an invalid response.
if (!isValidResponse) {
throw new WorkboxError('bad-precaching-response', {
url,
status: response.status,
});
}
// Redirected responses cannot be used to satisfy a navigation request, so
// any redirected response must be "copied" rather than cloned, so the new
// response doesn't contain the `redirected` flag. See:
// https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1
if (response.redirected) {
response = await copyResponse(response);
}
await cacheWrapper.put({
event,
plugins,
assert!.isInstance(originalResponse, Response, {
moduleName: 'workbox-range-requests',
funcName: 'createPartialResponse',
paramName: 'originalResponse',
});
}
if (originalResponse.status === 206) {
// If we already have a 206, then just pass it through as-is;
// see https://github.com/GoogleChrome/workbox/issues/1720
return originalResponse;
}
const rangeHeader = request.headers.get('range');
if (!rangeHeader) {
throw new WorkboxError('no-range-header');
}
const boundaries = parseRangeHeader(rangeHeader);
const originalBlob = await originalResponse.blob();
const effectiveBoundaries = calculateEffectiveBoundaries(
originalBlob, boundaries.start, boundaries.end);
const slicedBlob = originalBlob.slice(effectiveBoundaries.start,
effectiveBoundaries.end);
const slicedBlobSize = slicedBlob.size;
const slicedResponse = new Response(slicedBlob, {
// Status code 206 is for a Partial Content response.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206
status: 206,
constructor(config: CacheableResponseOptions = {}) {
if (process.env.NODE_ENV !== 'production') {
if (!(config.statuses || config.headers)) {
throw new WorkboxError('statuses-or-headers-required', {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'constructor',
});
}
if (config.statuses) {
assert!.isArray(config.statuses, {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'constructor',
paramName: 'config.statuses',
});
}
if (config.headers) {
error = err;
}
}
if (process.env.NODE_ENV !== 'production') {
logger.groupCollapsed(
messages.strategyStart('StaleWhileRevalidate', request));
for (let log of logs) {
logger.log(log);
}
messages.printFinalResponse(response);
logger.groupEnd();
}
if (!response) {
throw new WorkboxError('no-response', {url: request.url, error});
}
return response;
}
unregisterRoute(route: Route) {
if (!this._routes.has(route.method)) {
throw new WorkboxError(
'unregister-route-but-not-found-with-method', {
method: route.method,
}
);
}
const routeIndex = this._routes.get(route.method)!.indexOf(route);
if (routeIndex > -1) {
this._routes.get(route.method)!.splice(routeIndex, 1);
} else {
throw new WorkboxError('unregister-route-route-not-registered');
}
}
}
createHandlerBoundToURL(url: string, fallbackToNetwork = true): RouteHandlerCallback {
const cacheKey = this.getCacheKeyForURL(url);
if (!cacheKey) {
throw new WorkboxError('non-precached-url', {url});
}
const handler = this.createHandler(fallbackToNetwork);
const request = new Request(url);
return () => handler({request});
}
}
async isURLExpired(url: string): Promise {
if (!this._maxAgeSeconds) {
if (process.env.NODE_ENV !== 'production') {
throw new WorkboxError(`expired-test-without-max-age`, {
methodName: 'isURLExpired',
paramName: 'maxAgeSeconds',
});
}
return false;
} else {
const timestamp = await this._timestampModel.getTimestamp(url);
const expireOlderThan = Date.now() - (this._maxAgeSeconds! * 1000);
return (timestamp < expireOlderThan);
}
}
if (process.env.NODE_ENV !== 'production') {
logger.groupCollapsed(
messages.strategyStart('CacheOnly', request));
if (response) {
logger.log(`Found a cached response in the '${this._cacheName}'` +
` cache.`);
messages.printFinalResponse(response);
} else {
logger.log(`No response found in the '${this._cacheName}' cache.`);
}
logger.groupEnd();
}
if (!response) {
throw new WorkboxError('no-response', {url: request.url});
}
return response;
}
}