1 | var send = require('send');
|
2 | var debug = require('debug')('connect:gzip-static');
|
3 | var parseUrl = require('parseurl');
|
4 | var path = require('path');
|
5 | var mime = send.mime;
|
6 | var find = require('find');
|
7 |
|
8 | function setHeader(res, path) {
|
9 | var type = mime.lookup(path);
|
10 | var charset = mime.charsets.lookup(type);
|
11 |
|
12 | debug('content-type %s', type);
|
13 | res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
|
14 | res.setHeader('Content-Encoding', 'gzip');
|
15 | res.setHeader('Vary', 'Accept-Encoding');
|
16 | }
|
17 |
|
18 |
|
19 | function createCache(root) {
|
20 | var cache = Object.create(null);
|
21 | find.fileSync(/\.gz$/, root).forEach(function(file) {
|
22 | cache[file] = true;
|
23 | });
|
24 | debug('Found %d compressed files', Object.keys(cache).length);
|
25 | return cache;
|
26 | }
|
27 |
|
28 | module.exports = function(root, options) {
|
29 | var serveStatic, gzipCache = createCache(root);
|
30 |
|
31 | options = options || {};
|
32 | options.index = options.index || 'index.html';
|
33 | serveStatic = require('serve-static')(root, options);
|
34 |
|
35 | return function gzipStatic(req, res, next) {
|
36 | var acceptEncoding, passToStatic, name = {};
|
37 |
|
38 | if ('GET' != req.method && 'HEAD' != req.method) {
|
39 | return next();
|
40 | }
|
41 |
|
42 | passToStatic = serveStatic.bind(this, req, res, next);
|
43 |
|
44 | acceptEncoding = req.headers['accept-encoding'] || '';
|
45 | if (!~acceptEncoding.indexOf('gzip')) {
|
46 | debug('Passing %s', req.url);
|
47 | return passToStatic();
|
48 | }
|
49 |
|
50 | name.orig = parseUrl(req).pathname;
|
51 | if (name.orig[name.orig.length - 1] === '/') {
|
52 | name.gz = name.orig;
|
53 | name.orig += options.index;
|
54 | name.index = options.index + '.gz';
|
55 | } else {
|
56 | name.gz = name.orig + '.gz';
|
57 | }
|
58 | name.full = path.join(root, name.orig + '.gz');
|
59 | debug('request %s, check for %s', req.url, name.full);
|
60 |
|
61 | if (!gzipCache[name.full]) {
|
62 | debug('Passing %s', req.url);
|
63 | return passToStatic();
|
64 | }
|
65 |
|
66 | debug('Sending %s', name.full);
|
67 | setHeader(res, name.orig);
|
68 | send(req, name.gz, {
|
69 | maxAge: options.maxAge || 0,
|
70 | root: root,
|
71 | index: name.index,
|
72 | dotfiles: options.dotfiles
|
73 | })
|
74 | .on('error', next)
|
75 | .pipe(res);
|
76 | };
|
77 | };
|