Permalink
Browse files

Inital Commit

  • Loading branch information...
0 parents commit f0b5d92d82911cba7141e04cf794a39bc22dc124 @tomgco committed May 18, 2011
Showing with 227 additions and 0 deletions.
  1. +12 −0 .gitignore
  2. +51 −0 README.md
  3. +1 −0 index.js
  4. +145 −0 lib/staticGzip.js
  5. +18 −0 package.json
@@ -0,0 +1,12 @@
+node_modules/*
+.DS_STORE
+*.swp
+*.monitor
+nodemon-ignore
+.*.sw[a-z]
+*.un~i
+.DS_Store
+Icon?
+._*
+.Spotlight-V100
+.Trashes
@@ -0,0 +1,51 @@
+# gzippo
+
+gzippo pronounced `g-zippo` is a gzip middleware for Connect using Compress for better performace.
+
+## Installation
+ //Currently not up
+ $ npm install gzippo
+
+### Usage
+
+In your express/connect server setup, use as follows:
+ var gzippo = require('gzippo');
+
+ //Replace the static provider with gzippo's
+ //app.use(express.static(__dirname + '/public'));
+ app.use(gzippo.staticGzip({ src: __dirname + '/public' }));
+
+Options:
+
+- `matchType` - A regular expression tested against the Content-Type header to determine whether the response should be gzipped or not. The default value is `/text|javascript|json/`.
+- `maxAge` - cache-control max-age directive, defaulting to 1 day
+
+Currently the gzipped version is created and stored in memory. This is not final and was done to get a working version
+up and about. A version which will gzip text/html after res.render() / res.end() is in progress.
+
+[node-compress](https://github.com/waveto/node-compress) gzip library is used for gzipping.
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 Tom Gallacher &lt;<http://www.tomgallacher.info>&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
+exports.staticGzip = require("./lib/staticGzip.js");
@@ -0,0 +1,145 @@
+/*!
+ * Tom Gallacher
+ *
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs'),
+ parse = require('url').parse,
+ path = require('path'),
+ mime = require('mime'),
+ compress = require('compress'),
+ staticSend = require('connect').static.send;
+
+/**
+ * gzipped cache.
+ */
+
+var gzippoCache = {};
+
+/**
+ * gzip file.
+ */
+
+var gzippo = function(filename, callback) {
+ var gzip = new compress.Gzip();
+ gzip.init();
+ fs.readFile(filename, function (err, data) {
+ if (err) throw err;
+ var gzippedData = gzip.deflate(data, 'binary') + gzip.end();
+ callback(err, gzippedData);
+ });
+};
+
+/**
+ * By default gzip's static's that match the given regular expression /text|javascript|json/
+ * and then serves them with Connects static provider, denoted by the given `dirPath`.
+ *
+ * Options:
+ *
+ * - `maxAge` cache-control max-age directive, defaulting to 1 day
+ * - `matchType` - A regular expression tested against the Content-Type header to determine whether the response
+ * should be gzipped or not. The default value is `/text|javascript|json/`.
+ *
+ * Examples:
+ *
+ * connect.createServer(
+ * connect.staticGzip(__dirname + '/public/');
+ * );
+ *
+ * connect.createServer(
+ * connect.staticGzip(__dirname + '/public/', {maxAge: 86400000});
+ * );
+ *
+ * @param {String} path
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+exports = module.exports = function staticGzip(dirPath, options){
+ options = options || {};
+ dirPath = dirPath || __dirname + '/public/';
+ var maxAge = options.maxAge || 86400000,
+ contentTypeMatch = options.contentTypeMatch || /text|javascript|json/;
+
+ if (!contentTypeMatch.test) throw new Error('contentTypeMatch: must be a regular expression.');
+
+ return function staticGzip(req, res, next){
+ var url, filename, contentType, acceptEncoding;
+
+ function pass(name) {
+ var o = Object.create(options);
+ o.path = name;
+ staticSend(req, res, next, o);
+ }
+
+ function sendGzipped(data) {
+ var charset = mime.charsets.lookup(contentType);
+ contentType = contentType + (charset ? '; charset=' + charset : '');
+ res.setHeader('Content-Type', contentType);
+ res.setHeader('Content-Encoding', 'gzip');
+ res.setHeader('Vary', 'Accept-Encoding');
+ res.setHeader('Content-Length', data.length);
+ res.end(data, 'binary');
+ }
+
+ function gzipAndSend(filename, gzipName) {
+ gzippo(filename, function(err, gzippedData) {
+ gzippoCache[gzipName] = {
+ 'mtime': Date.now(),
+ 'content': gzippedData
+ };
+ sendGzipped(gzippedData);
+ });
+ }
+
+
+ if (req.method !== 'GET') {
+ return next();
+ }
+
+ url = parse(req.url);
+ filename = path.join(dirPath, url.pathname);
+
+ contentType = mime.lookup(filename);
+ acceptEncoding = req.headers['accept-encoding'] || '';
+
+ if (!contentTypeMatch.test(contentType)) {
+ return pass(filename);
+ }
+
+ if (!~acceptEncoding.indexOf('gzip')) {
+ return pass(filename);
+ }
+
+ //This is storing in memory for the moment, need to think what the best way to do this.
+ //Check file is not a directory
+
+ fs.stat(filename, function(err, stat) {
+ if (err || stat.isDirectory()) {
+ return pass(filename);
+ }
+
+ var base = path.basename(filename),
+ dir = path.dirname(filename),
+ gzipName = path.join(dir, base + '.gz');
+
+ //check for pre-compressed file
+ //TODO: Look into placing into a loop and using dot notation for speed improvements.
+ if (typeof gzippoCache[gzipName] === 'undefined') {
+ gzipAndSend(filename, gzipName);
+ } else {
+ if ((gzippoCache[gzipName].mtime + maxAge) < Date.now()) {
+ gzipAndSend(filename, gzipName);
+ } else {
+ sendGzipped(gzippoCache[gzipName].content);
+ }
+ }
+ });
+ };
+};
@@ -0,0 +1,18 @@
+{
+"name" : "gzippo",
+"version" : "0.0.1",
+"author" : "Tom Gallacher",
+"description" : "Gzip middleware for Connect using Compress for better performace.",
+"homepage" : "http://tomgallacher.info/gzippo",
+"repository":
+ {
+ "type": "git",
+ "url": "git://github.com/tomgallacher/gzippo.git"
+ },
+"engines" : { "node" : "*" },
+"main" : "./index.js",
+"dependencies" :
+ {
+ "compress" : "0.1.9"
+ }
+}

0 comments on commit f0b5d92

Please sign in to comment.