sockjs
Advanced tools
Comparing version 0.0.3 to 0.0.4
(function() { | ||
var $, Server, app, events, iframe, trans_eventsource, trans_jsonp, trans_websocket, trans_xhr, webjs; | ||
var Server, app, chunking_test, events, iframe, trans_eventsource, trans_htmlfile, trans_jsonp, trans_websocket, trans_xhr, utils, webjs; | ||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { | ||
@@ -13,3 +13,3 @@ for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } | ||
webjs = require('./webjs'); | ||
$ = require('jquery'); | ||
utils = require('./utils'); | ||
trans_websocket = require('./trans-websocket'); | ||
@@ -20,2 +20,4 @@ trans_jsonp = require('./trans-jsonp'); | ||
trans_eventsource = require('./trans-eventsource'); | ||
trans_htmlfile = require('./trans-htmlfile'); | ||
chunking_test = require('./chunking-test'); | ||
app = { | ||
@@ -33,8 +35,10 @@ welcome_screen: function(req, res) { | ||
}; | ||
$.extend(app, webjs.generic_app); | ||
$.extend(app, iframe.app); | ||
$.extend(app, trans_websocket.app); | ||
$.extend(app, trans_jsonp.app); | ||
$.extend(app, trans_xhr.app); | ||
$.extend(app, trans_eventsource.app); | ||
utils.objectExtend(app, webjs.generic_app); | ||
utils.objectExtend(app, iframe.app); | ||
utils.objectExtend(app, chunking_test.app); | ||
utils.objectExtend(app, trans_websocket.app); | ||
utils.objectExtend(app, trans_jsonp.app); | ||
utils.objectExtend(app, trans_xhr.app); | ||
utils.objectExtend(app, trans_eventsource.app); | ||
utils.objectExtend(app, trans_htmlfile.app); | ||
Server = (function() { | ||
@@ -52,3 +56,3 @@ __extends(Server, events.EventEmitter); | ||
if (user_options) { | ||
$.extend(this.options, user_options); | ||
utils.objectExtend(this.options, user_options); | ||
} | ||
@@ -59,5 +63,5 @@ } | ||
options = {}; | ||
$.extend(options, this.options); | ||
utils.objectExtend(options, this.options); | ||
if (user_options) { | ||
$.extend(options, user_options); | ||
utils.objectExtend(options, user_options); | ||
} | ||
@@ -71,3 +75,3 @@ p = __bind(function(s) { | ||
opts_filters = ['h_sid', 'xhr_cors', 'cache_for', 'xhr_options', 'expose']; | ||
dispatcher = [['GET', p(''), ['welcome_screen']], ['GET', p('/iframe[0-9-.a-z_]*.html'), ['iframe', 'cache_for', 'expose']], ['GET', t('/jsonp'), ['h_sid', 'h_no_cache', 'jsonp']], ['POST', t('/jsonp_send'), ['h_sid', 'expect_form', 'jsonp_send']], ['POST', t('/xhr'), ['h_sid', 'xhr_cors', 'xhr_poll']], ['OPTIONS', t('/xhr'), opts_filters], ['POST', t('/xhr_send'), ['h_sid', 'xhr_cors', 'expect_xhr', 'xhr_send']], ['OPTIONS', t('/xhr_send'), opts_filters], ['POST', t('/xhr_streaming'), ['h_sid', 'xhr_cors', 'xhr_streaming']], ['OPTIONS', t('/xhr_streaming'), opts_filters]]; | ||
dispatcher = [['GET', p(''), ['welcome_screen']], ['GET', p('/iframe[0-9-.a-z_]*.html'), ['iframe', 'cache_for', 'expose']], ['OPTIONS', p('/chunking_test'), opts_filters], ['POST', p('/chunking_test'), ['h_sid', 'xhr_cors', 'expect_xhr', 'chunking_test']], ['GET', t('/jsonp'), ['h_sid', 'h_no_cache', 'jsonp']], ['POST', t('/jsonp_send'), ['h_sid', 'expect_form', 'jsonp_send']], ['POST', t('/xhr'), ['h_sid', 'xhr_cors', 'xhr_poll']], ['OPTIONS', t('/xhr'), opts_filters], ['POST', t('/xhr_send'), ['h_sid', 'xhr_cors', 'expect_xhr', 'xhr_send']], ['OPTIONS', t('/xhr_send'), opts_filters], ['POST', t('/xhr_streaming'), ['h_sid', 'xhr_cors', 'xhr_streaming']], ['OPTIONS', t('/xhr_streaming'), opts_filters], ['GET', t('/eventsource'), ['h_sid', 'h_no_cache', 'eventsource']], ['GET', t('/htmlfile'), ['h_sid', 'h_no_cache', 'htmlfile']]]; | ||
maybe_add_transport = function(name, urls) { | ||
@@ -90,3 +94,2 @@ var filters, method, url; | ||
maybe_add_transport('websocket', [['GET', t('/websocket'), ['websocket']]]); | ||
maybe_add_transport('eventsource', [['GET', t('/eventsource'), ['h_sid', 'h_no_cache', 'eventsource']]]); | ||
webjs_handler = new webjs.WebJS(app, dispatcher); | ||
@@ -93,0 +96,0 @@ install_handler = function(ee, event, handler) { |
@@ -19,2 +19,3 @@ (function() { | ||
EventSourceReceiver.prototype.protocol = "eventsource"; | ||
EventSourceReceiver.prototype.max_response_size = 128 * 1024; | ||
EventSourceReceiver.prototype.doSendFrame = function(payload) { | ||
@@ -21,0 +22,0 @@ var data; |
@@ -9,3 +9,3 @@ (function() { | ||
var location, origin, ver; | ||
if (req.headers.upgrade.toLowerCase() !== 'websocket') { | ||
if ((req.headers.upgrade || '').toLowerCase() !== 'websocket') { | ||
throw { | ||
@@ -12,0 +12,0 @@ status: 406, |
@@ -10,93 +10,27 @@ (function() { | ||
return child; | ||
}, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | ||
}; | ||
transport = require('./transport'); | ||
utils = require('./utils'); | ||
XhrPollingReceiver = (function() { | ||
__extends(XhrPollingReceiver, transport.ResponseReceiver); | ||
function XhrPollingReceiver() { | ||
XhrPollingReceiver.__super__.constructor.apply(this, arguments); | ||
} | ||
XhrPollingReceiver.prototype.protocol = "xhr"; | ||
XhrPollingReceiver.prototype.doSendFrame = function(payload) { | ||
var ondrain, r, write; | ||
if (this.session) { | ||
this.session.unregister(); | ||
} | ||
if (payload !== 'o') { | ||
r = XhrPollingReceiver.__super__.doSendFrame.call(this, payload + '\n'); | ||
this.didClose(); | ||
return r; | ||
} else { | ||
write = __bind(function(payload) { | ||
try { | ||
return this.response.write(payload + '\n'); | ||
} catch (x) { | ||
} | ||
return true; | ||
}, this); | ||
ondrain = __bind(function() { | ||
this.response.connection.removeListener('drain', ondrain); | ||
return utils.timeout_chain([ | ||
[ | ||
150, __bind(function() { | ||
return write("o"); | ||
}, this) | ||
], [ | ||
150, __bind(function() { | ||
write(""); | ||
return this.didClose(); | ||
}, this) | ||
] | ||
]); | ||
}, this); | ||
r = write(Array(2048).join('h') + '\n'); | ||
if (r === false) { | ||
this.response.connection.addListener('drain', ondrain); | ||
} else { | ||
ondrain(); | ||
} | ||
return true; | ||
} | ||
}; | ||
XhrPollingReceiver.prototype.doKeepalive = function() { | ||
return this.doSendFrame("h"); | ||
}; | ||
return XhrPollingReceiver; | ||
})(); | ||
XhrStreamingReceiver = (function() { | ||
__extends(XhrStreamingReceiver, transport.ResponseReceiver); | ||
XhrStreamingReceiver.prototype.protocol = "xhr"; | ||
function XhrStreamingReceiver() { | ||
this.send_bytes = 0; | ||
XhrStreamingReceiver.__super__.constructor.apply(this, arguments); | ||
} | ||
XhrStreamingReceiver.prototype.protocol = "xhr-streaming"; | ||
XhrStreamingReceiver.prototype.max_response_size = 128 * 1024; | ||
XhrStreamingReceiver.prototype.doSendFrame = function(payload) { | ||
var r; | ||
this.send_bytes += payload.length + 1; | ||
if (this.send_bytes > 128 * 1024) { | ||
if (this.session) { | ||
this.session.unregister(); | ||
} | ||
} | ||
r = XhrStreamingReceiver.__super__.doSendFrame.call(this, payload + '\n'); | ||
if (this.send_bytes > 128 * 1024) { | ||
this.didClose(); | ||
} | ||
return r; | ||
return XhrStreamingReceiver.__super__.doSendFrame.call(this, payload + '\n'); | ||
}; | ||
XhrStreamingReceiver.prototype.doKeepalive = function() { | ||
return this.doSendFrame("h"); | ||
}; | ||
return XhrStreamingReceiver; | ||
})(); | ||
XhrPollingReceiver = (function() { | ||
__extends(XhrPollingReceiver, XhrStreamingReceiver); | ||
function XhrPollingReceiver() { | ||
XhrPollingReceiver.__super__.constructor.apply(this, arguments); | ||
} | ||
XhrPollingReceiver.prototype.protocol = "xhr"; | ||
XhrPollingReceiver.prototype.max_response_size = 1; | ||
return XhrPollingReceiver; | ||
})(); | ||
exports.app = { | ||
xhr_poll: function(req, res, _, next_filter) { | ||
var session; | ||
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8'); | ||
res.writeHead(200); | ||
session = transport.Session.bySessionIdOrNew(req.session, req.sockjs_server); | ||
session.register(new XhrPollingReceiver(res)); | ||
return true; | ||
}, | ||
xhr_options: function(req, res) { | ||
@@ -133,3 +67,4 @@ res.statusCode = 204; | ||
} | ||
res.writeHead(200); | ||
res.setHeader('Content-Type', 'text/plain'); | ||
res.writeHead(204); | ||
res.end(); | ||
@@ -149,2 +84,10 @@ return true; | ||
}, | ||
xhr_poll: function(req, res, _, next_filter) { | ||
var session; | ||
res.setHeader('Content-Type', 'application/javascript; charset=UTF-8'); | ||
res.writeHead(200); | ||
session = transport.Session.bySessionIdOrNew(req.session, req.sockjs_server); | ||
session.register(new XhrPollingReceiver(res)); | ||
return true; | ||
}, | ||
xhr_streaming: function(req, res, _, next_filter) { | ||
@@ -151,0 +94,0 @@ var session; |
@@ -246,4 +246,6 @@ (function() { | ||
__extends(ResponseReceiver, GenericReceiver); | ||
ResponseReceiver.prototype.max_response_size = void 0; | ||
function ResponseReceiver(response) { | ||
this.response = response; | ||
this.curr_response_size = 0; | ||
try { | ||
@@ -257,9 +259,15 @@ this.response.connection.setKeepAlive(true, 5000); | ||
ResponseReceiver.prototype.doSendFrame = function(payload) { | ||
var r; | ||
this.curr_response_size += payload.length; | ||
r = false; | ||
try { | ||
this.response.write(payload); | ||
return true; | ||
r = true; | ||
} catch (x) { | ||
} | ||
return false; | ||
if (this.max_response_size && this.curr_response_size >= this.max_response_size) { | ||
this.didClose(); | ||
} | ||
return r; | ||
}; | ||
@@ -266,0 +274,0 @@ ResponseReceiver.prototype.didClose = function() { |
@@ -79,2 +79,11 @@ (function() { | ||
}; | ||
exports.objectExtend = function(dst, src) { | ||
var k; | ||
for (k in src) { | ||
if (src.hasOwnProperty(k)) { | ||
dst[k] = src[k]; | ||
} | ||
} | ||
return dst; | ||
}; | ||
}).call(this); |
(function() { | ||
var $, WebJS, execute_request, fs, querystring, url; | ||
var WebJS, execute_request, fs, http, querystring, url, utils; | ||
url = require('url'); | ||
querystring = require('querystring'); | ||
fs = require('fs'); | ||
$ = require('jquery'); | ||
http = require('http'); | ||
utils = require('./utils'); | ||
execute_request = function(app, funs, req, res, data) { | ||
@@ -39,3 +40,3 @@ var fun, _results; | ||
that = this; | ||
$.extend(req, url.parse(req.url, true)); | ||
utils.objectExtend(req, url.parse(req.url, true)); | ||
found = false; | ||
@@ -47,3 +48,3 @@ allowed_methods = []; | ||
method = row[0], path = row[1], funs = row[2]; | ||
if ($.type(path) !== "array") { | ||
if (path.constructor !== Array) { | ||
path = [path]; | ||
@@ -68,5 +69,9 @@ } | ||
r.push('HTTP/' + req.httpVersion + ' ' + status + ' ' + http.STATUS_CODES[status]); | ||
r = r.concat(user_headers); | ||
r = r.concat(headers); | ||
r.push(''); | ||
if (user_headers && user_headers.length > 0) { | ||
r = r.concat(user_headers); | ||
} | ||
if (headers && headers.length > 0) { | ||
r = r.concat(headers); | ||
} | ||
r = r.concat(['', '']); | ||
if (content) { | ||
@@ -212,9 +217,9 @@ r.push(content); | ||
var data; | ||
data = []; | ||
data = new Buffer(0); | ||
req.on('data', function(d) { | ||
return data.push(d.toString('utf8')); | ||
return data = utils.buffer_concat(data, new Buffer(d, 'binary')); | ||
}); | ||
req.on('end', function() { | ||
var q; | ||
data = data.join(''); | ||
data = data.toString('utf-8'); | ||
switch ((req.headers['content-type'] || '').split(';')[0]) { | ||
@@ -240,9 +245,9 @@ case 'application/x-www-form-urlencoded': | ||
var data; | ||
data = []; | ||
data = new Buffer(0); | ||
req.on('data', function(d) { | ||
return data.push(d.toString('utf8')); | ||
return data = utils.buffer_concat(data, new Buffer(d, 'binary')); | ||
}); | ||
req.on('end', function() { | ||
var q; | ||
data = data.join(''); | ||
data = data.toString('utf-8'); | ||
switch ((req.headers['content-type'] || '').split(';')[0]) { | ||
@@ -249,0 +254,0 @@ case 'text/plain': |
{ | ||
"name": "sockjs", | ||
"author": "Marek Majkowski", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"repository": {"type": "git", | ||
"url": "https://github.com/majek/sockjs-client.git"}, | ||
"dependencies": { | ||
"coffee-script": "1.1.1", | ||
"jquery": "1.5.1", | ||
"node-uuid": "1.2.0" | ||
}, | ||
"devDependencies": { | ||
"coffee-script": "1.1.1" | ||
}, | ||
"main": "index" | ||
} |
@@ -67,3 +67,3 @@ SockJS-node server | ||
<dl> | ||
<dt>sockjs_url (required)</dt> | ||
<dt>sockjs_url (string, required)</dt> | ||
<dd>Transports which don't support cross-domain communication natively | ||
@@ -80,3 +80,3 @@ ('eventsource' to name one) use an iframe trick. A simple page is | ||
<dt>prefix</dt> | ||
<dt>prefix (string)</dt> | ||
<dd>A url prefix for the server. All http requests which paths begins | ||
@@ -86,3 +86,3 @@ with selected prefix will be handled by SockJS. All other requests | ||
<dt>disabled_transports</dt> | ||
<dt>disabled_transports (list of strings)</dt> | ||
<dd>A list of streaming transports that should not be handled by the | ||
@@ -214,5 +214,10 @@ server. This may be useful, when it's known that the server stands | ||
There are two issues that needs to be considered when planning a | ||
non-trivial SockJS-node deployment: WebSocket-compatible load balancer | ||
and sticky sessions (aka session affinity). | ||
### WebSocket compatible load balancer | ||
Often WebSockets don't play nicely with proxies and loadbalancers. | ||
Deploying SockJS server behind nginx or apache could be | ||
painful. | ||
Deploying a SockJS server behind Nginx or Apache could be painful. | ||
@@ -230,2 +235,19 @@ Fortunetely recent versions of an excellent loadbalancer | ||
### Sticky sessions | ||
If you plan depling more than one SockJS server, you must make sure | ||
that all HTTP requests for a single session will hit the same server. | ||
SockJS has two mechanisms that can be usefull to achieve that: | ||
* Urls are prefixed with server and session id numbers, like: | ||
`/resource/<server_number>/<session_id>/transport`. This is | ||
usefull for load balancers that support prefix-based affinity | ||
(HAProxy does). | ||
* `JSESSIONID` cookie is being set by SockJS-node. Many load | ||
balancers turn on sticky sessions if that cookie is set. This | ||
technique is derived from Java applications, where sticky sessions | ||
are often neccesary. HAProxy does support this method, as well as | ||
some hosting providers, for example CloudFoundry. In order to | ||
enable this method on the client side, please supply a | ||
`cookie:true` option to SockJS constructor. | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1
1645
249
70962
1
28
2
- Removedcoffee-script@1.1.1
- Removedjquery@1.5.1
- Removedcoffee-script@1.1.1(transitive)
- Removedhtmlparser@1.7.7(transitive)
- Removedjquery@1.5.1(transitive)