Implement the client-side framework for extensions.

This commit is contained in:
James Coglan
2014-11-24 22:05:31 +00:00
parent 40341c5439
commit eceb59e2fb
3 changed files with 78 additions and 18 deletions
+8 -2
View File
@@ -59,10 +59,18 @@ var instance = {
if (!this._http.isComplete()) return;
this._validateHandshake();
if (this.readyState === 3) return;
this._extensions.activate(this.headers['sec-websocket-extensions']);
this._open();
this.parse(this._http.body);
},
_handshakeRequest: function() {
var extensions = this._extensions.generateOffer();
if (extensions)
this._headers.set('Sec-WebSocket-Extensions', extensions);
var start = 'GET ' + this._pathname + ' HTTP/1.1',
headers = [start, this._headers.toString(), ''];
@@ -110,8 +118,6 @@ var instance = {
else
this.protocol = protocol;
}
this._open();
}
};
+4 -4
View File
@@ -227,11 +227,11 @@ var instance = {
}
var length = frame.length,
masked = frame.masked,
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10),
offset = header + (masked ? 4 : 0),
offset = header + (frame.masked ? 4 : 0),
buffer = new Buffer(offset + length),
BYTE = this.BYTE;
BYTE = this.BYTE,
masked = frame.masked ? this.MASK : 0;
buffer[0] = (frame.final ? this.FIN : 0) |
(frame.rsv1 ? this.RSV1 : 0) |
@@ -268,7 +268,7 @@ var instance = {
},
_handshakeResponse: function() {
var extensions = this._extensions.activate(this._request.headers['sec-websocket-extensions']);
var extensions = this._extensions.generateResponse(this._request.headers['sec-websocket-extensions']);
if (extensions) this._headers.set('Sec-WebSocket-Extensions', extensions);
var start = 'HTTP/1.1 101 Switching Protocols',
+66 -12
View File
@@ -13,6 +13,8 @@ var Extensions = function(driver) {
this._byName = {};
this._inOrder = [];
this._sessions = [];
this._rsv1 = this._rsv2 = this._rsv3 = false;
};
var instance = {
@@ -30,28 +32,68 @@ var instance = {
this._inOrder.push(extension);
},
activate: function(header) {
if (header === undefined) return;
generateOffer: function() {
var sessions = [],
offer = [],
index = {};
this._inOrder.forEach(function(ext) {
var session = ext.createClientSession(this);
if (!session) return;
sessions.push(session);
index[ext.name] = {ext: ext, session: session};
var offers = session.generateOffers();
offers = offers ? [].concat(offers) : [];
offers.forEach(function(off) {
offer.push(this._serializeParams(ext.name, off));
}, this);
}, this);
this._sessions = sessions;
this._index = index;
return offer.length > 0 ? offer.join(', ') : null;
},
activate: function(header) {
var responses = this._parseHeader(header),
active = [];
responses.forEach(function(response) {
var record = this._index[response.name],
ext = record.ext,
session = record.session;
if (this._reserved(ext)) return;
this._reserve(ext);
session.activate(response.params);
active.push(session);
}, this);
this._sessions = this._sessions.filter(function(session) {
return active.indexOf(session) >= 0;
});
},
generateResponse: function(header) {
var offers = this._parseHeader(header),
sessions = [],
response = [];
this._rsv1 = this._rsv2 = this._rsv3 = false;
offers.forEach(function(offer) {
var ext = this._byName[offer.name];
if (!ext || (this._rsv1 && ext.rsv1) || (this._rsv2 && ext.rsv2) || (this._rsv3 && ext.rsv3)) return;
if (!ext || this._reserved(ext)) return;
var session = ext && ext.createServerSession(this, offer.params);
if (!session) return;
this._rsv1 = this._rsv1 || ext.rsv1;
this._rsv2 = this._rsv2 || ext.rsv2;
this._rsv3 = this._rsv3 || ext.rsv3;
this._reserve(ext);
sessions.push(session);
response.push(this._serializeParams(offer.name, session.getResponseParams()));
response.push(this._serializeParams(offer.name, session.generateResponse()));
}, this);
this._sessions = sessions;
@@ -62,7 +104,7 @@ var instance = {
var sessions = this._sessions.slice();
var pipe = function(msg) {
var session = sessions.shift();
var session = sessions.pop();
if (!session) return callback.call(context, msg);
session.processIncomingMessage(msg, pipe);
};
@@ -73,7 +115,7 @@ var instance = {
var sessions = this._sessions.slice();
var pipe = function(msg) {
var session = sessions.pop();
var session = sessions.shift();
if (!session) return callback.call(context, msg);
session.processOutgoingMessage(msg, pipe);
};
@@ -88,7 +130,19 @@ var instance = {
this._driver._fail(type, message);
},
_reserve: function(ext) {
this._rsv1 = this._rsv1 || ext.rsv1;
this._rsv2 = this._rsv2 || ext.rsv2;
this._rsv3 = this._rsv3 || ext.rsv3;
},
_reserved: function(ext) {
return (this._rsv1 && ext.rsv1) || (this._rsv2 && ext.rsv2) || (this._rsv3 && ext.rsv3);
},
_parseHeader: function(header) {
if (header === undefined) return [];
if (!EXT_LIST.test(header))
throw new Error('Not a valid Sec-WebSocket-Extensions header: ' + header);