Comparing version 0.0.3 to 0.0.4
@@ -6,6 +6,9 @@ var Options = require('options') | ||
module.exports = SSE; | ||
module.exports.Client = SSEClient; | ||
function SSE(httpServer, options) { | ||
options = new Options({ | ||
path: '/sse', | ||
verifyRequest: null | ||
path : '/sse', | ||
verifyRequest : null | ||
}).merge(options); | ||
@@ -17,4 +20,3 @@ this.server = httpServer; | ||
this.server.on('request', function(req, res) { | ||
if (req.url == options.value.path && | ||
(options.value.verifyRequest == null || options.value.verifyRequest(req))) { | ||
if (req.url == options.value.path && (options.value.verifyRequest == null || options.value.verifyRequest(req))) { | ||
self.handleRequest(req, res); | ||
@@ -30,19 +32,8 @@ } | ||
/** | ||
* Inherits from EventEmitter. | ||
*/ | ||
util.inherits(SSE, events.EventEmitter); | ||
SSE.prototype.handleRequest = function(req, res) { | ||
req.socket.setNoDelay(true); | ||
var isLegacy = req.headers['user-agent'] && (/^Opera[^\/]*\/9/).test(req.headers['user-agent']); | ||
if (isLegacy) { | ||
res.writeHead(200, {'Content-Type': 'text/x-dom-event-stream'}); | ||
} | ||
else res.writeHead(200, {'Content-Type': 'text/event-stream'}); | ||
res.write(':ok\n\n'); | ||
this.emit('connection', new SSEClient(req, res, isLegacy)); | ||
var client = new SSEClient(req, res); | ||
client.initialize(); | ||
this.emit('connection', client); | ||
} | ||
module.exports = SSE; |
@@ -1,8 +0,9 @@ | ||
var util = require('util') | ||
, events = require('events'); | ||
var util = require('util'), | ||
events = require('events'); | ||
function SSEClient(req, res, isLegacy) { | ||
module.exports = SSEClient; | ||
function SSEClient(req, res) { | ||
this.req = req; | ||
this.res = res; | ||
this.isLegacy = isLegacy; | ||
var self = this; | ||
@@ -14,28 +15,48 @@ res.on('close', function() { | ||
/** | ||
* Inherits from EventEmitter. | ||
*/ | ||
util.inherits(SSEClient, events.EventEmitter); | ||
SSEClient.prototype.initialize = function() { | ||
this.req.socket.setNoDelay(true); | ||
this.res.writeHead(200, { | ||
'Content-Type': 'text/event-stream', | ||
'Cache-Control': 'no-cache', | ||
'Connection': 'keep-alive' | ||
}); | ||
this.res.write(':ok\n\n'); | ||
}; | ||
SSEClient.prototype.send = function(event, data, id) { | ||
if (arguments.length == 0) return; | ||
if (arguments.length == 1) { | ||
data = event; | ||
event = null; | ||
if (arguments.length === 0) return; | ||
var senderObject = { | ||
event : event || undefined, | ||
data : data || undefined, | ||
id : id || undefined, | ||
retry : undefined | ||
}; | ||
if (typeof event == 'object') { | ||
senderObject.event = event.event || undefined, | ||
senderObject.data = event.data || undefined, | ||
senderObject.id = event.id || undefined, | ||
senderObject.retry = event.retry || undefined | ||
} | ||
if (this.isLegacy) { | ||
this.res.write('Event: data\n'); | ||
if (typeof event != 'object' && arguments.length === 1) { | ||
senderObject.event = undefined; | ||
senderObject.data = event; | ||
} | ||
else { | ||
if (typeof event !== 'undefined' && event !== null) this.res.write('event:' + event + '\n'); | ||
if (typeof id !== 'undefined' && event !== null) this.res.write('id:' + id + '\n'); | ||
} | ||
data = data.replace(/(\r\n|\r|\n)/g, '\n'); | ||
var dataLines = data.split(/\n/); | ||
if (senderObject.event) this.res.write('event: ' + senderObject.event + '\n'); | ||
if (senderObject.retry) this.res.write('retry: ' + senderObject.retry + '\n'); | ||
if (senderObject.id) this.res.write('id: ' + senderObject.id + '\n'); | ||
senderObject.data = senderObject.data.replace(/(\r\n|\r|\n)/g, '\n'); | ||
var dataLines = senderObject.data.split(/\n/); | ||
for (var i = 0, l = dataLines.length; i < l; ++i) { | ||
var line = dataLines[i]; | ||
this.res.write('data:' + (this.isLegacy ? ' ' : '') + line + '\n'); | ||
if ((i+1) === l) this.res.write('data: ' + line + '\n\n'); | ||
else this.res.write('data: ' + line + '\n'); | ||
} | ||
this.res.write('\n'); | ||
} | ||
@@ -46,3 +67,1 @@ | ||
} | ||
module.exports = SSEClient; |
{ | ||
"author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)", | ||
"name": "sse", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"repository": { | ||
@@ -6,0 +6,0 @@ "type": "git", |
@@ -98,25 +98,23 @@ var SSE = require('../') | ||
}); | ||
}); | ||
it('has content-type set to text/x-dom-event-stream for Opera <v10', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
request('http://localhost:' + port + '/sse', function(res) { | ||
expect(res.headers['content-type']).to.equal('text/x-dom-event-stream'); | ||
done(); | ||
}, { 'user-agent': 'Opera/9.80' }); | ||
}); | ||
}); | ||
describe('client', function() { | ||
it('is exported', function(done) { | ||
expect(SSE.Client); | ||
it('has content-type set to text/event-stream for Opera =>v10', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
request('http://localhost:' + port + '/sse', function(res) { | ||
expect(res.headers['content-type']).to.equal('text/event-stream'); | ||
done(); | ||
}, { 'user-agent': 'Opera/10' }); | ||
sse.on('connection', function(client) { | ||
expect(client instanceof SSE.Client); | ||
client.on('close', function() { | ||
server.close(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
request('http://localhost:' + port + '/sse', function(res) { | ||
res.socket.end(); | ||
}); | ||
}); | ||
}); | ||
describe('client', function() { | ||
describe('emits', function() { | ||
@@ -173,3 +171,3 @@ it('a "close" event when a client connects', function(done) { | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foo\ndata:bar\ndata:baz\n\n'); | ||
expect(streamData).to.equal('data: foo\ndata: bar\ndata: baz\n\n'); | ||
done(); | ||
@@ -195,3 +193,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foo\ndata:bar\ndata:baz\n\n'); | ||
expect(streamData).to.equal('data: foo\ndata: bar\ndata: baz\n\n'); | ||
done(); | ||
@@ -217,3 +215,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foo\ndata:bar\ndata:baz\n\n'); | ||
expect(streamData).to.equal('data: foo\ndata: bar\ndata: baz\n\n'); | ||
done(); | ||
@@ -239,3 +237,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foo\ndata:\ndata:bar\ndata:\ndata:baz\ndata:\ndata:\n\n'); | ||
expect(streamData).to.equal('data: foo\ndata: \ndata: bar\ndata: \ndata: baz\ndata: \ndata: \n\n'); | ||
done(); | ||
@@ -247,10 +245,31 @@ }); | ||
it('sends a message witch goes over only one line', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foo'); | ||
client.close(); | ||
}); | ||
request('http://localhost:' + port + '/sse', function(res) { | ||
var streamData = ''; | ||
res.on('data', function(data) { | ||
streamData += data.toString('utf8'); | ||
}); | ||
res.on('end', function() { | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data: foo\n\n'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('without an event name or id', function() { | ||
it('sends a message event', function(done) { | ||
describe('first function attribute to send method as object', function() { | ||
it('passes a object to the first attribute, all other attributes is ignored', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foobar'); | ||
client.send({data:'foo'}, 'bar'); | ||
client.close(); | ||
@@ -265,3 +284,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foobar\n\n'); | ||
expect(streamData).to.equal('data: foo\n\n'); | ||
done(); | ||
@@ -272,10 +291,8 @@ }); | ||
}); | ||
}); | ||
describe('with custom event name', function() { | ||
it('sends a foobar event', function(done) { | ||
it('sends a message with only data value', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foobar', 'somedata'); | ||
client.send({data:'foo'}); | ||
client.close(); | ||
@@ -290,3 +307,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('event:foobar\ndata:somedata\n\n'); | ||
expect(streamData).to.equal('data: foo\n\n'); | ||
done(); | ||
@@ -297,10 +314,31 @@ }); | ||
}); | ||
it('sends a message with all object values set', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send({data:'foo',event:'bar',id:1,retry:6000}); | ||
client.close(); | ||
}); | ||
request('http://localhost:' + port + '/sse', function(res) { | ||
var streamData = ''; | ||
res.on('data', function(data) { | ||
streamData += data.toString('utf8'); | ||
}); | ||
res.on('end', function() { | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('event: bar\nretry: 6000\nid: 1\ndata: foo\n\n'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('with custom id', function() { | ||
it('sends a foobar event', function(done) { | ||
describe('without an event name or id', function() { | ||
it('sends a message event', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foobar', 'somedata', 100); | ||
client.send('foobar'); | ||
client.close(); | ||
@@ -315,3 +353,3 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('event:foobar\nid:100\ndata:somedata\n\n'); | ||
expect(streamData).to.equal('data: foobar\n\n'); | ||
done(); | ||
@@ -324,8 +362,8 @@ }); | ||
describe('Opera support', function() { | ||
it('uses legacy mode for <v10', function(done) { | ||
describe('with custom event name', function() { | ||
it('sends a foobar event', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foo\nbar'); | ||
client.send('foobar', 'somedata'); | ||
client.close(); | ||
@@ -340,14 +378,16 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('Event: data\ndata: foo\ndata: bar\n\n'); | ||
expect(streamData).to.equal('event: foobar\ndata: somedata\n\n'); | ||
done(); | ||
}); | ||
}, { 'user-agent': 'Opera/9.80' }); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it('uses normal mode for >=v10', function(done) { | ||
describe('with custom id', function() { | ||
it('sends a foobar event', function(done) { | ||
var server = listen(++port, function() { | ||
var sse = new SSE(server); | ||
sse.on('connection', function(client) { | ||
client.send('foo\nbar'); | ||
client.send('foobar', 'somedata', 100); | ||
client.close(); | ||
@@ -362,6 +402,6 @@ }); | ||
streamData = stripComments(streamData); | ||
expect(streamData).to.equal('data:foo\ndata:bar\n\n'); | ||
expect(streamData).to.equal('event: foobar\nid: 100\ndata: somedata\n\n'); | ||
done(); | ||
}); | ||
}, { 'user-agent': 'Opera/10.00' }); | ||
}); | ||
}); | ||
@@ -368,0 +408,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
463169
230
0
9660
40
18