UNPKG

polyserve

Version:

A simple dev server for bower components

106 lines (95 loc) 3.34 kB
/** * @license * Copyright (c) 2015 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt * The complete set of authors may be found at * http://polymer.github.io/AUTHORS.txt * The complete set of contributors may be found at * http://polymer.github.io/CONTRIBUTORS.txt * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ import * as fs from 'fs'; import * as mime from 'mime'; import * as path from 'path'; import * as assert from 'assert'; import {ServerOptions} from '../start_server'; /** h2 push manifest cache */ let _pushManifest = {}; /** * Asserts file existence for all specified files in a push-manifest * @param root path to root directory * @param manifest manifest object */ function assertValidManifest(root: string, manifest: {[path: string]: any}) { function assertExists(filename: string) { const fname = path.join(root, filename); try { // Ignore root path, since that always exists for the router if (filename !== '/') { assert(fs.existsSync(fname), `not found: ${fname}`); } } catch (err) { throw new Error(`invalid h2-push manifest: ${err}`); } } for (const refFile of Object.keys(manifest)) { assertExists(refFile); for (const pushFile of Object.keys(manifest[refFile])) { assertExists(pushFile); } } } /** * Reads a push-manifest from the specified path, or a cached version * of the file * @param root path to root directory * @param manifestPath path to manifest file * @returns the manifest */ export function getPushManifest( root: string, manifestPath: string): {[path: string]: any} { if (!_pushManifest[manifestPath]) { const data = fs.readFileSync(manifestPath); const manifest = JSON.parse(data.toString()); assertValidManifest(root, manifest); _pushManifest[manifestPath] = manifest; } return _pushManifest[manifestPath]; } /** * Pushes any resources for the requested file * @param options server options * @param req HTTP request * @param res HTTP response */ export function pushResources(options: ServerOptions, req: any, res: any) { if (res.push && options.protocol === 'h2' && options.pushManifestPath && !req.get('x-is-push')) { // TODO: Handle preload link headers const pushManifest = getPushManifest(options.root, options.pushManifestPath); const resources = pushManifest[req.path]; if (resources) { const root = options.root; for (const filename of Object.keys(resources)) { const stream: NodeJS.WritableStream = res.push(filename, { request: {accept: '*/*'}, response: { 'content-type': mime.lookup(filename), // Add an X-header to the pushed request so we don't trigger // pushes for pushes 'x-is-push': 'true' } }) .on('error', (err: any) => console.error('failed to push', filename, err)); fs.createReadStream(path.join(root, filename)).pipe(stream); } } } }