Skip to content

Commit

Permalink
Use fastify-static and hooks instead (#6)
Browse files Browse the repository at this point in the history
* my changes

* added fastify-static definitions

* Updated fastify. Added fastify-static. Use hooks instead.

* Added fastify-static to the dependencies

* Removed extraneous console.log

* squash gts fix

* Added AUTHORS and fixed copyright header in fastify-static

* use fastify v0.43.0

* require public npm instead of local code
  • Loading branch information
mcollina authored and jinwoo committed Feb 7, 2018
1 parent faa8bcd commit e4f2c23
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 45 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Google LLC
Matteo Collina <hello@matteocollina.com>
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@
},
"dependencies": {
"cookie": "^0.3.1",
"fastify": "^0.39.1",
"fastify": "^0.43.0",
"fastify-plugin": "^0.2.1",
"h2-auto-push": "^0.2.0",
"send": "^0.16.1"
"fastify-static": "^0.7.0",
"h2-auto-push": "^0.2.0"
},
"devDependencies": {
"@types/cookie": "^0.3.1",
"@types/get-port": "^3.2.0",
"@types/node": "^9.4.0",
"@types/send": "^0.14.4",
"ava": "^0.24.0",
"codecov": "^3.0.0",
Expand Down
27 changes: 27 additions & 0 deletions ts/src/fastify-static.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2018 The node-fastify-auto-push authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

declare module 'fastify-static' {
import * as fastify from 'fastify';

interface PluginOptions {
}

function fastifyStatic<HttpServer, HttpRequest, HttpResponse, T>(
fn: fastify.Plugin<HttpServer, HttpRequest, HttpResponse, T>,
options?: PluginOptions|
string): fastify.Plugin<HttpServer, HttpRequest, HttpResponse, T>;

export = fastifyStatic;
}
85 changes: 43 additions & 42 deletions ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import * as autoPush from 'h2-auto-push';
import * as http from 'http';
import * as http2 from 'http2';
import * as https from 'https';
import * as send from 'send';
import * as stream from 'stream';

import fp = require('fastify-plugin');
Expand All @@ -43,60 +42,62 @@ function isHttp2Request(req: RawRequest): req is http2.Http2ServerRequest {
return !!(req as http2.Http2ServerRequest).stream;
}

function isHttp2Response(res: RawResponse): res is http2.Http2ServerResponse {
return !!(res as http2.Http2ServerResponse).stream;
}

const CACHE_COOKIE_KEY = '__ap_cache__';

function staticServeFn(
// TODO use a Symbol if ts behaves
interface StorePath extends http2.Http2Stream {
__req_path?: string;
}

async function staticServeFn(
app: fastify.FastifyInstance<HttpServer, RawRequest, RawResponse>,
opts: AutoPushOptions, done?: (err?: Error) => void): void {
opts: AutoPushOptions): Promise<void> {
const root = opts.root;
let prefix = opts.prefix;
const prefix = opts.prefix || '';
const ap = new autoPush.AutoPush(root, opts.cacheConfig);

if (prefix === undefined) prefix = '/';
if (prefix[0] !== '/') prefix = '/' + prefix;
if (prefix[prefix.length - 1] !== '/') prefix += '/';
app.get(prefix + '*', async (req: Request, res: Response) => {
const reqPath: string = prefix + (req.params['*'] || '');
if (isHttp2Request(req.req)) {
const reqStream = req.req.stream;
const cookies = cookie.parse(req.req.headers['cookie'] as string || '');
app.register(require('fastify-static'), opts);

app.addHook('onRequest', async (req, res) => {
if (isHttp2Request(req)) {
const reqStream = req.stream;
const url: string = req.url;
let reqPath: string = url.split('?')[0];
reqPath = reqPath.replace(prefix, '');
(req.stream as StorePath).__req_path = reqPath;
const cookies = cookie.parse(req.headers['cookie'] as string || '');
const cacheKey = cookies[CACHE_COOKIE_KEY];
const newCacheKey =
await ap.preprocessRequest(reqPath, reqStream, cacheKey);
// TODO(jinwoo): Consider making this persistent across sessions.
res.header('set-cookie', cookie.serialize(CACHE_COOKIE_KEY, newCacheKey));

send(req.req, reqPath, {root})
.on('error',
(err) => {
if (err.code === 'ENOENT') {
ap.recordRequestPath(reqStream.session, reqPath, false);
res.code(404).send();
} else {
res.code(500).send(err);
}
})
.on('end',
() => {
ap.recordRequestPath(reqStream.session, reqPath, true);
})
.pipe(res.res as stream.Writable);
await ap.push(reqStream);
} else {
send(req.req, reqPath, {root})
.on('error',
(err) => {
if (err.code === 'ENOENT') {
res.code(404).send();
} else {
res.code(500).send(err);
}
})
.pipe(res.res as stream.Writable);
res.setHeader(
'set-cookie', cookie.serialize(CACHE_COOKIE_KEY, newCacheKey));

ap.push(reqStream).then(noop, noop);
}
});

if (done) done();
app.addHook('onSend', async (request, reply, payload) => {
const res = reply.res;
if (isHttp2Response(res)) {
const resStream = (res as http2.Http2ServerResponse).stream;
const statusCode = (res as http2.Http2ServerResponse).statusCode;
if (statusCode === 404) {
ap.recordRequestPath(
resStream.session, (resStream as StorePath).__req_path || '',
false);
} else if (statusCode < 300 && statusCode >= 200) {
ap.recordRequestPath(
resStream.session, (resStream as StorePath).__req_path || '', true);
}
}
});
}

function noop() {}

export const staticServe = fp(staticServeFn);

0 comments on commit e4f2c23

Please sign in to comment.