Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transport options/headers for server-to-server use case #534

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ Where `options` is a hash which can contain:
the number of expected round trips. This setting will establish a minimum,
but if the calculated timeout is higher, that will be used.

* **transportOptions (object)**

Additional options to pass per transport, keyed on transport name. For example:
```{ 'xhr-streaming': { headers: { Authorization: 'xxx' } } }```

Although the 'SockJS' object tries to emulate the 'WebSocket'
behaviour, it's impossible to support all of its features. An
important SockJS limitation is the fact that you're not allowed to
Expand Down
17 changes: 17 additions & 0 deletions lib/event/info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

var inherits = require('inherits')
, Event = require('./event')
;

function InfoEvent(info, rtt, headers) {
Event.call(this);
this.initEvent('info', false, false);
this.info = info;
this.rtt = rtt;
this.headers = headers;
}

inherits(InfoEvent, Event);

module.exports = InfoEvent;
8 changes: 4 additions & 4 deletions lib/info-ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:info-ajax');
}

function InfoAjax(url, AjaxObject) {
function InfoAjax(url, AjaxObject, opts) {
EventEmitter.call(this);

var self = this;
var t0 = +new Date();
this.xo = new AjaxObject('GET', url);
this.xo = new AjaxObject('GET', url, null, opts);

this.xo.once('finish', function(status, text) {
this.xo.once('finish', function(status, text, headers) {
var info, rtt;
if (status === 200) {
rtt = (+new Date()) - t0;
Expand All @@ -33,7 +33,7 @@ function InfoAjax(url, AjaxObject) {
info = {};
}
}
self.emit('finish', info, rtt, status);
self.emit('finish', info, rtt, status, headers);
self.removeAllListeners();
});
}
Expand Down
4 changes: 2 additions & 2 deletions lib/info-iframe-receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ var inherits = require('inherits')
, InfoAjax = require('./info-ajax')
;

function InfoReceiverIframe(transUrl) {
function InfoReceiverIframe(transUrl, ignore, opts) {
var self = this;
EventEmitter.call(this);

this.ir = new InfoAjax(transUrl, XHRLocalObject);
this.ir = new InfoAjax(transUrl, XHRLocalObject, opts);
this.ir.once('finish', function(info, rtt) {
self.ir = null;
self.emit('message', JSON.stringify([info, rtt]));
Expand Down
24 changes: 12 additions & 12 deletions lib/info-receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,55 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:info-receiver');
}

function InfoReceiver(baseUrl, urlInfo) {
function InfoReceiver(baseUrl, urlInfo, transportOptions) {
debug(baseUrl);
var self = this;
EventEmitter.call(this);

setTimeout(function() {
self.doXhr(baseUrl, urlInfo);
self.doXhr(baseUrl, urlInfo, transportOptions);
}, 0);
}

inherits(InfoReceiver, EventEmitter);

// TODO this is currently ignoring the list of available transports and the whitelist

InfoReceiver._getReceiver = function(baseUrl, url, urlInfo) {
InfoReceiver._getReceiver = function(baseUrl, url, urlInfo, transportOptions) {
// determine method of CORS support (if needed)
if (urlInfo.sameOrigin) {
return new InfoAjax(url, XHRLocal);
return new InfoAjax(url, XHRLocal, transportOptions['xhr-streaming'] || transportOptions['xhr-polling']);
}
if (XHRCors.enabled) {
return new InfoAjax(url, XHRCors);
return new InfoAjax(url, XHRCors, transportOptions['xhr-streaming'] || transportOptions['xhr-polling']);
}
if (XDR.enabled && urlInfo.sameScheme) {
return new InfoAjax(url, XDR);
return new InfoAjax(url, XDR, transportOptions['xdr-streaming'] || transportOptions['xdr-polling']);
}
if (InfoIframe.enabled()) {
return new InfoIframe(baseUrl, url);
return new InfoIframe(baseUrl, url, transportOptions['iframe']);
}
return new InfoAjax(url, XHRFake);
};

InfoReceiver.prototype.doXhr = function(baseUrl, urlInfo) {
InfoReceiver.prototype.doXhr = function(baseUrl, urlInfo, transportOptions) {
var self = this
, url = urlUtils.addPath(baseUrl, '/info')
;
debug('doXhr', url);

this.xo = InfoReceiver._getReceiver(baseUrl, url, urlInfo);
this.xo = InfoReceiver._getReceiver(baseUrl, url, urlInfo, transportOptions);

this.timeoutRef = setTimeout(function() {
debug('timeout');
self._cleanup(false);
self.emit('finish');
}, InfoReceiver.timeout);

this.xo.once('finish', function(info, rtt, status) {
debug('finish', info, rtt);
this.xo.once('finish', function(info, rtt, status, headers) {
debug('finish', info, rtt, status, headers);
self._cleanup(true);
self.emit('finish', info, rtt, status);
self.emit('finish', info, rtt, status, headers || {});
});
};

Expand Down
13 changes: 10 additions & 3 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var URL = require('url-parse')
, loc = require('./location')
, CloseEvent = require('./event/close')
, TransportMessageEvent = require('./event/trans-message')
, InfoEvent = require('./event/info')
, InfoReceiver = require('./info-receiver')
;

Expand Down Expand Up @@ -121,7 +122,7 @@ function SockJS(url, protocols, options) {
, sameScheme: urlUtils.isSchemeEqual(this.url, loc.href)
};

this._ir = new InfoReceiver(this.url, this._urlInfo);
this._ir = new InfoReceiver(this.url, this._urlInfo, this._transportOptions);
this._ir.once('finish', this._receiveInfo.bind(this));
}

Expand Down Expand Up @@ -163,7 +164,7 @@ SockJS.prototype.send = function(data) {
if (this.readyState !== SockJS.OPEN) {
return;
}
this._transport.send(escape.quote(data));
return this._transport.send(escape.quote(data));
};

SockJS.version = require('./version');
Expand All @@ -173,8 +174,9 @@ SockJS.OPEN = 1;
SockJS.CLOSING = 2;
SockJS.CLOSED = 3;

SockJS.prototype._receiveInfo = function(info, rtt, status) {
SockJS.prototype._receiveInfo = function(info, rtt, status, headers) {
debug('_receiveInfo', rtt);
this.dispatchEvent(new InfoEvent(info, rtt, headers));
this._ir = null;
if (!info) {
this._close(status || 1002, 'Cannot connect to server');
Expand All @@ -197,6 +199,7 @@ SockJS.prototype._receiveInfo = function(info, rtt, status) {
};

SockJS.prototype._connect = function() {
var self = this;
for (var Transport = this._transports.shift(); Transport; Transport = this._transports.shift()) {
debug('attempt', Transport.transportName);
if (Transport.needBody) {
Expand All @@ -221,6 +224,10 @@ SockJS.prototype._connect = function() {
debug('transport url', transportUrl);
var transportObj = new Transport(transportUrl, this._transUrl, options);
transportObj.on('message', this._transportMessage.bind(this));
// for transports that support backpressure handle drain event
transportObj.on('drain', function() {
self.dispatchEvent(new Event('drain'));
});
transportObj.once('close', this._transportClose.bind(this));
transportObj.transportName = Transport.transportName;
this._transport = transportObj;
Expand Down
2 changes: 1 addition & 1 deletion lib/transport/driver/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function XhrDriver(method, url, payload, opts) {
});
res.once('end', function() {
debug('end');
self.emit('finish', res.statusCode, responseText);
self.emit('finish', res.statusCode, responseText, res.headers);
self.req = null;
});
});
Expand Down
4 changes: 2 additions & 2 deletions lib/transport/eventsource.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ var inherits = require('inherits')
, EventSourceDriver = require('eventsource')
;

function EventSourceTransport(transUrl) {
function EventSourceTransport(transUrl, ignore, opts) {
if (!EventSourceTransport.enabled()) {
throw new Error('Transport created when disabled');
}

AjaxBasedTransport.call(this, transUrl, '/eventsource', EventSourceReceiver, XHRCorsObject);
AjaxBasedTransport.call(this, transUrl, '/eventsource', EventSourceReceiver, XHRCorsObject, opts);
}

inherits(EventSourceTransport, AjaxBasedTransport);
Expand Down
4 changes: 2 additions & 2 deletions lib/transport/htmlfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ var inherits = require('inherits')
, AjaxBasedTransport = require('./lib/ajax-based')
;

function HtmlFileTransport(transUrl) {
function HtmlFileTransport(transUrl, ignore, opts) {
if (!HtmlfileReceiver.enabled) {
throw new Error('Transport created when disabled');
}
AjaxBasedTransport.call(this, transUrl, '/htmlfile', HtmlfileReceiver, XHRLocalObject);
AjaxBasedTransport.call(this, transUrl, '/htmlfile', HtmlfileReceiver, XHRLocalObject, opts);
}

inherits(HtmlFileTransport, AjaxBasedTransport);
Expand Down
1 change: 1 addition & 0 deletions lib/transport/iframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ IframeTransport.prototype.postMessage = function(type, data) {
IframeTransport.prototype.send = function(message) {
debug('send', message);
this.postMessage('m', message);
return true;
};

IframeTransport.enabled = function() {
Expand Down
13 changes: 7 additions & 6 deletions lib/transport/lib/ajax-based.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:ajax-based');
}

function createAjaxSender(AjaxObject) {
function createAjaxSender(AjaxObject, opts) {
return function(url, payload, callback) {
debug('create ajax sender', url, payload);
var opt = {};
opts = opts || {};
if (typeof payload === 'string') {
opt.headers = {'Content-type': 'text/plain'};
opts.headers = opts.headers || {};
opts.headers['Content-type'] = 'text/plain';
}
var ajaxUrl = urlUtils.addPath(url, '/xhr_send');
var xo = new AjaxObject('POST', ajaxUrl, payload, opt);
var xo = new AjaxObject('POST', ajaxUrl, payload, opts);
xo.once('finish', function(status) {
debug('finish', status);
xo = null;
Expand All @@ -40,8 +41,8 @@ function createAjaxSender(AjaxObject) {
};
}

function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject) {
SenderReceiver.call(this, transUrl, urlSuffix, createAjaxSender(AjaxObject), Receiver, AjaxObject);
function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject, opts) {
SenderReceiver.call(this, transUrl, urlSuffix, createAjaxSender(AjaxObject, opts), Receiver, AjaxObject, opts);
}

inherits(AjaxBasedTransport, SenderReceiver);
Expand Down
1 change: 1 addition & 0 deletions lib/transport/lib/buffered-sender.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ BufferedSender.prototype.send = function(message) {
if (!this.sendStop) {
this.sendSchedule();
}
return true;
};

// For polling transports in a situation when in the message callback,
Expand Down
5 changes: 3 additions & 2 deletions lib/transport/lib/polling.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:polling');
}

function Polling(Receiver, receiveUrl, AjaxObject) {
function Polling(Receiver, receiveUrl, AjaxObject, opts) {
debug(receiveUrl);
EventEmitter.call(this);
this.Receiver = Receiver;
this.receiveUrl = receiveUrl;
this.AjaxObject = AjaxObject;
this.opts = opts;
this._scheduleReceiver();
}

Expand All @@ -23,7 +24,7 @@ inherits(Polling, EventEmitter);
Polling.prototype._scheduleReceiver = function() {
debug('_scheduleReceiver');
var self = this;
var poll = this.poll = new this.Receiver(this.receiveUrl, this.AjaxObject);
var poll = this.poll = new this.Receiver(this.receiveUrl, this.AjaxObject, this.opts);

poll.on('message', function(msg) {
debug('message', msg);
Expand Down
4 changes: 2 additions & 2 deletions lib/transport/lib/sender-receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:sender-receiver');
}

function SenderReceiver(transUrl, urlSuffix, senderFunc, Receiver, AjaxObject) {
function SenderReceiver(transUrl, urlSuffix, senderFunc, Receiver, AjaxObject, opts) {
var pollUrl = urlUtils.addPath(transUrl, urlSuffix);
debug(pollUrl);
var self = this;
BufferedSender.call(this, transUrl, senderFunc);

this.poll = new Polling(Receiver, pollUrl, AjaxObject);
this.poll = new Polling(Receiver, pollUrl, AjaxObject, opts);
this.poll.on('message', function(msg) {
debug('poll message', msg);
self.emit('message', msg);
Expand Down
5 changes: 3 additions & 2 deletions lib/transport/receiver/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ if (process.env.NODE_ENV !== 'production') {
debug = require('debug')('sockjs-client:receiver:xhr');
}

function XhrReceiver(url, AjaxObject) {
function XhrReceiver(url, AjaxObject, opts) {
debug(url);
EventEmitter.call(this);
var self = this;

this.bufferPosition = 0;

this.xo = new AjaxObject('POST', url, null);
this.opts = opts;
this.xo = new AjaxObject('POST', url, null, opts);
this.xo.on('chunk', this._chunkHandler.bind(this));
this.xo.once('finish', function(status, text) {
debug('finish', status, text);
Expand Down
8 changes: 4 additions & 4 deletions lib/transport/sender/xhr-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ var inherits = require('inherits')
, XhrDriver = require('../driver/xhr')
;

function XHRLocalObject(method, url, payload /*, opts */) {
XhrDriver.call(this, method, url, payload, {
noCredentials: true
});
function XHRLocalObject(method, url, payload, opts) {
opts = opts || {};
opts.noCredentials = true;
XhrDriver.call(this, method, url, payload, opts);
}

inherits(XHRLocalObject, XhrDriver);
Expand Down
5 changes: 4 additions & 1 deletion lib/transport/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ function WebSocketTransport(transUrl, ignore, options) {
self.emit('close', 1006, 'WebSocket connection broken');
self._cleanup();
};
this.ws.on('drain', function() {
self.emit('drain');
})
}

inherits(WebSocketTransport, EventEmitter);

WebSocketTransport.prototype.send = function(data) {
var msg = '[' + data + ']';
debug('send', msg);
this.ws.send(msg);
return this.ws.send(msg);
};

WebSocketTransport.prototype.close = function() {
Expand Down
4 changes: 2 additions & 2 deletions lib/transport/xdr-polling.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ var inherits = require('inherits')
, XDRObject = require('./sender/xdr')
;

function XdrPollingTransport(transUrl) {
function XdrPollingTransport(transUrl, ignore, opts) {
if (!XDRObject.enabled) {
throw new Error('Transport created when disabled');
}
AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XDRObject);
AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XDRObject, opts);
}

inherits(XdrPollingTransport, AjaxBasedTransport);
Expand Down
Loading