Permalink
Browse files

Refactored tests and improved the coverage a lot. Made sure that gzip…

… middleware now works with various ways of setting headers and writing to the response. Had to make a small change to expresso to support requests for binary files.
  • Loading branch information...
1 parent 79a74c5 commit 5903b7e843bbdb673d13e0f61acce4fdd9f67321 @nateps committed Apr 23, 2011
View
@@ -1,26 +1,37 @@
-
/*!
* Ext JS Connect
* Copyright(c) 2010 Sencha Inc.
* MIT Licensed
*/
-/**
- * Module dependencies.
- */
-
var spawn = require('child_process').spawn,
sys = require('sys');
/**
- * Provides gzip compression via the `gzip` executable.
+ * Connect middleware providing gzip compression on the fly. By default, it
+ * compresses requests with mime types that match the expression
+ * /text|javascript|json/.
+ *
+ * Options:
*
- * @return {Function}
+ * - `matchType` Regular expression matching mime types to be compressed
+ * - `flags` String of flags passed to the binary. Nothing by default
+ * - `bin` Binary executable defaulting to "gzip"
+ *
+ * @param {Object} options
* @api public
*/
-module.exports = function gzip(matchType){
- matchType = matchType || /text|javascript|json/;
+exports = module.exports = function gzip(options) {
+ var options = options || {},
+ matchType = options.matchType || /text|javascript|json/,
+ bin = options.bin || 'gzip',
+ flags = options.flags || '';
+
+ if (!matchType.test) throw new Error('option matchType must be a regular expression');
+
+ flags = (flags) ? '-c ' + flags : '-c';
+ flags = flags.split(' ');
return function gzip(req, res, next) {
var writeHead = res.writeHead,
@@ -29,7 +40,6 @@ module.exports = function gzip(matchType){
['write', 'end'].forEach(function(name) {
defaults[name] = res[name];
res[name] = function() {
- res[name] = defaults[name];
// Make sure headers are setup if they haven't been called yet
if (res.writeHead !== writeHead) {
res.writeHead(res.statusCode);
@@ -42,7 +52,7 @@ module.exports = function gzip(matchType){
var args = Array.prototype.slice.call(arguments, 0),
write = defaults.write,
end = defaults.end,
- headers, key, type, accept, gzip;
+ headers, key, accept, type, encoding, gzip;
if (args.length > 1) {
headers = args.pop();
for (key in headers) {
@@ -56,14 +66,16 @@ module.exports = function gzip(matchType){
if (code !== 200 || !~accept.indexOf('gzip') ||
!matchType.test(type) || encoding) {
+ res.write = write;
+ res.end = end;
return finish();
}
res.setHeader('Content-Encoding', 'gzip');
res.setHeader('Vary', 'Accept-Encoding');
res.removeHeader('Content-Length');
- gzip = spawn('gzip', ['--best', '-c']);
+ gzip = spawn(bin, flags);
res.write = function(chunk, encoding) {
gzip.stdin.write(chunk, encoding);
View
@@ -7,57 +7,51 @@
var fs = require('fs'),
parse = require('url').parse,
path = require('path'),
+ mime = require('mime'),
exec = require('child_process').exec,
- staticSend = require('connect').static.send,
- bin = 'gzip', // Default command for gzip binary
- flags = '--best'; // Default flags passed to gzip
+ staticSend = require('connect').static.send;
/**
- * staticGzip gzips statics via whitelist of extensions specified
- * by the `extensions` option. Once created, `staticProvider` can continue
- * on to serve the gzipped version of the file.
+ * staticGzip gzips statics and then serves them with the regular Connect
+ * static provider. By default, it compresses files with mime types that
+ * match the expression /text|javascript|json/.
*
* Options:
*
- * - `root` Root direction from which to generate gzipped statics
- * - `extensions` Array of extensions serving as a whitelist
- * - `flags` String of flags passed to the binary
+ * - `matchType` Regular expression matching mime types to be compressed
+ * - `flags` String of flags passed to the binary. Defaults to "--best"
* - `bin` Binary executable defaulting to "gzip"
*
+ * @param {String} root
* @param {Object} options
* @api public
*/
exports = module.exports = function staticGzip(root, options) {
var options = options || {},
- extensions = options.extensions,
- whitelist = {};
+ matchType = options.matchType || /text|javascript|json/,
+ bin = options.bin || 'gzip',
+ flags = options.flags || '--best';
if (!root) throw new Error('staticGzip root must be set');
- if (!extensions) throw new Error('staticGzip extensions array must be passed');
-
- if (options.bin) bin = options.bin;
- if (options.flags) flags = options.flags;
-
- extensions.forEach(function(item) {
- whitelist[item] = true;
- });
+ if (!matchType.test) throw new Error('option matchType must be a regular expression');
return function(req, res, next) {
- var acceptEncoding, url, filename, ext;
+ var url, filename, type, acceptEncoding;
if (req.method !== 'GET') return next();
url = parse(req.url);
filename = path.join(root, url.pathname);
if ('/' == filename[filename.length - 1]) filename += 'index.html';
- ext = path.extname(filename);
- acceptEncoding = req.headers['accept-encoding'] || '';
+ type = mime.lookup(filename);
+ if (!matchType.test(type)) {
+ return passToStatic(filename);
+ }
- // When the extension is not whitelisted or Accept-Encoding does not allow
- // gzip, pass along to the regular static provider
- if (!whitelist[ext] || !~acceptEncoding.indexOf('gzip')) {
+ acceptEncoding = req.headers['accept-encoding'] || '';
+ if (!~acceptEncoding.indexOf('gzip')) {
return passToStatic(filename);
}
@@ -74,7 +68,7 @@ exports = module.exports = function staticGzip(root, options) {
fs.stat(gzipname, function(err) {
if (err && err.code === 'ENOENT') {
// Gzipped file doesn't exist, so make it then send
- gzip(filename, gzipname, function(err) {
+ gzip(bin, flags, filename, gzipname, function(err) {
return sendGzip();
});
} else if (err) {
@@ -99,15 +93,7 @@ exports = module.exports = function staticGzip(root, options) {
}
};
-/**
- * Gzip `src` to `dest`.
- *
- * @param {String} src
- * @param {String} dest
- * @api private
- */
-
-function gzip(src, dest, callback) {
+function gzip(bin, flags, src, dest, callback) {
var cmd = bin + ' ' + flags + ' -c ' + src + ' > ' + dest;
exec(cmd, function(err, stdout, stderr) {
if (err) {
View
@@ -1,10 +1,11 @@
{
"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",
+ "description": "Gzip middleware for Connect. Based on implementation in Connect 0.5.9. Original source: https://github.com/senchalabs/connect/tree/c9a0c1e0e98451bb5fffb70c622b827a11bf4fc7",
"version": "0.0.1",
"author": "Nate Smith",
- "main" : "./index.js",
+ "main": "./index.js",
"dependencies": {
- "connect": "*"
+ "connect": ">= 1.0.0",
+ "mime": ">= 0.0.1"
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View
@@ -1 +1,4 @@
-body { font-size: 12px; color: red; }
+body {
+ font-size: 12px;
+ color: red;
+}
Oops, something went wrong.

0 comments on commit 5903b7e

Please sign in to comment.