diff --git a/examples/chat/app.js b/examples/chat/app.js index cc594c26c8..7c2d2ed939 100644 --- a/examples/chat/app.js +++ b/examples/chat/app.js @@ -61,6 +61,14 @@ app.listen(3000, function () { var io = sio.listen(app) , nicknames = {}; +io.set('transports', [ + 'websocket' + , 'flashsocket' + , 'htmlfile' + , 'xhr-polling' + , 'jsonp-polling' +]); + io.sockets.on('connection', function (socket) { socket.on('user message', function (msg) { socket.broadcast.emit('user message', socket.nickname, msg); diff --git a/lib/manager.js b/lib/manager.js index 31e4e69f49..2f68d86697 100644 --- a/lib/manager.js +++ b/lib/manager.js @@ -233,9 +233,9 @@ Manager.prototype.handleRequest = function (req, res) { return; } - if (!data.transport && !data.protocol) { - if (data.path == '/socket.io.js' && this.enabled('browser client')) { - this.handleClientRequest(req, res); + if (data.static || !data.transport && !data.protocol) { + if (data.static && this.enabled('browser client')) { + this.handleClientRequest(req, res, data); } else { res.writeHead(200); res.end('Welcome to socket.io.'); @@ -356,54 +356,78 @@ Manager.prototype.handleClient = function (data, req) { }); }; +/** + * Dictionary for static file serving + * + * @api public + */ + +Manager.static = { + cache:{} +, paths: { + '/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf' + , '/static/flashsocket/WebSocketMainInsecure.swf': client.dist + '/WebSocketMainInsecure.swf' + , '/socket.io.js': client.dist + '/socket.io.js' + , '/socket.io.js.min': client.dist + '/socket.io.min.js' + } +, contentType: { + 'js': 'application/javascript' + , 'swf': 'application/x-shockwave-flash' + } +, encoding:{ + 'js': 'utf8' + , 'swf': 'binary' + } +}; + /** * Serves the client. * * @api private */ -Manager.prototype.handleClientRequest = function (req, res) { +Manager.prototype.handleClientRequest = function (req, res, data) { + var static = Manager.static + , extension = data.path.split('.').pop() + , file = data.path + (this.enabled('browser client minification') && extension == 'js' ? '.min' : '') + , location = static.paths[file] + , cache = static.cache[file]; + var self = this; function serve () { - if (!self.clientLength) { - self.clientLength = Buffer.byteLength(self.client); - } - var headers = { - 'Content-Type': 'application/javascript' - , 'Content-Length': self.clientLength + 'Content-Type': static.contentType[extension] + , 'Content-Length': cache.length }; - if (self.enabled('browser client etag') && self.clientEtag) { - headers.ETag = self.clientEtag; + if (self.enabled('browser client etag') && cache.Etag) { + headers.Etag = cache.Etag; } res.writeHead(200, headers); - res.end(self.client); + res.end(cache.content, cache.encoding); - self.log.debug('served client'); - }; + self.log.debug('served static ' + data.path); + } if (this.get('browser client handler')) { this.get('browser client handler').call(this, req, res); - } else if (!this.client) { - var file = this.enabled('browser client minification') - ? 'socket.io.min.js' - : 'socket.io.js'; - - fs.readFile(client.dist + '/' + file, function (err, data) { + } else if (!cache) { + fs.readFile(location, function (err, data) { if (err) { res.writeHead(500); res.end('Error serving socket.io client.'); - self.log.warn('Can\'t cache socket.io client'); + self.log.warn('Can\'t cache socket.io client, ' + err.message); return; } - self.client = data.toString(); - self.clientEtag = client.version; - self.log.debug('caching', client.version, 'client'); + cache = Manager.static.cache[file] = { + content: data.toString() + , length: data.length + , Etag: client.version + }; serve(); }); @@ -588,6 +612,7 @@ Manager.prototype.checkRequest = function (req) { data.protocol = Number(pieces[1]); data.transport = pieces[2]; data.id = pieces[3]; + data.static = !!Manager.static.paths[path]; }; return data; diff --git a/test/manager.test.js b/test/manager.test.js index d8ba29e6c3..a7725effb6 100644 --- a/test/manager.test.js +++ b/test/manager.test.js @@ -185,7 +185,8 @@ module.exports = { should.strictEqual(res.headers.etag, undefined); data.should.match(/XMLHttpRequest/); - io.client.should.match(/XMLHttpRequest/); + var static = sio.Manager.static; + static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/); cl.get('/socket.io/socket.io.js', function (res, data) { res.headers['content-type'].should.eql('application/javascript'); @@ -216,7 +217,8 @@ module.exports = { res.headers.etag.should.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/); data.should.match(/XMLHttpRequest/); - io.client.should.match(/XMLHttpRequest/); + var static = sio.Manager.static; + static.cache['/socket.io.js'].content.should.match(/XMLHttpRequest/); cl.get('/socket.io/socket.io.js', function (res, data) { res.headers['content-type'].should.eql('application/javascript'); @@ -267,6 +269,38 @@ module.exports = { }); }, + 'test that the WebSocketMain.swf is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/static/flashsocket/WebSocketMain.swf', function (res, data) { + res.headers['content-type'].should.eql('application/x-shockwave-flash'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + cl.end(); + io.server.close(); + done(); + }); + }, + + 'test that the WebSocketMainInsecure.swf is served': function (done) { + var port = ++ports + , io = sio.listen(port) + , cl = client(port); + + cl.get('/socket.io/static/flashsocket/WebSocketMainInsecure.swf', function (res, data) { + res.headers['content-type'].should.eql('application/x-shockwave-flash'); + res.headers['content-length'].should.match(/([0-9]+)/); + should.strictEqual(res.headers.etag, undefined); + + cl.end(); + io.server.close(); + done(); + }); + }, + 'test that you can serve custom clients': function (done) { var port = ++ports , io = sio.listen(port)