comunicationLeap/node_modules/connect/lib/middleware/compress.js
node_modules/connect/lib/middleware/compress.jsRaw
1/*!
2 * Connect - compress
3 * Copyright(c) 2010 Sencha Inc.
4 * Copyright(c) 2011 TJ Holowaychuk
5 * MIT Licensed
6 */
7
8/**
9 * Module dependencies.
10 */
11
12var zlib = require('zlib');
13
14/**
15 * Supported content-encoding methods.
16 */
17
18exports.methods = {
19 gzip: zlib.createGzip
20 , deflate: zlib.createDeflate
21};
22
23/**
24 * Default filter function.
25 */
26
27exports.filter = function(req, res){
28 return /json|text|javascript/.test(res.getHeader('Content-Type'));
29};
30
31/**
32 * Compress:
33 *
34 * Compress response data with gzip/deflate.
35 *
36 * Filter:
37 *
38 * A `filter` callback function may be passed to
39 * replace the default logic of:
40 *
41 * exports.filter = function(req, res){
42 * return /json|text|javascript/.test(res.getHeader('Content-Type'));
43 * };
44 *
45 * Options:
46 *
47 * All remaining options are passed to the gzip/deflate
48 * creation functions. Consult node's docs for additional details.
49 *
50 * - `chunkSize` (default: 16*1024)
51 * - `windowBits`
52 * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
53 * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
54 * - `strategy`: compression strategy
55 *
56 * @param {Object} options
57 * @return {Function}
58 * @api public
59 */
60
61module.exports = function compress(options) {
62 options = options || {};
63 var names = Object.keys(exports.methods)
64 , filter = options.filter || exports.filter;
65
66 return function compress(req, res, next){
67 var accept = req.headers['accept-encoding']
68 , vary = res.getHeader('Vary')
69 , write = res.write
70 , end = res.end
71 , stream
72 , method;
73
74 // vary
75 if (!vary) {
76 res.setHeader('Vary', 'Accept-Encoding');
77 } else if (!~vary.indexOf('Accept-Encoding')) {
78 res.setHeader('Vary', vary + ', Accept-Encoding');
79 }
80
81 // see #724
82 req.on('close', function(){
83 res.write = res.end = function(){};
84 });
85
86 // proxy
87
88 res.write = function(chunk, encoding){
89 if (!this.headerSent) this._implicitHeader();
90 return stream
91 ? stream.write(new Buffer(chunk, encoding))
92 : write.call(res, chunk, encoding);
93 };
94
95 res.end = function(chunk, encoding){
96 if (chunk) this.write(chunk, encoding);
97 return stream
98 ? stream.end()
99 : end.call(res);
100 };
101
102 res.on('header', function(){
103 var encoding = res.getHeader('Content-Encoding') || 'identity';
104
105 // already encoded
106 if ('identity' != encoding) return;
107
108 // default request filter
109 if (!filter(req, res)) return;
110
111 // SHOULD use identity
112 if (!accept) return;
113
114 // head
115 if ('HEAD' == req.method) return;
116
117 // default to gzip
118 if ('*' == accept.trim()) method = 'gzip';
119
120 // compression method
121 if (!method) {
122 for (var i = 0, len = names.length; i < len; ++i) {
123 if (~accept.indexOf(names[i])) {
124 method = names[i];
125 break;
126 }
127 }
128 }
129
130 // compression method
131 if (!method) return;
132
133 // compression stream
134 stream = exports.methods[method](options);
135
136 // header fields
137 res.setHeader('Content-Encoding', method);
138 res.removeHeader('Content-Length');
139
140 // compression
141
142 stream.on('data', function(chunk){
143 write.call(res, chunk);
144 });
145
146 stream.on('end', function(){
147 end.call(res);
148 });
149
150 stream.on('drain', function() {
151 res.emit('drain');
152 });
153 });
154
155 next();
156 };
157};