Permalink
Browse files

Initial copy of connect gzip middleware into new repo.

  • Loading branch information...
0 parents commit 5425b4492200ca017d0de0570942fb88e567abab @nateps committed Apr 9, 2011
Showing with 313 additions and 0 deletions.
  1. 0 README
  2. +2 −0 index.js
  3. +77 −0 lib/gzip-compress.js
  4. +73 −0 lib/gzip-proc.js
  5. +8 −0 lib/gzip.js
  6. +147 −0 lib/staticGzip.js
  7. +6 −0 package.json
No changes.
@@ -0,0 +1,2 @@
+exports.gzip = require('./lib/gzip');
+exports.staticGzip = require('./lib/staticGzip');
@@ -0,0 +1,77 @@
+
+/*!
+ * Ext JS Connect
+ * Copyright(c) 2010 Sencha Inc.
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var compress = require('compress');
+
+/**
+ * Provides gzip compression via the node-compress library.
+ *
+ * @return {Function}
+ * @api public
+ */
+
+module.exports = function gzip(){
+ return function gzip(req, res, next) {
+ var writeHead = res.writeHead,
+ write = res.write,
+ end = res.end;
+
+ res.writeHead = function (code, headers) {
+ var type = headers["Content-Type"],
+ accept = req.headers["accept-encoding"];
+
+ if (!(code === 200 && accept && accept.indexOf('gzip') >= 0
+ && type && (/(text|javascript|json)/).test(type)
+ && headers["Content-Encoding"] === undefined)) {
+ res.writeHead = writeHead;
+ res.writeHead(code, headers);
+ return;
+ }
+
+ headers["Content-Encoding"] = "gzip";
+ delete headers["Content-Length"];
+
+ var gzip = new compress.GzipStream();
+
+ res.write = function (chunk, encoding) {
+ gzip.setInputEncoding(encoding);
+ gzip.write(chunk);
+ };
+
+ res.end = function (chunk, encoding) {
+ if (chunk) {
+ res.write(chunk, encoding);
+ }
+ gzip.close();
+ };
+
+ gzip.addListener('data', function (chunk) {
+ write.call(res, chunk);
+ });
+ gzip.addListener('error', function(err) {
+ res.write = write;
+ res.end = end;
+ next(err);
+ });
+ gzip.addListener('end', function (code) {
+ res.write = write;
+ res.end = end;
+ res.end();
+ });
+
+ res.writeHead = writeHead;
+ res.writeHead(code, headers);
+
+ };
+
+ next();
+ };
+};
@@ -0,0 +1,73 @@
+
+/*!
+ * Ext JS Connect
+ * Copyright(c) 2010 Sencha Inc.
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var child_process = require('child_process'),
+ sys = require('sys');
+
+/**
+ * Provides gzip compression via the `gzip` executable.
+ *
+ * @return {Function}
+ * @api public
+ */
+
+module.exports = function gzip(){
+ return function gzip(req, res, next) {
+ var writeHead = res.writeHead,
+ write = res.write,
+ end = res.end;
+
+ res.writeHead = function (code, headers) {
+ var type = headers["Content-Type"],
+ accept = req.headers["accept-encoding"];
+
+ if (!(code === 200 && accept && accept.indexOf('gzip') >= 0
+ && type && (/(text|javascript|json)/).test(type)
+ && headers["Content-Encoding"] === undefined)) {
+ res.writeHead = writeHead;
+ res.writeHead(code, headers);
+ return;
+ }
+
+ headers["Content-Encoding"] = "gzip";
+ delete headers["Content-Length"];
+
+ var gzip = child_process.spawn("gzip", ["-9"]);
+
+ res.write = function (chunk, encoding) {
+ gzip.stdin.write(chunk, encoding);
+ };
+
+ res.end = function (chunk, encoding) {
+ if (chunk) {
+ res.write(chunk, encoding);
+ }
+ gzip.stdin.end();
+ };
+
+ gzip.stdout.addListener('data', function (chunk) {
+ write.call(res, chunk);
+ });
+
+ gzip.addListener("exit", function (code) {
+ res.write = write;
+ res.end = end;
+ res.end();
+ });
+
+ res.writeHead = writeHead;
+ res.writeHead(code, headers);
+
+ };
+
+ next();
+ };
+};
@@ -0,0 +1,8 @@
+try {
+ module.exports = require('./gzip-compress');
+} catch (e) {
+ if (/^Cannot find module /.test(e.message))
+ module.exports = require('./gzip-proc');
+ else
+ throw e;
+}
@@ -0,0 +1,147 @@
+
+/*!
+ * Ext JS Connect
+ * Copyright(c) 2010 Sencha Inc.
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs'),
+ parse = require('url').parse
+ path = require('path'),
+ exec = require('child_process').exec,
+ mime = require('mime');
+
+/**
+ * Expose staticGzip as the module.
+ */
+
+exports = module.exports = staticGzip;
+
+/**
+ * Gzip binary.
+ *
+ * @type String
+ */
+
+exports.bin = 'gzip';
+
+/**
+ * Flags passed to gzip.
+ *
+ * @type String
+ */
+
+exports.flags = '--best';
+
+/**
+ * staticGzip gzips statics via whitelist of mime types specified
+ * by the `compress` option. Once created `staticProvider` can continue
+ * on to serve the gzipped version of the file.
+ *
+ * Options:
+ *
+ * - `root` Root direction from which to generate gzipped statics
+ * - `compress` Array of mime types serving as a whitelist
+ * - `flags` String of flags passed to the binary
+ * - `bin` Binary executable defaulting to "gzip"
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+function staticGzip(options){
+ var options = options || {},
+ root = options.root,
+ compress = options.compress,
+ flags = options.flags || exports.flags,
+ bin = options.bin || exports.bin;
+
+ if (!root) throw new Error('staticGzip root must be set');
+ if (!compress) throw new Error('staticGzip compress array must be passed');
+
+ return function(req, res, next){
+ if (req.method !== 'GET') return next();
+
+ var acceptEncoding = req.headers['accept-encoding'] || '';
+
+ // Ignore when Accept-Encoding does not allow gzip
+ if (acceptEncoding && !~acceptEncoding.indexOf('gzip')) return next();
+
+ // Parse the url
+ var url = parse(req.url),
+ filename = path.join(root, url.pathname),
+ mime = mime.lookup(filename);
+
+ // MIME type not white-listed
+ if (!~compress.indexOf(mime)) return next();
+
+ // Check if gzipped static is available
+ gzipped(filename, function(err, path, ext){
+ if (err && err.errno === process.ENOENT) {
+ next();
+ // We were looking for a gzipped static,
+ // so lets gzip it!
+ if (err.path.indexOf('.gz') === err.path.length - 3) {
+ gzip(filename, path, flags, bin);
+ }
+ } else if (err) {
+ next(err);
+ } else {
+ // Re-write the url to serve the gzipped static
+ req.url = url.pathname + ext;
+ var writeHead = res.writeHead;
+ res.writeHead = function(status, headers){
+ headers = headers || {};
+ res.writeHead = writeHead;
+ headers['Content-Type'] = mime;
+ headers['Content-Encoding'] = 'gzip';
+ res.writeHead(status, headers);
+ };
+ next();
+ }
+ });
+ }
+};
+
+/**
+ * Check for a gzipped version of the file at `path`.
+ *
+ * @param {String} path
+ * @param {Function} fn
+ * @api private
+ */
+
+function gzipped(path, fn) {
+ fs.stat(path, function(err, stat){
+ if (err) return fn(err);
+ var ext = '.' + Number(stat.mtime) + '.gz';
+ path += ext;
+ fs.stat(path, function(err){
+ fn(err, path, ext);
+ });
+ });
+};
+
+/**
+ * Gzip `src` to `dest`.
+ *
+ * @param {String} src
+ * @param {String} dest
+ * @param {String} flags
+ * @param {String} bin
+ * @api private
+ */
+
+function gzip(src, dest, flags, bin) {
+ var cmd = bin + ' ' + flags + ' -c ' + src + ' > ' + dest;
+ exec(cmd, function(err, stdout, stderr){
+ if (err) {
+ console.error('\n' + err.stack);
+ fs.unlink(dest);
+ }
+ });
+};
@@ -0,0 +1,6 @@
+{
+ "name": "connect-gzip",
+ "description": "Gzip middleware for Connect. Copied from Connect 0.5.9 before these were removed from the main Connect implementation. Original source: https://github.com/senchalabs/connect/tree/c9a0c1e0e98451bb5fffb70c622b827a11bf4fc7",
+ "version": "0.0.1",
+ "author": "Nate Smith",
+}

0 comments on commit 5425b44

Please sign in to comment.