Alex Rickabaugh f10f8db5fb fix(service-worker): several misc fixes for corner cases
This commit fixes several issues discovered through use in real apps.

* The sha1() function operated on text content, causing issues for binary-format files.
  A sha1Binary() function which operates on unparsed data now avoids any encoding issues.
* The characters '?' and '+' were not escaped in Glob-to-regex conversion previously, but
  are now.
* URLs from the browser contain the full origin, but were checked against the table of
  hashes from the manifest which only has the path for URLs from the same origin. Now the
  origin is checked and URLs are relativized to the domain root before comparison if
  appropriate.
* ngsw: prefix was missing from data groups, is now added.
* Occasionally servers will return a redirected response for an asset, and caching it could
  cause errors for navigation requests. The SW now handles this by detecting such responses
  and following the redirect manually, to avoid caching a redirected response.
* The request for known assets is now created from scratch from the URL before fetching from
  the network, in order to sanitize it and avoid carrying any special modes or headers that
  might result in opaque responses.
* Debugging log for troubleshooting.
* Avoid creating errors by returning 504 responses on error.
* Fix bug where idle queue doesn't run in some circumstances.
* Add tests for the above.
2017-10-05 13:27:31 -07:00

111 lines
3.0 KiB
TypeScript

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export enum UpdateCacheStatus {
NOT_CACHED,
CACHED_BUT_UNUSED,
CACHED,
}
/**
* A source for old versions of URL contents and other resources.
*
* Used to abstract away the fetching of old contents, to avoid a
* circular dependency between the `Driver` and `AppVersion`. Without
* this interface, `AppVersion` would need a reference to the `Driver`
* to access information from other versions.
*/
export interface UpdateSource {
/**
* Lookup an older version of a resource for which the hash is known.
*
* If an old version of the resource doesn't exist, or exists but does
* not match the hash given, this returns null.
*/
lookupResourceWithHash(url: string, hash: string): Promise<Response|null>;
/**
* Lookup an older version of a resource for which the hash is not known.
*
* This will return the most recent previous version of the resource, if
* it exists. It returns a `CacheState` object which encodes not only the
* `Response`, but the cache metadata needed to re-cache the resource in
* a newer `AppVersion`.
*/
lookupResourceWithoutHash(url: string): Promise<CacheState|null>;
/**
* List the URLs of all of the resources which were previously cached.
*
* This allows for the discovery of resources which are not listed in the
* manifest but which were picked up because they matched URL patterns.
*/
previouslyCachedResources(): Promise<string[]>;
/**
* Check whether a particular resource exists in the most recent cache.
*
* This returns a state value which indicates whether the resource was
* cached at all and whether that cache was utilized.
*/
recentCacheStatus(url: string): Promise<UpdateCacheStatus>;
}
/**
* Metadata cached along with a URL.
*/
export interface UrlMetadata {
/**
* The timestamp, in UNIX time in milliseconds, of when this URL was stored
* in the cache.
*/
ts: number;
/**
* Whether the resource was requested before for this particular cached
* instance.
*/
used: boolean;
}
/**
* The fully cached state of a resource, including both the `Response` itself
* and the cache metadata.
*/
export interface CacheState {
response: Response;
metadata?: UrlMetadata;
}
export interface DebugLogger { log(value: string|Error, context?: string): void; }
export interface DebugState {
state: string;
why: string;
latestHash: string|null;
lastUpdateCheck: number|null;
}
export interface DebugVersion {
hash: string;
manifest: Object;
clients: string[];
status: string;
}
export interface DebugIdleState {
queue: string[];
lastTrigger: number|null;
lastRun: number|null;
}
export interface Debuggable {
debugState(): Promise<DebugState>;
debugVersions(): Promise<DebugVersion[]>;
debugIdleState(): Promise<DebugIdleState>;
}