Files
nirvana-server/node_modules/@firebase/database-compat/dist/index.standalone.js
T
2021-12-29 01:57:42 -08:00

18736 lines
702 KiB
JavaScript

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var require$$2 = require('util');
var require$$0 = require('buffer');
var require$$1 = require('events');
var require$$0$1 = require('stream');
var require$$1$1 = require('crypto');
var require$$2$1 = require('url');
var require$$0$2 = require('assert');
var require$$1$2 = require('net');
var require$$2$2 = require('tls');
var require$$1$3 = require('@firebase/util');
var require$$2$3 = require('tslib');
var require$$3 = require('@firebase/logger');
var component = require('@firebase/component');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2);
var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0);
var require$$1__default = /*#__PURE__*/_interopDefaultLegacy(require$$1);
var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$1);
var require$$1__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$1$1);
var require$$2__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$2$1);
var require$$0__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$0$2);
var require$$1__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$1$2);
var require$$2__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$2$2);
var require$$1__default$3 = /*#__PURE__*/_interopDefaultLegacy(require$$1$3);
var require$$2__default$3 = /*#__PURE__*/_interopDefaultLegacy(require$$2$3);
var require$$3__default = /*#__PURE__*/_interopDefaultLegacy(require$$3);
var index_standalone = {};
var safeBuffer = {exports: {}};
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
(function (module, exports) {
/* eslint-disable node/no-deprecated-api */
var buffer = require$$0__default["default"];
var Buffer = buffer.Buffer;
// alternative to using Object.keys for old browsers
function copyProps (src, dst) {
for (var key in src) {
dst[key] = src[key];
}
}
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {
module.exports = buffer;
} else {
// Copy properties from require('buffer')
copyProps(buffer, exports);
exports.Buffer = SafeBuffer;
}
function SafeBuffer (arg, encodingOrOffset, length) {
return Buffer(arg, encodingOrOffset, length)
}
SafeBuffer.prototype = Object.create(Buffer.prototype);
// Copy static methods from Buffer
copyProps(Buffer, SafeBuffer);
SafeBuffer.from = function (arg, encodingOrOffset, length) {
if (typeof arg === 'number') {
throw new TypeError('Argument must not be a number')
}
return Buffer(arg, encodingOrOffset, length)
};
SafeBuffer.alloc = function (size, fill, encoding) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
var buf = Buffer(size);
if (fill !== undefined) {
if (typeof encoding === 'string') {
buf.fill(fill, encoding);
} else {
buf.fill(fill);
}
} else {
buf.fill(0);
}
return buf
};
SafeBuffer.allocUnsafe = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return Buffer(size)
};
SafeBuffer.allocUnsafeSlow = function (size) {
if (typeof size !== 'number') {
throw new TypeError('Argument must be a number')
}
return buffer.SlowBuffer(size)
};
}(safeBuffer, safeBuffer.exports));
var streams$1 = {};
/**
Streams in a WebSocket connection
---------------------------------
We model a WebSocket as two duplex streams: one stream is for the wire protocol
over an I/O socket, and the other is for incoming/outgoing messages.
+----------+ +---------+ +----------+
[1] write(chunk) -->| ~~~~~~~~ +----->| parse() +----->| ~~~~~~~~ +--> emit('data') [2]
| | +----+----+ | |
| | | | |
| IO | | [5] | Messages |
| | V | |
| | +---------+ | |
[4] emit('data') <--+ ~~~~~~~~ |<-----+ frame() |<-----+ ~~~~~~~~ |<-- write(chunk) [3]
+----------+ +---------+ +----------+
Message transfer in each direction is simple: IO receives a byte stream [1] and
sends this stream for parsing. The parser will periodically emit a complete
message text on the Messages stream [2]. Similarly, when messages are written
to the Messages stream [3], they are framed using the WebSocket wire format and
emitted via IO [4].
There is a feedback loop via [5] since some input from [1] will be things like
ping, pong and close frames. In these cases the protocol responds by emitting
responses directly back to [4] rather than emitting messages via [2].
For the purposes of flow control, we consider the sources of each Readable
stream to be as follows:
* [2] receives input from [1]
* [4] receives input from [1] and [3]
The classes below express the relationships described above without prescribing
anything about how parse() and frame() work, other than assuming they emit
'data' events to the IO and Messages streams. They will work with any protocol
driver having these two methods.
**/
var Stream$3 = require$$0__default$1["default"].Stream,
util$c = require$$2__default["default"];
var IO = function(driver) {
this.readable = this.writable = true;
this._paused = false;
this._driver = driver;
};
util$c.inherits(IO, Stream$3);
// The IO pause() and resume() methods will be called when the socket we are
// piping to gets backed up and drains. Since IO output [4] comes from IO input
// [1] and Messages input [3], we need to tell both of those to return false
// from write() when this stream is paused.
IO.prototype.pause = function() {
this._paused = true;
this._driver.messages._paused = true;
};
IO.prototype.resume = function() {
this._paused = false;
this.emit('drain');
var messages = this._driver.messages;
messages._paused = false;
messages.emit('drain');
};
// When we receive input from a socket, send it to the parser and tell the
// source whether to back off.
IO.prototype.write = function(chunk) {
if (!this.writable) return false;
this._driver.parse(chunk);
return !this._paused;
};
// The IO end() method will be called when the socket piping into it emits
// 'close' or 'end', i.e. the socket is closed. In this situation the Messages
// stream will not emit any more data so we emit 'end'.
IO.prototype.end = function(chunk) {
if (!this.writable) return;
if (chunk !== undefined) this.write(chunk);
this.writable = false;
var messages = this._driver.messages;
if (messages.readable) {
messages.readable = messages.writable = false;
messages.emit('end');
}
};
IO.prototype.destroy = function() {
this.end();
};
var Messages = function(driver) {
this.readable = this.writable = true;
this._paused = false;
this._driver = driver;
};
util$c.inherits(Messages, Stream$3);
// The Messages pause() and resume() methods will be called when the app that's
// processing the messages gets backed up and drains. If we're emitting
// messages too fast we should tell the source to slow down. Message output [2]
// comes from IO input [1].
Messages.prototype.pause = function() {
this._driver.io._paused = true;
};
Messages.prototype.resume = function() {
this._driver.io._paused = false;
this._driver.io.emit('drain');
};
// When we receive messages from the user, send them to the formatter and tell
// the source whether to back off.
Messages.prototype.write = function(message) {
if (!this.writable) return false;
if (typeof message === 'string') this._driver.text(message);
else this._driver.binary(message);
return !this._paused;
};
// The Messages end() method will be called when a stream piping into it emits
// 'end'. Many streams may be piped into the WebSocket and one of them ending
// does not mean the whole socket is done, so just process the input and move
// on leaving the socket open.
Messages.prototype.end = function(message) {
if (message !== undefined) this.write(message);
};
Messages.prototype.destroy = function() {};
streams$1.IO = IO;
streams$1.Messages = Messages;
var Headers$3 = function() {
this.clear();
};
Headers$3.prototype.ALLOWED_DUPLICATES = ['set-cookie', 'set-cookie2', 'warning', 'www-authenticate'];
Headers$3.prototype.clear = function() {
this._sent = {};
this._lines = [];
};
Headers$3.prototype.set = function(name, value) {
if (value === undefined) return;
name = this._strip(name);
value = this._strip(value);
var key = name.toLowerCase();
if (!this._sent.hasOwnProperty(key) || this.ALLOWED_DUPLICATES.indexOf(key) >= 0) {
this._sent[key] = true;
this._lines.push(name + ': ' + value + '\r\n');
}
};
Headers$3.prototype.toString = function() {
return this._lines.join('');
};
Headers$3.prototype._strip = function(string) {
return string.toString().replace(/^ */, '').replace(/ *$/, '');
};
var headers = Headers$3;
var Buffer$9 = safeBuffer.exports.Buffer;
var StreamReader = function() {
this._queue = [];
this._queueSize = 0;
this._offset = 0;
};
StreamReader.prototype.put = function(buffer) {
if (!buffer || buffer.length === 0) return;
if (!Buffer$9.isBuffer(buffer)) buffer = Buffer$9.from(buffer);
this._queue.push(buffer);
this._queueSize += buffer.length;
};
StreamReader.prototype.read = function(length) {
if (length > this._queueSize) return null;
if (length === 0) return Buffer$9.alloc(0);
this._queueSize -= length;
var queue = this._queue,
remain = length,
first = queue[0],
buffers, buffer;
if (first.length >= length) {
if (first.length === length) {
return queue.shift();
} else {
buffer = first.slice(0, length);
queue[0] = first.slice(length);
return buffer;
}
}
for (var i = 0, n = queue.length; i < n; i++) {
if (remain < queue[i].length) break;
remain -= queue[i].length;
}
buffers = queue.splice(0, i);
if (remain > 0 && queue.length > 0) {
buffers.push(queue[0].slice(0, remain));
queue[0] = queue[0].slice(remain);
}
return Buffer$9.concat(buffers, length);
};
StreamReader.prototype.eachByte = function(callback, context) {
var buffer, n, index;
while (this._queue.length > 0) {
buffer = this._queue[0];
n = buffer.length;
while (this._offset < n) {
index = this._offset;
this._offset += 1;
callback.call(context, buffer[index]);
}
this._offset = 0;
this._queue.shift();
}
};
var stream_reader = StreamReader;
var Buffer$8 = safeBuffer.exports.Buffer,
Emitter = require$$1__default["default"].EventEmitter,
util$b = require$$2__default["default"],
streams = streams$1,
Headers$2 = headers,
Reader = stream_reader;
var Base$7 = function(request, url, options) {
Emitter.call(this);
Base$7.validateOptions(options || {}, ['maxLength', 'masking', 'requireMasking', 'protocols']);
this._request = request;
this._reader = new Reader();
this._options = options || {};
this._maxLength = this._options.maxLength || this.MAX_LENGTH;
this._headers = new Headers$2();
this.__queue = [];
this.readyState = 0;
this.url = url;
this.io = new streams.IO(this);
this.messages = new streams.Messages(this);
this._bindEventListeners();
};
util$b.inherits(Base$7, Emitter);
Base$7.isWebSocket = function(request) {
var connection = request.headers.connection || '',
upgrade = request.headers.upgrade || '';
return request.method === 'GET' &&
connection.toLowerCase().split(/ *, */).indexOf('upgrade') >= 0 &&
upgrade.toLowerCase() === 'websocket';
};
Base$7.validateOptions = function(options, validKeys) {
for (var key in options) {
if (validKeys.indexOf(key) < 0)
throw new Error('Unrecognized option: ' + key);
}
};
var instance$b = {
// This is 64MB, small enough for an average VPS to handle without
// crashing from process out of memory
MAX_LENGTH: 0x3ffffff,
STATES: ['connecting', 'open', 'closing', 'closed'],
_bindEventListeners: function() {
var self = this;
// Protocol errors are informational and do not have to be handled
this.messages.on('error', function() {});
this.on('message', function(event) {
var messages = self.messages;
if (messages.readable) messages.emit('data', event.data);
});
this.on('error', function(error) {
var messages = self.messages;
if (messages.readable) messages.emit('error', error);
});
this.on('close', function() {
var messages = self.messages;
if (!messages.readable) return;
messages.readable = messages.writable = false;
messages.emit('end');
});
},
getState: function() {
return this.STATES[this.readyState] || null;
},
addExtension: function(extension) {
return false;
},
setHeader: function(name, value) {
if (this.readyState > 0) return false;
this._headers.set(name, value);
return true;
},
start: function() {
if (this.readyState !== 0) return false;
if (!Base$7.isWebSocket(this._request))
return this._failHandshake(new Error('Not a WebSocket request'));
var response;
try {
response = this._handshakeResponse();
} catch (error) {
return this._failHandshake(error);
}
this._write(response);
if (this._stage !== -1) this._open();
return true;
},
_failHandshake: function(error) {
var headers = new Headers$2();
headers.set('Content-Type', 'text/plain');
headers.set('Content-Length', Buffer$8.byteLength(error.message, 'utf8'));
headers = ['HTTP/1.1 400 Bad Request', headers.toString(), error.message];
this._write(Buffer$8.from(headers.join('\r\n'), 'utf8'));
this._fail('protocol_error', error.message);
return false;
},
text: function(message) {
return this.frame(message);
},
binary: function(message) {
return false;
},
ping: function() {
return false;
},
pong: function() {
return false;
},
close: function(reason, code) {
if (this.readyState !== 1) return false;
this.readyState = 3;
this.emit('close', new Base$7.CloseEvent(null, null));
return true;
},
_open: function() {
this.readyState = 1;
this.__queue.forEach(function(args) { this.frame.apply(this, args); }, this);
this.__queue = [];
this.emit('open', new Base$7.OpenEvent());
},
_queue: function(message) {
this.__queue.push(message);
return true;
},
_write: function(chunk) {
var io = this.io;
if (io.readable) io.emit('data', chunk);
},
_fail: function(type, message) {
this.readyState = 2;
this.emit('error', new Error(message));
this.close();
}
};
for (var key$b in instance$b)
Base$7.prototype[key$b] = instance$b[key$b];
Base$7.ConnectEvent = function() {};
Base$7.OpenEvent = function() {};
Base$7.CloseEvent = function(code, reason) {
this.code = code;
this.reason = reason;
};
Base$7.MessageEvent = function(data) {
this.data = data;
};
Base$7.PingEvent = function(data) {
this.data = data;
};
Base$7.PongEvent = function(data) {
this.data = data;
};
var base = Base$7;
var httpParser = {};
/*jshint node:true */
var assert = require$$0__default$2["default"];
httpParser.HTTPParser = HTTPParser;
function HTTPParser(type) {
assert.ok(type === HTTPParser.REQUEST || type === HTTPParser.RESPONSE || type === undefined);
if (type === undefined) ; else {
this.initialize(type);
}
}
HTTPParser.prototype.initialize = function (type, async_resource) {
assert.ok(type === HTTPParser.REQUEST || type === HTTPParser.RESPONSE);
this.type = type;
this.state = type + '_LINE';
this.info = {
headers: [],
upgrade: false
};
this.trailers = [];
this.line = '';
this.isChunked = false;
this.connection = '';
this.headerSize = 0; // for preventing too big headers
this.body_bytes = null;
this.isUserCall = false;
this.hadError = false;
};
HTTPParser.encoding = 'ascii';
HTTPParser.maxHeaderSize = 80 * 1024; // maxHeaderSize (in bytes) is configurable, but 80kb by default;
HTTPParser.REQUEST = 'REQUEST';
HTTPParser.RESPONSE = 'RESPONSE';
// Note: *not* starting with kOnHeaders=0 line the Node parser, because any
// newly added constants (kOnTimeout in Node v12.19.0) will overwrite 0!
var kOnHeaders = HTTPParser.kOnHeaders = 1;
var kOnHeadersComplete = HTTPParser.kOnHeadersComplete = 2;
var kOnBody = HTTPParser.kOnBody = 3;
var kOnMessageComplete = HTTPParser.kOnMessageComplete = 4;
// Some handler stubs, needed for compatibility
HTTPParser.prototype[kOnHeaders] =
HTTPParser.prototype[kOnHeadersComplete] =
HTTPParser.prototype[kOnBody] =
HTTPParser.prototype[kOnMessageComplete] = function () {};
var compatMode0_12 = true;
Object.defineProperty(HTTPParser, 'kOnExecute', {
get: function () {
// hack for backward compatibility
compatMode0_12 = false;
return 99;
}
});
var methods = httpParser.methods = HTTPParser.methods = [
'DELETE',
'GET',
'HEAD',
'POST',
'PUT',
'CONNECT',
'OPTIONS',
'TRACE',
'COPY',
'LOCK',
'MKCOL',
'MOVE',
'PROPFIND',
'PROPPATCH',
'SEARCH',
'UNLOCK',
'BIND',
'REBIND',
'UNBIND',
'ACL',
'REPORT',
'MKACTIVITY',
'CHECKOUT',
'MERGE',
'M-SEARCH',
'NOTIFY',
'SUBSCRIBE',
'UNSUBSCRIBE',
'PATCH',
'PURGE',
'MKCALENDAR',
'LINK',
'UNLINK'
];
var method_connect = methods.indexOf('CONNECT');
HTTPParser.prototype.reinitialize = HTTPParser;
HTTPParser.prototype.close =
HTTPParser.prototype.pause =
HTTPParser.prototype.resume =
HTTPParser.prototype.free = function () {};
HTTPParser.prototype._compatMode0_11 = false;
HTTPParser.prototype.getAsyncId = function() { return 0; };
var headerState = {
REQUEST_LINE: true,
RESPONSE_LINE: true,
HEADER: true
};
HTTPParser.prototype.execute = function (chunk, start, length) {
if (!(this instanceof HTTPParser)) {
throw new TypeError('not a HTTPParser');
}
// backward compat to node < 0.11.4
// Note: the start and length params were removed in newer version
start = start || 0;
length = typeof length === 'number' ? length : chunk.length;
this.chunk = chunk;
this.offset = start;
var end = this.end = start + length;
try {
while (this.offset < end) {
if (this[this.state]()) {
break;
}
}
} catch (err) {
if (this.isUserCall) {
throw err;
}
this.hadError = true;
return err;
}
this.chunk = null;
length = this.offset - start;
if (headerState[this.state]) {
this.headerSize += length;
if (this.headerSize > HTTPParser.maxHeaderSize) {
return new Error('max header size exceeded');
}
}
return length;
};
var stateFinishAllowed = {
REQUEST_LINE: true,
RESPONSE_LINE: true,
BODY_RAW: true
};
HTTPParser.prototype.finish = function () {
if (this.hadError) {
return;
}
if (!stateFinishAllowed[this.state]) {
return new Error('invalid state for EOF');
}
if (this.state === 'BODY_RAW') {
this.userCall()(this[kOnMessageComplete]());
}
};
// These three methods are used for an internal speed optimization, and it also
// works if theses are noops. Basically consume() asks us to read the bytes
// ourselves, but if we don't do it we get them through execute().
HTTPParser.prototype.consume =
HTTPParser.prototype.unconsume =
HTTPParser.prototype.getCurrentBuffer = function () {};
//For correct error handling - see HTTPParser#execute
//Usage: this.userCall()(userFunction('arg'));
HTTPParser.prototype.userCall = function () {
this.isUserCall = true;
var self = this;
return function (ret) {
self.isUserCall = false;
return ret;
};
};
HTTPParser.prototype.nextRequest = function () {
this.userCall()(this[kOnMessageComplete]());
this.reinitialize(this.type);
};
HTTPParser.prototype.consumeLine = function () {
var end = this.end,
chunk = this.chunk;
for (var i = this.offset; i < end; i++) {
if (chunk[i] === 0x0a) { // \n
var line = this.line + chunk.toString(HTTPParser.encoding, this.offset, i);
if (line.charAt(line.length - 1) === '\r') {
line = line.substr(0, line.length - 1);
}
this.line = '';
this.offset = i + 1;
return line;
}
}
//line split over multiple chunks
this.line += chunk.toString(HTTPParser.encoding, this.offset, this.end);
this.offset = this.end;
};
var headerExp = /^([^: \t]+):[ \t]*((?:.*[^ \t])|)/;
var headerContinueExp = /^[ \t]+(.*[^ \t])/;
HTTPParser.prototype.parseHeader = function (line, headers) {
if (line.indexOf('\r') !== -1) {
throw parseErrorCode('HPE_LF_EXPECTED');
}
var match = headerExp.exec(line);
var k = match && match[1];
if (k) { // skip empty string (malformed header)
headers.push(k);
headers.push(match[2]);
} else {
var matchContinue = headerContinueExp.exec(line);
if (matchContinue && headers.length) {
if (headers[headers.length - 1]) {
headers[headers.length - 1] += ' ';
}
headers[headers.length - 1] += matchContinue[1];
}
}
};
var requestExp = /^([A-Z-]+) ([^ ]+) HTTP\/(\d)\.(\d)$/;
HTTPParser.prototype.REQUEST_LINE = function () {
var line = this.consumeLine();
if (!line) {
return;
}
var match = requestExp.exec(line);
if (match === null) {
throw parseErrorCode('HPE_INVALID_CONSTANT');
}
this.info.method = this._compatMode0_11 ? match[1] : methods.indexOf(match[1]);
if (this.info.method === -1) {
throw new Error('invalid request method');
}
this.info.url = match[2];
this.info.versionMajor = +match[3];
this.info.versionMinor = +match[4];
this.body_bytes = 0;
this.state = 'HEADER';
};
var responseExp = /^HTTP\/(\d)\.(\d) (\d{3}) ?(.*)$/;
HTTPParser.prototype.RESPONSE_LINE = function () {
var line = this.consumeLine();
if (!line) {
return;
}
var match = responseExp.exec(line);
if (match === null) {
throw parseErrorCode('HPE_INVALID_CONSTANT');
}
this.info.versionMajor = +match[1];
this.info.versionMinor = +match[2];
var statusCode = this.info.statusCode = +match[3];
this.info.statusMessage = match[4];
// Implied zero length.
if ((statusCode / 100 | 0) === 1 || statusCode === 204 || statusCode === 304) {
this.body_bytes = 0;
}
this.state = 'HEADER';
};
HTTPParser.prototype.shouldKeepAlive = function () {
if (this.info.versionMajor > 0 && this.info.versionMinor > 0) {
if (this.connection.indexOf('close') !== -1) {
return false;
}
} else if (this.connection.indexOf('keep-alive') === -1) {
return false;
}
if (this.body_bytes !== null || this.isChunked) { // || skipBody
return true;
}
return false;
};
HTTPParser.prototype.HEADER = function () {
var line = this.consumeLine();
if (line === undefined) {
return;
}
var info = this.info;
if (line) {
this.parseHeader(line, info.headers);
} else {
var headers = info.headers;
var hasContentLength = false;
var currentContentLengthValue;
var hasUpgradeHeader = false;
for (var i = 0; i < headers.length; i += 2) {
switch (headers[i].toLowerCase()) {
case 'transfer-encoding':
this.isChunked = headers[i + 1].toLowerCase() === 'chunked';
break;
case 'content-length':
currentContentLengthValue = +headers[i + 1];
if (hasContentLength) {
// Fix duplicate Content-Length header with same values.
// Throw error only if values are different.
// Known issues:
// https://github.com/request/request/issues/2091#issuecomment-328715113
// https://github.com/nodejs/node/issues/6517#issuecomment-216263771
if (currentContentLengthValue !== this.body_bytes) {
throw parseErrorCode('HPE_UNEXPECTED_CONTENT_LENGTH');
}
} else {
hasContentLength = true;
this.body_bytes = currentContentLengthValue;
}
break;
case 'connection':
this.connection += headers[i + 1].toLowerCase();
break;
case 'upgrade':
hasUpgradeHeader = true;
break;
}
}
// if both isChunked and hasContentLength, isChunked wins
// This is required so the body is parsed using the chunked method, and matches
// Chrome's behavior. We could, maybe, ignore them both (would get chunked
// encoding into the body), and/or disable shouldKeepAlive to be more
// resilient.
if (this.isChunked && hasContentLength) {
hasContentLength = false;
this.body_bytes = null;
}
// Logic from https://github.com/nodejs/http-parser/blob/921d5585515a153fa00e411cf144280c59b41f90/http_parser.c#L1727-L1737
// "For responses, "Upgrade: foo" and "Connection: upgrade" are
// mandatory only when it is a 101 Switching Protocols response,
// otherwise it is purely informational, to announce support.
if (hasUpgradeHeader && this.connection.indexOf('upgrade') != -1) {
info.upgrade = this.type === HTTPParser.REQUEST || info.statusCode === 101;
} else {
info.upgrade = info.method === method_connect;
}
if (this.isChunked && info.upgrade) {
this.isChunked = false;
}
info.shouldKeepAlive = this.shouldKeepAlive();
//problem which also exists in original node: we should know skipBody before calling onHeadersComplete
var skipBody;
if (compatMode0_12) {
skipBody = this.userCall()(this[kOnHeadersComplete](info));
} else {
skipBody = this.userCall()(this[kOnHeadersComplete](info.versionMajor,
info.versionMinor, info.headers, info.method, info.url, info.statusCode,
info.statusMessage, info.upgrade, info.shouldKeepAlive));
}
if (skipBody === 2) {
this.nextRequest();
return true;
} else if (this.isChunked && !skipBody) {
this.state = 'BODY_CHUNKHEAD';
} else if (skipBody || this.body_bytes === 0) {
this.nextRequest();
// For older versions of node (v6.x and older?), that return skipBody=1 or skipBody=true,
// need this "return true;" if it's an upgrade request.
return info.upgrade;
} else if (this.body_bytes === null) {
this.state = 'BODY_RAW';
} else {
this.state = 'BODY_SIZED';
}
}
};
HTTPParser.prototype.BODY_CHUNKHEAD = function () {
var line = this.consumeLine();
if (line === undefined) {
return;
}
this.body_bytes = parseInt(line, 16);
if (!this.body_bytes) {
this.state = 'BODY_CHUNKTRAILERS';
} else {
this.state = 'BODY_CHUNK';
}
};
HTTPParser.prototype.BODY_CHUNK = function () {
var length = Math.min(this.end - this.offset, this.body_bytes);
this.userCall()(this[kOnBody](this.chunk, this.offset, length));
this.offset += length;
this.body_bytes -= length;
if (!this.body_bytes) {
this.state = 'BODY_CHUNKEMPTYLINE';
}
};
HTTPParser.prototype.BODY_CHUNKEMPTYLINE = function () {
var line = this.consumeLine();
if (line === undefined) {
return;
}
assert.equal(line, '');
this.state = 'BODY_CHUNKHEAD';
};
HTTPParser.prototype.BODY_CHUNKTRAILERS = function () {
var line = this.consumeLine();
if (line === undefined) {
return;
}
if (line) {
this.parseHeader(line, this.trailers);
} else {
if (this.trailers.length) {
this.userCall()(this[kOnHeaders](this.trailers, ''));
}
this.nextRequest();
}
};
HTTPParser.prototype.BODY_RAW = function () {
var length = this.end - this.offset;
this.userCall()(this[kOnBody](this.chunk, this.offset, length));
this.offset = this.end;
};
HTTPParser.prototype.BODY_SIZED = function () {
var length = Math.min(this.end - this.offset, this.body_bytes);
this.userCall()(this[kOnBody](this.chunk, this.offset, length));
this.offset += length;
this.body_bytes -= length;
if (!this.body_bytes) {
this.nextRequest();
}
};
// backward compat to node < 0.11.6
['Headers', 'HeadersComplete', 'Body', 'MessageComplete'].forEach(function (name) {
var k = HTTPParser['kOn' + name];
Object.defineProperty(HTTPParser.prototype, 'on' + name, {
get: function () {
return this[k];
},
set: function (to) {
// hack for backward compatibility
this._compatMode0_11 = true;
method_connect = 'CONNECT';
return (this[k] = to);
}
});
});
function parseErrorCode(code) {
var err = new Error('Parse Error');
err.code = code;
return err;
}
var NodeHTTPParser = httpParser.HTTPParser,
Buffer$7 = safeBuffer.exports.Buffer;
var TYPES = {
request: NodeHTTPParser.REQUEST || 'request',
response: NodeHTTPParser.RESPONSE || 'response'
};
var HttpParser$3 = function(type) {
this._type = type;
this._parser = new NodeHTTPParser(TYPES[type]);
this._complete = false;
this.headers = {};
var current = null,
self = this;
this._parser.onHeaderField = function(b, start, length) {
current = b.toString('utf8', start, start + length).toLowerCase();
};
this._parser.onHeaderValue = function(b, start, length) {
var value = b.toString('utf8', start, start + length);
if (self.headers.hasOwnProperty(current))
self.headers[current] += ', ' + value;
else
self.headers[current] = value;
};
this._parser.onHeadersComplete = this._parser[NodeHTTPParser.kOnHeadersComplete] =
function(majorVersion, minorVersion, headers, method, pathname, statusCode) {
var info = arguments[0];
if (typeof info === 'object') {
method = info.method;
pathname = info.url;
statusCode = info.statusCode;
headers = info.headers;
}
self.method = (typeof method === 'number') ? HttpParser$3.METHODS[method] : method;
self.statusCode = statusCode;
self.url = pathname;
if (!headers) return;
for (var i = 0, n = headers.length, key, value; i < n; i += 2) {
key = headers[i].toLowerCase();
value = headers[i+1];
if (self.headers.hasOwnProperty(key))
self.headers[key] += ', ' + value;
else
self.headers[key] = value;
}
self._complete = true;
};
};
HttpParser$3.METHODS = {
0: 'DELETE',
1: 'GET',
2: 'HEAD',
3: 'POST',
4: 'PUT',
5: 'CONNECT',
6: 'OPTIONS',
7: 'TRACE',
8: 'COPY',
9: 'LOCK',
10: 'MKCOL',
11: 'MOVE',
12: 'PROPFIND',
13: 'PROPPATCH',
14: 'SEARCH',
15: 'UNLOCK',
16: 'BIND',
17: 'REBIND',
18: 'UNBIND',
19: 'ACL',
20: 'REPORT',
21: 'MKACTIVITY',
22: 'CHECKOUT',
23: 'MERGE',
24: 'M-SEARCH',
25: 'NOTIFY',
26: 'SUBSCRIBE',
27: 'UNSUBSCRIBE',
28: 'PATCH',
29: 'PURGE',
30: 'MKCALENDAR',
31: 'LINK',
32: 'UNLINK'
};
var VERSION = process.version
? process.version.match(/[0-9]+/g).map(function(n) { return parseInt(n, 10) })
: [];
if (VERSION[0] === 0 && VERSION[1] === 12) {
HttpParser$3.METHODS[16] = 'REPORT';
HttpParser$3.METHODS[17] = 'MKACTIVITY';
HttpParser$3.METHODS[18] = 'CHECKOUT';
HttpParser$3.METHODS[19] = 'MERGE';
HttpParser$3.METHODS[20] = 'M-SEARCH';
HttpParser$3.METHODS[21] = 'NOTIFY';
HttpParser$3.METHODS[22] = 'SUBSCRIBE';
HttpParser$3.METHODS[23] = 'UNSUBSCRIBE';
HttpParser$3.METHODS[24] = 'PATCH';
HttpParser$3.METHODS[25] = 'PURGE';
}
HttpParser$3.prototype.isComplete = function() {
return this._complete;
};
HttpParser$3.prototype.parse = function(chunk) {
var consumed = this._parser.execute(chunk, 0, chunk.length);
if (typeof consumed !== 'number') {
this.error = consumed;
this._complete = true;
return;
}
if (this._complete)
this.body = (consumed < chunk.length)
? chunk.slice(consumed)
: Buffer$7.alloc(0);
};
var http_parser = HttpParser$3;
var TOKEN = /([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)/,
NOTOKEN = /([^!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z])/g,
QUOTED = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"/,
PARAM = new RegExp(TOKEN.source + '(?:=(?:' + TOKEN.source + '|' + QUOTED.source + '))?'),
EXT = new RegExp(TOKEN.source + '(?: *; *' + PARAM.source + ')*', 'g'),
EXT_LIST = new RegExp('^' + EXT.source + '(?: *, *' + EXT.source + ')*$'),
NUMBER = /^-?(0|[1-9][0-9]*)(\.[0-9]+)?$/;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var Parser$1 = {
parseHeader: function(header) {
var offers = new Offers();
if (header === '' || header === undefined) return offers;
if (!EXT_LIST.test(header))
throw new SyntaxError('Invalid Sec-WebSocket-Extensions header: ' + header);
var values = header.match(EXT);
values.forEach(function(value) {
var params = value.match(new RegExp(PARAM.source, 'g')),
name = params.shift(),
offer = {};
params.forEach(function(param) {
var args = param.match(PARAM), key = args[1], data;
if (args[2] !== undefined) {
data = args[2];
} else if (args[3] !== undefined) {
data = args[3].replace(/\\/g, '');
} else {
data = true;
}
if (NUMBER.test(data)) data = parseFloat(data);
if (hasOwnProperty.call(offer, key)) {
offer[key] = [].concat(offer[key]);
offer[key].push(data);
} else {
offer[key] = data;
}
}, this);
offers.push(name, offer);
}, this);
return offers;
},
serializeParams: function(name, params) {
var values = [];
var print = function(key, value) {
if (value instanceof Array) {
value.forEach(function(v) { print(key, v); });
} else if (value === true) {
values.push(key);
} else if (typeof value === 'number') {
values.push(key + '=' + value);
} else if (NOTOKEN.test(value)) {
values.push(key + '="' + value.replace(/"/g, '\\"') + '"');
} else {
values.push(key + '=' + value);
}
};
for (var key in params) print(key, params[key]);
return [name].concat(values).join('; ');
}
};
var Offers = function() {
this._byName = {};
this._inOrder = [];
};
Offers.prototype.push = function(name, params) {
if (!hasOwnProperty.call(this._byName, name))
this._byName[name] = [];
this._byName[name].push(params);
this._inOrder.push({ name: name, params: params });
};
Offers.prototype.eachOffer = function(callback, context) {
var list = this._inOrder;
for (var i = 0, n = list.length; i < n; i++)
callback.call(context, list[i].name, list[i].params);
};
Offers.prototype.byName = function(name) {
return this._byName[name] || [];
};
Offers.prototype.toArray = function() {
return this._inOrder.slice();
};
var parser = Parser$1;
var RingBuffer$2 = function(bufferSize) {
this._bufferSize = bufferSize;
this.clear();
};
RingBuffer$2.prototype.clear = function() {
this._buffer = new Array(this._bufferSize);
this._ringOffset = 0;
this._ringSize = this._bufferSize;
this._head = 0;
this._tail = 0;
this.length = 0;
};
RingBuffer$2.prototype.push = function(value) {
var expandBuffer = false,
expandRing = false;
if (this._ringSize < this._bufferSize) {
expandBuffer = (this._tail === 0);
} else if (this._ringOffset === this._ringSize) {
expandBuffer = true;
expandRing = (this._tail === 0);
}
if (expandBuffer) {
this._tail = this._bufferSize;
this._buffer = this._buffer.concat(new Array(this._bufferSize));
this._bufferSize = this._buffer.length;
if (expandRing)
this._ringSize = this._bufferSize;
}
this._buffer[this._tail] = value;
this.length += 1;
if (this._tail < this._ringSize) this._ringOffset += 1;
this._tail = (this._tail + 1) % this._bufferSize;
};
RingBuffer$2.prototype.peek = function() {
if (this.length === 0) return void 0;
return this._buffer[this._head];
};
RingBuffer$2.prototype.shift = function() {
if (this.length === 0) return void 0;
var value = this._buffer[this._head];
this._buffer[this._head] = void 0;
this.length -= 1;
this._ringOffset -= 1;
if (this._ringOffset === 0 && this.length > 0) {
this._head = this._ringSize;
this._ringOffset = this.length;
this._ringSize = this._bufferSize;
} else {
this._head = (this._head + 1) % this._ringSize;
}
return value;
};
var ring_buffer = RingBuffer$2;
var RingBuffer$1 = ring_buffer;
var Functor$1 = function(session, method) {
this._session = session;
this._method = method;
this._queue = new RingBuffer$1(Functor$1.QUEUE_SIZE);
this._stopped = false;
this.pending = 0;
};
Functor$1.QUEUE_SIZE = 8;
Functor$1.prototype.call = function(error, message, callback, context) {
if (this._stopped) return;
var record = { error: error, message: message, callback: callback, context: context, done: false },
called = false,
self = this;
this._queue.push(record);
if (record.error) {
record.done = true;
this._stop();
return this._flushQueue();
}
var handler = function(err, msg) {
if (!(called ^ (called = true))) return;
if (err) {
self._stop();
record.error = err;
record.message = null;
} else {
record.message = msg;
}
record.done = true;
self._flushQueue();
};
try {
this._session[this._method](message, handler);
} catch (err) {
handler(err);
}
};
Functor$1.prototype._stop = function() {
this.pending = this._queue.length;
this._stopped = true;
};
Functor$1.prototype._flushQueue = function() {
var queue = this._queue, record;
while (queue.length > 0 && queue.peek().done) {
record = queue.shift();
if (record.error) {
this.pending = 0;
queue.clear();
} else {
this.pending -= 1;
}
record.callback.call(record.context, record.error, record.message);
}
};
var functor = Functor$1;
var RingBuffer = ring_buffer;
var Pledge$2 = function() {
this._complete = false;
this._callbacks = new RingBuffer(Pledge$2.QUEUE_SIZE);
};
Pledge$2.QUEUE_SIZE = 4;
Pledge$2.all = function(list) {
var pledge = new Pledge$2(),
pending = list.length,
n = pending;
if (pending === 0) pledge.done();
while (n--) list[n].then(function() {
pending -= 1;
if (pending === 0) pledge.done();
});
return pledge;
};
Pledge$2.prototype.then = function(callback) {
if (this._complete) callback();
else this._callbacks.push(callback);
};
Pledge$2.prototype.done = function() {
this._complete = true;
var callbacks = this._callbacks, callback;
while (callback = callbacks.shift()) callback();
};
var pledge = Pledge$2;
var Functor = functor,
Pledge$1 = pledge;
var Cell$1 = function(tuple) {
this._ext = tuple[0];
this._session = tuple[1];
this._functors = {
incoming: new Functor(this._session, 'processIncomingMessage'),
outgoing: new Functor(this._session, 'processOutgoingMessage')
};
};
Cell$1.prototype.pending = function(direction) {
var functor = this._functors[direction];
if (!functor._stopped) functor.pending += 1;
};
Cell$1.prototype.incoming = function(error, message, callback, context) {
this._exec('incoming', error, message, callback, context);
};
Cell$1.prototype.outgoing = function(error, message, callback, context) {
this._exec('outgoing', error, message, callback, context);
};
Cell$1.prototype.close = function() {
this._closed = this._closed || new Pledge$1();
this._doClose();
return this._closed;
};
Cell$1.prototype._exec = function(direction, error, message, callback, context) {
this._functors[direction].call(error, message, function(err, msg) {
if (err) err.message = this._ext.name + ': ' + err.message;
callback.call(context, err, msg);
this._doClose();
}, this);
};
Cell$1.prototype._doClose = function() {
var fin = this._functors.incoming,
fout = this._functors.outgoing;
if (!this._closed || fin.pending + fout.pending !== 0) return;
if (this._session) this._session.close();
this._session = null;
this._closed.done();
};
var cell = Cell$1;
var Cell = cell,
Pledge = pledge;
var Pipeline$1 = function(sessions) {
this._cells = sessions.map(function(session) { return new Cell(session) });
this._stopped = { incoming: false, outgoing: false };
};
Pipeline$1.prototype.processIncomingMessage = function(message, callback, context) {
if (this._stopped.incoming) return;
this._loop('incoming', this._cells.length - 1, -1, -1, message, callback, context);
};
Pipeline$1.prototype.processOutgoingMessage = function(message, callback, context) {
if (this._stopped.outgoing) return;
this._loop('outgoing', 0, this._cells.length, 1, message, callback, context);
};
Pipeline$1.prototype.close = function(callback, context) {
this._stopped = { incoming: true, outgoing: true };
var closed = this._cells.map(function(a) { return a.close() });
if (callback)
Pledge.all(closed).then(function() { callback.call(context); });
};
Pipeline$1.prototype._loop = function(direction, start, end, step, message, callback, context) {
var cells = this._cells,
n = cells.length,
self = this;
while (n--) cells[n].pending(direction);
var pipe = function(index, error, msg) {
if (index === end) return callback.call(context, error, msg);
cells[index][direction](error, msg, function(err, m) {
if (err) self._stopped[direction] = true;
pipe(index + step, err, m);
});
};
pipe(start, null, message);
};
var pipeline = Pipeline$1;
var Parser = parser,
Pipeline = pipeline;
var Extensions$1 = function() {
this._rsv1 = this._rsv2 = this._rsv3 = null;
this._byName = {};
this._inOrder = [];
this._sessions = [];
this._index = {};
};
Extensions$1.MESSAGE_OPCODES = [1, 2];
var instance$a = {
add: function(ext) {
if (typeof ext.name !== 'string') throw new TypeError('extension.name must be a string');
if (ext.type !== 'permessage') throw new TypeError('extension.type must be "permessage"');
if (typeof ext.rsv1 !== 'boolean') throw new TypeError('extension.rsv1 must be true or false');
if (typeof ext.rsv2 !== 'boolean') throw new TypeError('extension.rsv2 must be true or false');
if (typeof ext.rsv3 !== 'boolean') throw new TypeError('extension.rsv3 must be true or false');
if (this._byName.hasOwnProperty(ext.name))
throw new TypeError('An extension with name "' + ext.name + '" is already registered');
this._byName[ext.name] = ext;
this._inOrder.push(ext);
},
generateOffer: function() {
var sessions = [],
offer = [],
index = {};
this._inOrder.forEach(function(ext) {
var session = ext.createClientSession();
if (!session) return;
var record = [ext, session];
sessions.push(record);
index[ext.name] = record;
var offers = session.generateOffer();
offers = offers ? [].concat(offers) : [];
offers.forEach(function(off) {
offer.push(Parser.serializeParams(ext.name, off));
}, this);
}, this);
this._sessions = sessions;
this._index = index;
return offer.length > 0 ? offer.join(', ') : null;
},
activate: function(header) {
var responses = Parser.parseHeader(header),
sessions = [];
responses.eachOffer(function(name, params) {
var record = this._index[name];
if (!record)
throw new Error('Server sent an extension response for unknown extension "' + name + '"');
var ext = record[0],
session = record[1],
reserved = this._reserved(ext);
if (reserved)
throw new Error('Server sent two extension responses that use the RSV' +
reserved[0] + ' bit: "' +
reserved[1] + '" and "' + ext.name + '"');
if (session.activate(params) !== true)
throw new Error('Server sent unacceptable extension parameters: ' +
Parser.serializeParams(name, params));
this._reserve(ext);
sessions.push(record);
}, this);
this._sessions = sessions;
this._pipeline = new Pipeline(sessions);
},
generateResponse: function(header) {
var sessions = [],
response = [],
offers = Parser.parseHeader(header);
this._inOrder.forEach(function(ext) {
var offer = offers.byName(ext.name);
if (offer.length === 0 || this._reserved(ext)) return;
var session = ext.createServerSession(offer);
if (!session) return;
this._reserve(ext);
sessions.push([ext, session]);
response.push(Parser.serializeParams(ext.name, session.generateResponse()));
}, this);
this._sessions = sessions;
this._pipeline = new Pipeline(sessions);
return response.length > 0 ? response.join(', ') : null;
},
validFrameRsv: function(frame) {
var allowed = { rsv1: false, rsv2: false, rsv3: false },
ext;
if (Extensions$1.MESSAGE_OPCODES.indexOf(frame.opcode) >= 0) {
for (var i = 0, n = this._sessions.length; i < n; i++) {
ext = this._sessions[i][0];
allowed.rsv1 = allowed.rsv1 || ext.rsv1;
allowed.rsv2 = allowed.rsv2 || ext.rsv2;
allowed.rsv3 = allowed.rsv3 || ext.rsv3;
}
}
return (allowed.rsv1 || !frame.rsv1) &&
(allowed.rsv2 || !frame.rsv2) &&
(allowed.rsv3 || !frame.rsv3);
},
processIncomingMessage: function(message, callback, context) {
this._pipeline.processIncomingMessage(message, callback, context);
},
processOutgoingMessage: function(message, callback, context) {
this._pipeline.processOutgoingMessage(message, callback, context);
},
close: function(callback, context) {
if (!this._pipeline) return callback.call(context);
this._pipeline.close(callback, context);
},
_reserve: function(ext) {
this._rsv1 = this._rsv1 || (ext.rsv1 && ext.name);
this._rsv2 = this._rsv2 || (ext.rsv2 && ext.name);
this._rsv3 = this._rsv3 || (ext.rsv3 && ext.name);
},
_reserved: function(ext) {
if (this._rsv1 && ext.rsv1) return [1, this._rsv1];
if (this._rsv2 && ext.rsv2) return [2, this._rsv2];
if (this._rsv3 && ext.rsv3) return [3, this._rsv3];
return false;
}
};
for (var key$a in instance$a)
Extensions$1.prototype[key$a] = instance$a[key$a];
var websocket_extensions = Extensions$1;
var Frame$1 = function() {};
var instance$9 = {
final: false,
rsv1: false,
rsv2: false,
rsv3: false,
opcode: null,
masked: false,
maskingKey: null,
lengthBytes: 1,
length: 0,
payload: null
};
for (var key$9 in instance$9)
Frame$1.prototype[key$9] = instance$9[key$9];
var frame = Frame$1;
var Buffer$6 = safeBuffer.exports.Buffer;
var Message$1 = function() {
this.rsv1 = false;
this.rsv2 = false;
this.rsv3 = false;
this.opcode = null;
this.length = 0;
this._chunks = [];
};
var instance$8 = {
read: function() {
return this.data = this.data || Buffer$6.concat(this._chunks, this.length);
},
pushFrame: function(frame) {
this.rsv1 = this.rsv1 || frame.rsv1;
this.rsv2 = this.rsv2 || frame.rsv2;
this.rsv3 = this.rsv3 || frame.rsv3;
if (this.opcode === null) this.opcode = frame.opcode;
this._chunks.push(frame.payload);
this.length += frame.length;
}
};
for (var key$8 in instance$8)
Message$1.prototype[key$8] = instance$8[key$8];
var message = Message$1;
var Buffer$5 = safeBuffer.exports.Buffer,
crypto$2 = require$$1__default$1["default"],
util$a = require$$2__default["default"],
Extensions = websocket_extensions,
Base$6 = base,
Frame = frame,
Message = message;
var Hybi$2 = function(request, url, options) {
Base$6.apply(this, arguments);
this._extensions = new Extensions();
this._stage = 0;
this._masking = this._options.masking;
this._protocols = this._options.protocols || [];
this._requireMasking = this._options.requireMasking;
this._pingCallbacks = {};
if (typeof this._protocols === 'string')
this._protocols = this._protocols.split(/ *, */);
if (!this._request) return;
var protos = this._request.headers['sec-websocket-protocol'],
supported = this._protocols;
if (protos !== undefined) {
if (typeof protos === 'string') protos = protos.split(/ *, */);
this.protocol = protos.filter(function(p) { return supported.indexOf(p) >= 0 })[0];
}
this.version = 'hybi-' + Hybi$2.VERSION;
};
util$a.inherits(Hybi$2, Base$6);
Hybi$2.VERSION = '13';
Hybi$2.mask = function(payload, mask, offset) {
if (!mask || mask.length === 0) return payload;
offset = offset || 0;
for (var i = 0, n = payload.length - offset; i < n; i++) {
payload[offset + i] = payload[offset + i] ^ mask[i % 4];
}
return payload;
};
Hybi$2.generateAccept = function(key) {
var sha1 = crypto$2.createHash('sha1');
sha1.update(key + Hybi$2.GUID);
return sha1.digest('base64');
};
Hybi$2.GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
var instance$7 = {
FIN: 0x80,
MASK: 0x80,
RSV1: 0x40,
RSV2: 0x20,
RSV3: 0x10,
OPCODE: 0x0F,
LENGTH: 0x7F,
OPCODES: {
continuation: 0,
text: 1,
binary: 2,
close: 8,
ping: 9,
pong: 10
},
OPCODE_CODES: [0, 1, 2, 8, 9, 10],
MESSAGE_OPCODES: [0, 1, 2],
OPENING_OPCODES: [1, 2],
ERRORS: {
normal_closure: 1000,
going_away: 1001,
protocol_error: 1002,
unacceptable: 1003,
encoding_error: 1007,
policy_violation: 1008,
too_large: 1009,
extension_error: 1010,
unexpected_condition: 1011
},
ERROR_CODES: [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011],
DEFAULT_ERROR_CODE: 1000,
MIN_RESERVED_ERROR: 3000,
MAX_RESERVED_ERROR: 4999,
// http://www.w3.org/International/questions/qa-forms-utf-8.en.php
UTF8_MATCH: /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/,
addExtension: function(extension) {
this._extensions.add(extension);
return true;
},
parse: function(chunk) {
this._reader.put(chunk);
var buffer = true;
while (buffer) {
switch (this._stage) {
case 0:
buffer = this._reader.read(1);
if (buffer) this._parseOpcode(buffer[0]);
break;
case 1:
buffer = this._reader.read(1);
if (buffer) this._parseLength(buffer[0]);
break;
case 2:
buffer = this._reader.read(this._frame.lengthBytes);
if (buffer) this._parseExtendedLength(buffer);
break;
case 3:
buffer = this._reader.read(4);
if (buffer) {
this._stage = 4;
this._frame.maskingKey = buffer;
}
break;
case 4:
buffer = this._reader.read(this._frame.length);
if (buffer) {
this._stage = 0;
this._emitFrame(buffer);
}
break;
default:
buffer = null;
}
}
},
text: function(message) {
if (this.readyState > 1) return false;
return this.frame(message, 'text');
},
binary: function(message) {
if (this.readyState > 1) return false;
return this.frame(message, 'binary');
},
ping: function(message, callback) {
if (this.readyState > 1) return false;
message = message || '';
if (callback) this._pingCallbacks[message] = callback;
return this.frame(message, 'ping');
},
pong: function(message) {
if (this.readyState > 1) return false;
message = message ||'';
return this.frame(message, 'pong');
},
close: function(reason, code) {
reason = reason || '';
code = code || this.ERRORS.normal_closure;
if (this.readyState <= 0) {
this.readyState = 3;
this.emit('close', new Base$6.CloseEvent(code, reason));
return true;
} else if (this.readyState === 1) {
this.readyState = 2;
this._extensions.close(function() { this.frame(reason, 'close', code); }, this);
return true;
} else {
return false;
}
},
frame: function(buffer, type, code) {
if (this.readyState <= 0) return this._queue([buffer, type, code]);
if (this.readyState > 2) return false;
if (buffer instanceof Array) buffer = Buffer$5.from(buffer);
if (typeof buffer === 'number') buffer = buffer.toString();
var message = new Message(),
isText = (typeof buffer === 'string'),
payload, copy;
message.rsv1 = message.rsv2 = message.rsv3 = false;
message.opcode = this.OPCODES[type || (isText ? 'text' : 'binary')];
payload = isText ? Buffer$5.from(buffer, 'utf8') : buffer;
if (code) {
copy = payload;
payload = Buffer$5.allocUnsafe(2 + copy.length);
payload.writeUInt16BE(code, 0);
copy.copy(payload, 2);
}
message.data = payload;
var onMessageReady = function(message) {
var frame = new Frame();
frame.final = true;
frame.rsv1 = message.rsv1;
frame.rsv2 = message.rsv2;
frame.rsv3 = message.rsv3;
frame.opcode = message.opcode;
frame.masked = !!this._masking;
frame.length = message.data.length;
frame.payload = message.data;
if (frame.masked) frame.maskingKey = crypto$2.randomBytes(4);
this._sendFrame(frame);
};
if (this.MESSAGE_OPCODES.indexOf(message.opcode) >= 0)
this._extensions.processOutgoingMessage(message, function(error, message) {
if (error) return this._fail('extension_error', error.message);
onMessageReady.call(this, message);
}, this);
else
onMessageReady.call(this, message);
return true;
},
_sendFrame: function(frame) {
var length = frame.length,
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10),
offset = header + (frame.masked ? 4 : 0),
buffer = Buffer$5.allocUnsafe(offset + length),
masked = frame.masked ? this.MASK : 0;
buffer[0] = (frame.final ? this.FIN : 0) |
(frame.rsv1 ? this.RSV1 : 0) |
(frame.rsv2 ? this.RSV2 : 0) |
(frame.rsv3 ? this.RSV3 : 0) |
frame.opcode;
if (length <= 125) {
buffer[1] = masked | length;
} else if (length <= 65535) {
buffer[1] = masked | 126;
buffer.writeUInt16BE(length, 2);
} else {
buffer[1] = masked | 127;
buffer.writeUInt32BE(Math.floor(length / 0x100000000), 2);
buffer.writeUInt32BE(length % 0x100000000, 6);
}
frame.payload.copy(buffer, offset);
if (frame.masked) {
frame.maskingKey.copy(buffer, header);
Hybi$2.mask(buffer, frame.maskingKey, offset);
}
this._write(buffer);
},
_handshakeResponse: function() {
var secKey = this._request.headers['sec-websocket-key'],
version = this._request.headers['sec-websocket-version'];
if (version !== Hybi$2.VERSION)
throw new Error('Unsupported WebSocket version: ' + version);
if (typeof secKey !== 'string')
throw new Error('Missing handshake request header: Sec-WebSocket-Key');
this._headers.set('Upgrade', 'websocket');
this._headers.set('Connection', 'Upgrade');
this._headers.set('Sec-WebSocket-Accept', Hybi$2.generateAccept(secKey));
if (this.protocol) this._headers.set('Sec-WebSocket-Protocol', this.protocol);
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',
headers = [start, this._headers.toString(), ''];
return Buffer$5.from(headers.join('\r\n'), 'utf8');
},
_shutdown: function(code, reason, error) {
delete this._frame;
delete this._message;
this._stage = 5;
var sendCloseFrame = (this.readyState === 1);
this.readyState = 2;
this._extensions.close(function() {
if (sendCloseFrame) this.frame(reason, 'close', code);
this.readyState = 3;
if (error) this.emit('error', new Error(reason));
this.emit('close', new Base$6.CloseEvent(code, reason));
}, this);
},
_fail: function(type, message) {
if (this.readyState > 1) return;
this._shutdown(this.ERRORS[type], message, true);
},
_parseOpcode: function(octet) {
var rsvs = [this.RSV1, this.RSV2, this.RSV3].map(function(rsv) {
return (octet & rsv) === rsv;
});
var frame = this._frame = new Frame();
frame.final = (octet & this.FIN) === this.FIN;
frame.rsv1 = rsvs[0];
frame.rsv2 = rsvs[1];
frame.rsv3 = rsvs[2];
frame.opcode = (octet & this.OPCODE);
this._stage = 1;
if (!this._extensions.validFrameRsv(frame))
return this._fail('protocol_error',
'One or more reserved bits are on: reserved1 = ' + (frame.rsv1 ? 1 : 0) +
', reserved2 = ' + (frame.rsv2 ? 1 : 0) +
', reserved3 = ' + (frame.rsv3 ? 1 : 0));
if (this.OPCODE_CODES.indexOf(frame.opcode) < 0)
return this._fail('protocol_error', 'Unrecognized frame opcode: ' + frame.opcode);
if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && !frame.final)
return this._fail('protocol_error', 'Received fragmented control frame: opcode = ' + frame.opcode);
if (this._message && this.OPENING_OPCODES.indexOf(frame.opcode) >= 0)
return this._fail('protocol_error', 'Received new data frame but previous continuous frame is unfinished');
},
_parseLength: function(octet) {
var frame = this._frame;
frame.masked = (octet & this.MASK) === this.MASK;
frame.length = (octet & this.LENGTH);
if (frame.length >= 0 && frame.length <= 125) {
this._stage = frame.masked ? 3 : 4;
if (!this._checkFrameLength()) return;
} else {
this._stage = 2;
frame.lengthBytes = (frame.length === 126 ? 2 : 8);
}
if (this._requireMasking && !frame.masked)
return this._fail('unacceptable', 'Received unmasked frame but masking is required');
},
_parseExtendedLength: function(buffer) {
var frame = this._frame;
frame.length = this._readUInt(buffer);
this._stage = frame.masked ? 3 : 4;
if (this.MESSAGE_OPCODES.indexOf(frame.opcode) < 0 && frame.length > 125)
return this._fail('protocol_error', 'Received control frame having too long payload: ' + frame.length);
if (!this._checkFrameLength()) return;
},
_checkFrameLength: function() {
var length = this._message ? this._message.length : 0;
if (length + this._frame.length > this._maxLength) {
this._fail('too_large', 'WebSocket frame length too large');
return false;
} else {
return true;
}
},
_emitFrame: function(buffer) {
var frame = this._frame,
payload = frame.payload = Hybi$2.mask(buffer, frame.maskingKey),
opcode = frame.opcode,
message,
code, reason,
callbacks, callback;
delete this._frame;
if (opcode === this.OPCODES.continuation) {
if (!this._message) return this._fail('protocol_error', 'Received unexpected continuation frame');
this._message.pushFrame(frame);
}
if (opcode === this.OPCODES.text || opcode === this.OPCODES.binary) {
this._message = new Message();
this._message.pushFrame(frame);
}
if (frame.final && this.MESSAGE_OPCODES.indexOf(opcode) >= 0)
return this._emitMessage(this._message);
if (opcode === this.OPCODES.close) {
code = (payload.length >= 2) ? payload.readUInt16BE(0) : null;
reason = (payload.length > 2) ? this._encode(payload.slice(2)) : null;
if (!(payload.length === 0) &&
!(code !== null && code >= this.MIN_RESERVED_ERROR && code <= this.MAX_RESERVED_ERROR) &&
this.ERROR_CODES.indexOf(code) < 0)
code = this.ERRORS.protocol_error;
if (payload.length > 125 || (payload.length > 2 && !reason))
code = this.ERRORS.protocol_error;
this._shutdown(code || this.DEFAULT_ERROR_CODE, reason || '');
}
if (opcode === this.OPCODES.ping) {
this.frame(payload, 'pong');
this.emit('ping', new Base$6.PingEvent(payload.toString()));
}
if (opcode === this.OPCODES.pong) {
callbacks = this._pingCallbacks;
message = this._encode(payload);
callback = callbacks[message];
delete callbacks[message];
if (callback) callback();
this.emit('pong', new Base$6.PongEvent(payload.toString()));
}
},
_emitMessage: function(message) {
var message = this._message;
message.read();
delete this._message;
this._extensions.processIncomingMessage(message, function(error, message) {
if (error) return this._fail('extension_error', error.message);
var payload = message.data;
if (message.opcode === this.OPCODES.text) payload = this._encode(payload);
if (payload === null)
return this._fail('encoding_error', 'Could not decode a text frame as UTF-8');
else
this.emit('message', new Base$6.MessageEvent(payload));
}, this);
},
_encode: function(buffer) {
try {
var string = buffer.toString('binary', 0, buffer.length);
if (!this.UTF8_MATCH.test(string)) return null;
} catch (e) {}
return buffer.toString('utf8', 0, buffer.length);
},
_readUInt: function(buffer) {
if (buffer.length === 2) return buffer.readUInt16BE(0);
return buffer.readUInt32BE(0) * 0x100000000 +
buffer.readUInt32BE(4);
}
};
for (var key$7 in instance$7)
Hybi$2.prototype[key$7] = instance$7[key$7];
var hybi = Hybi$2;
var Buffer$4 = safeBuffer.exports.Buffer,
Stream$2 = require$$0__default$1["default"].Stream,
url$2 = require$$2__default$1["default"],
util$9 = require$$2__default["default"],
Base$5 = base,
Headers$1 = headers,
HttpParser$2 = http_parser;
var PORTS = { 'ws:': 80, 'wss:': 443 };
var Proxy$1 = function(client, origin, options) {
this._client = client;
this._http = new HttpParser$2('response');
this._origin = (typeof client.url === 'object') ? client.url : url$2.parse(client.url);
this._url = (typeof origin === 'object') ? origin : url$2.parse(origin);
this._options = options || {};
this._state = 0;
this.readable = this.writable = true;
this._paused = false;
this._headers = new Headers$1();
this._headers.set('Host', this._origin.host);
this._headers.set('Connection', 'keep-alive');
this._headers.set('Proxy-Connection', 'keep-alive');
var auth = this._url.auth && Buffer$4.from(this._url.auth, 'utf8').toString('base64');
if (auth) this._headers.set('Proxy-Authorization', 'Basic ' + auth);
};
util$9.inherits(Proxy$1, Stream$2);
var instance$6 = {
setHeader: function(name, value) {
if (this._state !== 0) return false;
this._headers.set(name, value);
return true;
},
start: function() {
if (this._state !== 0) return false;
this._state = 1;
var origin = this._origin,
port = origin.port || PORTS[origin.protocol],
start = 'CONNECT ' + origin.hostname + ':' + port + ' HTTP/1.1';
var headers = [start, this._headers.toString(), ''];
this.emit('data', Buffer$4.from(headers.join('\r\n'), 'utf8'));
return true;
},
pause: function() {
this._paused = true;
},
resume: function() {
this._paused = false;
this.emit('drain');
},
write: function(chunk) {
if (!this.writable) return false;
this._http.parse(chunk);
if (!this._http.isComplete()) return !this._paused;
this.statusCode = this._http.statusCode;
this.headers = this._http.headers;
if (this.statusCode === 200) {
this.emit('connect', new Base$5.ConnectEvent());
} else {
var message = "Can't establish a connection to the server at " + this._origin.href;
this.emit('error', new Error(message));
}
this.end();
return !this._paused;
},
end: function(chunk) {
if (!this.writable) return;
if (chunk !== undefined) this.write(chunk);
this.readable = this.writable = false;
this.emit('close');
this.emit('end');
},
destroy: function() {
this.end();
}
};
for (var key$6 in instance$6)
Proxy$1.prototype[key$6] = instance$6[key$6];
var proxy = Proxy$1;
var Buffer$3 = safeBuffer.exports.Buffer,
crypto$1 = require$$1__default$1["default"],
url$1 = require$$2__default$1["default"],
util$8 = require$$2__default["default"],
HttpParser$1 = http_parser,
Base$4 = base,
Hybi$1 = hybi,
Proxy = proxy;
var Client$2 = function(_url, options) {
this.version = 'hybi-' + Hybi$1.VERSION;
Hybi$1.call(this, null, _url, options);
this.readyState = -1;
this._key = Client$2.generateKey();
this._accept = Hybi$1.generateAccept(this._key);
this._http = new HttpParser$1('response');
var uri = url$1.parse(this.url),
auth = uri.auth && Buffer$3.from(uri.auth, 'utf8').toString('base64');
if (this.VALID_PROTOCOLS.indexOf(uri.protocol) < 0)
throw new Error(this.url + ' is not a valid WebSocket URL');
this._pathname = (uri.pathname || '/') + (uri.search || '');
this._headers.set('Host', uri.host);
this._headers.set('Upgrade', 'websocket');
this._headers.set('Connection', 'Upgrade');
this._headers.set('Sec-WebSocket-Key', this._key);
this._headers.set('Sec-WebSocket-Version', Hybi$1.VERSION);
if (this._protocols.length > 0)
this._headers.set('Sec-WebSocket-Protocol', this._protocols.join(', '));
if (auth)
this._headers.set('Authorization', 'Basic ' + auth);
};
util$8.inherits(Client$2, Hybi$1);
Client$2.generateKey = function() {
return crypto$1.randomBytes(16).toString('base64');
};
var instance$5 = {
VALID_PROTOCOLS: ['ws:', 'wss:'],
proxy: function(origin, options) {
return new Proxy(this, origin, options);
},
start: function() {
if (this.readyState !== -1) return false;
this._write(this._handshakeRequest());
this.readyState = 0;
return true;
},
parse: function(chunk) {
if (this.readyState === 3) return;
if (this.readyState > 0) return Hybi$1.prototype.parse.call(this, chunk);
this._http.parse(chunk);
if (!this._http.isComplete()) return;
this._validateHandshake();
if (this.readyState === 3) return;
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(), ''];
return Buffer$3.from(headers.join('\r\n'), 'utf8');
},
_failHandshake: function(message) {
message = 'Error during WebSocket handshake: ' + message;
this.readyState = 3;
this.emit('error', new Error(message));
this.emit('close', new Base$4.CloseEvent(this.ERRORS.protocol_error, message));
},
_validateHandshake: function() {
this.statusCode = this._http.statusCode;
this.headers = this._http.headers;
if (this._http.error)
return this._failHandshake(this._http.error.message);
if (this._http.statusCode !== 101)
return this._failHandshake('Unexpected response code: ' + this._http.statusCode);
var headers = this._http.headers,
upgrade = headers['upgrade'] || '',
connection = headers['connection'] || '',
accept = headers['sec-websocket-accept'] || '',
protocol = headers['sec-websocket-protocol'] || '';
if (upgrade === '')
return this._failHandshake("'Upgrade' header is missing");
if (upgrade.toLowerCase() !== 'websocket')
return this._failHandshake("'Upgrade' header value is not 'WebSocket'");
if (connection === '')
return this._failHandshake("'Connection' header is missing");
if (connection.toLowerCase() !== 'upgrade')
return this._failHandshake("'Connection' header value is not 'Upgrade'");
if (accept !== this._accept)
return this._failHandshake('Sec-WebSocket-Accept mismatch');
this.protocol = null;
if (protocol !== '') {
if (this._protocols.indexOf(protocol) < 0)
return this._failHandshake('Sec-WebSocket-Protocol mismatch');
else
this.protocol = protocol;
}
try {
this._extensions.activate(this.headers['sec-websocket-extensions']);
} catch (e) {
return this._failHandshake(e.message);
}
}
};
for (var key$5 in instance$5)
Client$2.prototype[key$5] = instance$5[key$5];
var client$1 = Client$2;
var Buffer$2 = safeBuffer.exports.Buffer,
Base$3 = base,
util$7 = require$$2__default["default"];
var Draft75$2 = function(request, url, options) {
Base$3.apply(this, arguments);
this._stage = 0;
this.version = 'hixie-75';
this._headers.set('Upgrade', 'WebSocket');
this._headers.set('Connection', 'Upgrade');
this._headers.set('WebSocket-Origin', this._request.headers.origin);
this._headers.set('WebSocket-Location', this.url);
};
util$7.inherits(Draft75$2, Base$3);
var instance$4 = {
close: function() {
if (this.readyState === 3) return false;
this.readyState = 3;
this.emit('close', new Base$3.CloseEvent(null, null));
return true;
},
parse: function(chunk) {
if (this.readyState > 1) return;
this._reader.put(chunk);
this._reader.eachByte(function(octet) {
var message;
switch (this._stage) {
case -1:
this._body.push(octet);
this._sendHandshakeBody();
break;
case 0:
this._parseLeadingByte(octet);
break;
case 1:
this._length = (octet & 0x7F) + 128 * this._length;
if (this._closing && this._length === 0) {
return this.close();
}
else if ((octet & 0x80) !== 0x80) {
if (this._length === 0) {
this._stage = 0;
}
else {
this._skipped = 0;
this._stage = 2;
}
}
break;
case 2:
if (octet === 0xFF) {
this._stage = 0;
message = Buffer$2.from(this._buffer).toString('utf8', 0, this._buffer.length);
this.emit('message', new Base$3.MessageEvent(message));
}
else {
if (this._length) {
this._skipped += 1;
if (this._skipped === this._length)
this._stage = 0;
} else {
this._buffer.push(octet);
if (this._buffer.length > this._maxLength) return this.close();
}
}
break;
}
}, this);
},
frame: function(buffer) {
if (this.readyState === 0) return this._queue([buffer]);
if (this.readyState > 1) return false;
if (typeof buffer !== 'string') buffer = buffer.toString();
var length = Buffer$2.byteLength(buffer),
frame = Buffer$2.allocUnsafe(length + 2);
frame[0] = 0x00;
frame.write(buffer, 1);
frame[frame.length - 1] = 0xFF;
this._write(frame);
return true;
},
_handshakeResponse: function() {
var start = 'HTTP/1.1 101 Web Socket Protocol Handshake',
headers = [start, this._headers.toString(), ''];
return Buffer$2.from(headers.join('\r\n'), 'utf8');
},
_parseLeadingByte: function(octet) {
if ((octet & 0x80) === 0x80) {
this._length = 0;
this._stage = 1;
} else {
delete this._length;
delete this._skipped;
this._buffer = [];
this._stage = 2;
}
}
};
for (var key$4 in instance$4)
Draft75$2.prototype[key$4] = instance$4[key$4];
var draft75 = Draft75$2;
var Buffer$1 = safeBuffer.exports.Buffer,
Base$2 = base,
Draft75$1 = draft75,
crypto = require$$1__default$1["default"],
util$6 = require$$2__default["default"];
var numberFromKey = function(key) {
return parseInt((key.match(/[0-9]/g) || []).join(''), 10);
};
var spacesInKey = function(key) {
return (key.match(/ /g) || []).length;
};
var Draft76$1 = function(request, url, options) {
Draft75$1.apply(this, arguments);
this._stage = -1;
this._body = [];
this.version = 'hixie-76';
this._headers.clear();
this._headers.set('Upgrade', 'WebSocket');
this._headers.set('Connection', 'Upgrade');
this._headers.set('Sec-WebSocket-Origin', this._request.headers.origin);
this._headers.set('Sec-WebSocket-Location', this.url);
};
util$6.inherits(Draft76$1, Draft75$1);
var instance$3 = {
BODY_SIZE: 8,
start: function() {
if (!Draft75$1.prototype.start.call(this)) return false;
this._started = true;
this._sendHandshakeBody();
return true;
},
close: function() {
if (this.readyState === 3) return false;
if (this.readyState === 1) this._write(Buffer$1.from([0xFF, 0x00]));
this.readyState = 3;
this.emit('close', new Base$2.CloseEvent(null, null));
return true;
},
_handshakeResponse: function() {
var headers = this._request.headers,
key1 = headers['sec-websocket-key1'],
key2 = headers['sec-websocket-key2'];
if (!key1) throw new Error('Missing required header: Sec-WebSocket-Key1');
if (!key2) throw new Error('Missing required header: Sec-WebSocket-Key2');
var number1 = numberFromKey(key1),
spaces1 = spacesInKey(key1),
number2 = numberFromKey(key2),
spaces2 = spacesInKey(key2);
if (number1 % spaces1 !== 0 || number2 % spaces2 !== 0)
throw new Error('Client sent invalid Sec-WebSocket-Key headers');
this._keyValues = [number1 / spaces1, number2 / spaces2];
var start = 'HTTP/1.1 101 WebSocket Protocol Handshake',
headers = [start, this._headers.toString(), ''];
return Buffer$1.from(headers.join('\r\n'), 'binary');
},
_handshakeSignature: function() {
if (this._body.length < this.BODY_SIZE) return null;
var md5 = crypto.createHash('md5'),
buffer = Buffer$1.allocUnsafe(8 + this.BODY_SIZE);
buffer.writeUInt32BE(this._keyValues[0], 0);
buffer.writeUInt32BE(this._keyValues[1], 4);
Buffer$1.from(this._body).copy(buffer, 8, 0, this.BODY_SIZE);
md5.update(buffer);
return Buffer$1.from(md5.digest('binary'), 'binary');
},
_sendHandshakeBody: function() {
if (!this._started) return;
var signature = this._handshakeSignature();
if (!signature) return;
this._write(signature);
this._stage = 0;
this._open();
if (this._body.length > this.BODY_SIZE)
this.parse(this._body.slice(this.BODY_SIZE));
},
_parseLeadingByte: function(octet) {
if (octet !== 0xFF)
return Draft75$1.prototype._parseLeadingByte.call(this, octet);
this._closing = true;
this._length = 0;
this._stage = 1;
}
};
for (var key$3 in instance$3)
Draft76$1.prototype[key$3] = instance$3[key$3];
var draft76 = Draft76$1;
var util$5 = require$$2__default["default"],
HttpParser = http_parser,
Base$1 = base,
Draft75 = draft75,
Draft76 = draft76,
Hybi = hybi;
var Server$1 = function(options) {
Base$1.call(this, null, null, options);
this._http = new HttpParser('request');
};
util$5.inherits(Server$1, Base$1);
var instance$2 = {
EVENTS: ['open', 'message', 'error', 'close', 'ping', 'pong'],
_bindEventListeners: function() {
this.messages.on('error', function() {});
this.on('error', function() {});
},
parse: function(chunk) {
if (this._delegate) return this._delegate.parse(chunk);
this._http.parse(chunk);
if (!this._http.isComplete()) return;
this.method = this._http.method;
this.url = this._http.url;
this.headers = this._http.headers;
this.body = this._http.body;
var self = this;
this._delegate = Server$1.http(this, this._options);
this._delegate.messages = this.messages;
this._delegate.io = this.io;
this._open();
this.EVENTS.forEach(function(event) {
this._delegate.on(event, function(e) { self.emit(event, e); });
}, this);
this.protocol = this._delegate.protocol;
this.version = this._delegate.version;
this.parse(this._http.body);
this.emit('connect', new Base$1.ConnectEvent());
},
_open: function() {
this.__queue.forEach(function(msg) {
this._delegate[msg[0]].apply(this._delegate, msg[1]);
}, this);
this.__queue = [];
}
};
['addExtension', 'setHeader', 'start', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) {
instance$2[method] = function() {
if (this._delegate) {
return this._delegate[method].apply(this._delegate, arguments);
} else {
this.__queue.push([method, arguments]);
return true;
}
};
});
for (var key$2 in instance$2)
Server$1.prototype[key$2] = instance$2[key$2];
Server$1.isSecureRequest = function(request) {
if (request.connection && request.connection.authorized !== undefined) return true;
if (request.socket && request.socket.secure) return true;
var headers = request.headers;
if (!headers) return false;
if (headers['https'] === 'on') return true;
if (headers['x-forwarded-ssl'] === 'on') return true;
if (headers['x-forwarded-scheme'] === 'https') return true;
if (headers['x-forwarded-proto'] === 'https') return true;
return false;
};
Server$1.determineUrl = function(request) {
var scheme = this.isSecureRequest(request) ? 'wss:' : 'ws:';
return scheme + '//' + request.headers.host + request.url;
};
Server$1.http = function(request, options) {
options = options || {};
if (options.requireMasking === undefined) options.requireMasking = true;
var headers = request.headers,
version = headers['sec-websocket-version'],
key = headers['sec-websocket-key'],
key1 = headers['sec-websocket-key1'],
key2 = headers['sec-websocket-key2'],
url = this.determineUrl(request);
if (version || key)
return new Hybi(request, url, options);
else if (key1 || key2)
return new Draft76(request, url, options);
else
return new Draft75(request, url, options);
};
var server = Server$1;
// Protocol references:
//
// * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
// * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
// * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
var Base = base,
Client$1 = client$1,
Server = server;
var Driver = {
client: function(url, options) {
options = options || {};
if (options.masking === undefined) options.masking = true;
return new Client$1(url, options);
},
server: function(options) {
options = options || {};
if (options.requireMasking === undefined) options.requireMasking = true;
return new Server(options);
},
http: function() {
return Server.http.apply(Server, arguments);
},
isSecureRequest: function(request) {
return Server.isSecureRequest(request);
},
isWebSocket: function(request) {
return Base.isWebSocket(request);
},
validateOptions: function(options, validKeys) {
Base.validateOptions(options, validKeys);
}
};
var driver$4 = Driver;
var Event$3 = function(eventType, options) {
this.type = eventType;
for (var key in options)
this[key] = options[key];
};
Event$3.prototype.initEvent = function(eventType, canBubble, cancelable) {
this.type = eventType;
this.bubbles = canBubble;
this.cancelable = cancelable;
};
Event$3.prototype.stopPropagation = function() {};
Event$3.prototype.preventDefault = function() {};
Event$3.CAPTURING_PHASE = 1;
Event$3.AT_TARGET = 2;
Event$3.BUBBLING_PHASE = 3;
var event = Event$3;
var Event$2 = event;
var EventTarget$2 = {
onopen: null,
onmessage: null,
onerror: null,
onclose: null,
addEventListener: function(eventType, listener, useCapture) {
this.on(eventType, listener);
},
removeEventListener: function(eventType, listener, useCapture) {
this.removeListener(eventType, listener);
},
dispatchEvent: function(event) {
event.target = event.currentTarget = this;
event.eventPhase = Event$2.AT_TARGET;
if (this['on' + event.type])
this['on' + event.type](event);
this.emit(event.type, event);
}
};
var event_target = EventTarget$2;
var Stream$1 = require$$0__default$1["default"].Stream,
util$4 = require$$2__default["default"],
driver$3 = driver$4,
EventTarget$1 = event_target,
Event$1 = event;
var API$3 = function(options) {
options = options || {};
driver$3.validateOptions(options, ['headers', 'extensions', 'maxLength', 'ping', 'proxy', 'tls', 'ca']);
this.readable = this.writable = true;
var headers = options.headers;
if (headers) {
for (var name in headers) this._driver.setHeader(name, headers[name]);
}
var extensions = options.extensions;
if (extensions) {
[].concat(extensions).forEach(this._driver.addExtension, this._driver);
}
this._ping = options.ping;
this._pingId = 0;
this.readyState = API$3.CONNECTING;
this.bufferedAmount = 0;
this.protocol = '';
this.url = this._driver.url;
this.version = this._driver.version;
var self = this;
this._driver.on('open', function(e) { self._open(); });
this._driver.on('message', function(e) { self._receiveMessage(e.data); });
this._driver.on('close', function(e) { self._beginClose(e.reason, e.code); });
this._driver.on('error', function(error) {
self._emitError(error.message);
});
this.on('error', function() {});
this._driver.messages.on('drain', function() {
self.emit('drain');
});
if (this._ping)
this._pingTimer = setInterval(function() {
self._pingId += 1;
self.ping(self._pingId.toString());
}, this._ping * 1000);
this._configureStream();
if (!this._proxy) {
this._stream.pipe(this._driver.io);
this._driver.io.pipe(this._stream);
}
};
util$4.inherits(API$3, Stream$1);
API$3.CONNECTING = 0;
API$3.OPEN = 1;
API$3.CLOSING = 2;
API$3.CLOSED = 3;
API$3.CLOSE_TIMEOUT = 30000;
var instance$1 = {
write: function(data) {
return this.send(data);
},
end: function(data) {
if (data !== undefined) this.send(data);
this.close();
},
pause: function() {
return this._driver.messages.pause();
},
resume: function() {
return this._driver.messages.resume();
},
send: function(data) {
if (this.readyState > API$3.OPEN) return false;
if (!(data instanceof Buffer)) data = String(data);
return this._driver.messages.write(data);
},
ping: function(message, callback) {
if (this.readyState > API$3.OPEN) return false;
return this._driver.ping(message, callback);
},
close: function(code, reason) {
if (code === undefined) code = 1000;
if (reason === undefined) reason = '';
if (code !== 1000 && (code < 3000 || code > 4999))
throw new Error("Failed to execute 'close' on WebSocket: " +
"The code must be either 1000, or between 3000 and 4999. " +
code + " is neither.");
if (this.readyState < API$3.CLOSING) {
var self = this;
this._closeTimer = setTimeout(function() {
self._beginClose('', 1006);
}, API$3.CLOSE_TIMEOUT);
}
if (this.readyState !== API$3.CLOSED) this.readyState = API$3.CLOSING;
this._driver.close(reason, code);
},
_configureStream: function() {
var self = this;
this._stream.setTimeout(0);
this._stream.setNoDelay(true);
['close', 'end'].forEach(function(event) {
this._stream.on(event, function() { self._finalizeClose(); });
}, this);
this._stream.on('error', function(error) {
self._emitError('Network error: ' + self.url + ': ' + error.message);
self._finalizeClose();
});
},
_open: function() {
if (this.readyState !== API$3.CONNECTING) return;
this.readyState = API$3.OPEN;
this.protocol = this._driver.protocol || '';
var event = new Event$1('open');
event.initEvent('open', false, false);
this.dispatchEvent(event);
},
_receiveMessage: function(data) {
if (this.readyState > API$3.OPEN) return false;
if (this.readable) this.emit('data', data);
var event = new Event$1('message', { data: data });
event.initEvent('message', false, false);
this.dispatchEvent(event);
},
_emitError: function(message) {
if (this.readyState >= API$3.CLOSING) return;
var event = new Event$1('error', { message: message });
event.initEvent('error', false, false);
this.dispatchEvent(event);
},
_beginClose: function(reason, code) {
if (this.readyState === API$3.CLOSED) return;
this.readyState = API$3.CLOSING;
this._closeParams = [reason, code];
if (this._stream) {
this._stream.destroy();
if (!this._stream.readable) this._finalizeClose();
}
},
_finalizeClose: function() {
if (this.readyState === API$3.CLOSED) return;
this.readyState = API$3.CLOSED;
if (this._closeTimer) clearTimeout(this._closeTimer);
if (this._pingTimer) clearInterval(this._pingTimer);
if (this._stream) this._stream.end();
if (this.readable) this.emit('end');
this.readable = this.writable = false;
var reason = this._closeParams ? this._closeParams[0] : '',
code = this._closeParams ? this._closeParams[1] : 1006;
var event = new Event$1('close', { code: code, reason: reason });
event.initEvent('close', false, false);
this.dispatchEvent(event);
}
};
for (var method$1 in instance$1) API$3.prototype[method$1] = instance$1[method$1];
for (var key$1 in EventTarget$1) API$3.prototype[key$1] = EventTarget$1[key$1];
var api = API$3;
var util$3 = require$$2__default["default"],
net = require$$1__default$2["default"],
tls = require$$2__default$2["default"],
url = require$$2__default$1["default"],
driver$2 = driver$4,
API$2 = api;
var DEFAULT_PORTS = { 'http:': 80, 'https:': 443, 'ws:':80, 'wss:': 443 },
SECURE_PROTOCOLS = ['https:', 'wss:'];
var Client = function(_url, protocols, options) {
options = options || {};
this.url = _url;
this._driver = driver$2.client(this.url, { maxLength: options.maxLength, protocols: protocols });
['open', 'error'].forEach(function(event) {
this._driver.on(event, function() {
self.headers = self._driver.headers;
self.statusCode = self._driver.statusCode;
});
}, this);
var proxy = options.proxy || {},
endpoint = url.parse(proxy.origin || this.url),
port = endpoint.port || DEFAULT_PORTS[endpoint.protocol],
secure = SECURE_PROTOCOLS.indexOf(endpoint.protocol) >= 0,
onConnect = function() { self._onConnect(); },
netOptions = options.net || {},
originTLS = options.tls || {},
socketTLS = proxy.origin ? (proxy.tls || {}) : originTLS,
self = this;
netOptions.host = socketTLS.host = endpoint.hostname;
netOptions.port = socketTLS.port = port;
originTLS.ca = originTLS.ca || options.ca;
socketTLS.servername = socketTLS.servername || endpoint.hostname;
this._stream = secure
? tls.connect(socketTLS, onConnect)
: net.connect(netOptions, onConnect);
if (proxy.origin) this._configureProxy(proxy, originTLS);
API$2.call(this, options);
};
util$3.inherits(Client, API$2);
Client.prototype._onConnect = function() {
var worker = this._proxy || this._driver;
worker.start();
};
Client.prototype._configureProxy = function(proxy, originTLS) {
var uri = url.parse(this.url),
secure = SECURE_PROTOCOLS.indexOf(uri.protocol) >= 0,
self = this,
name;
this._proxy = this._driver.proxy(proxy.origin);
if (proxy.headers) {
for (name in proxy.headers) this._proxy.setHeader(name, proxy.headers[name]);
}
this._proxy.pipe(this._stream, { end: false });
this._stream.pipe(this._proxy);
this._proxy.on('connect', function() {
if (secure) {
var options = { socket: self._stream, servername: uri.hostname };
for (name in originTLS) options[name] = originTLS[name];
self._stream = tls.connect(options);
self._configureStream();
}
self._driver.io.pipe(self._stream);
self._stream.pipe(self._driver.io);
self._driver.start();
});
this._proxy.on('error', function(error) {
self._driver.emit('error', error);
});
};
var client = Client;
var Stream = require$$0__default$1["default"].Stream,
util$2 = require$$2__default["default"],
driver$1 = driver$4,
Headers = headers,
API$1 = api,
EventTarget = event_target,
Event = event;
var EventSource = function(request, response, options) {
this.writable = true;
options = options || {};
this._stream = response.socket;
this._ping = options.ping || this.DEFAULT_PING;
this._retry = options.retry || this.DEFAULT_RETRY;
var scheme = driver$1.isSecureRequest(request) ? 'https:' : 'http:';
this.url = scheme + '//' + request.headers.host + request.url;
this.lastEventId = request.headers['last-event-id'] || '';
this.readyState = API$1.CONNECTING;
var headers = new Headers(),
self = this;
if (options.headers) {
for (var key in options.headers) headers.set(key, options.headers[key]);
}
if (!this._stream || !this._stream.writable) return;
process.nextTick(function() { self._open(); });
this._stream.setTimeout(0);
this._stream.setNoDelay(true);
var handshake = 'HTTP/1.1 200 OK\r\n' +
'Content-Type: text/event-stream\r\n' +
'Cache-Control: no-cache, no-store\r\n' +
'Connection: close\r\n' +
headers.toString() +
'\r\n' +
'retry: ' + Math.floor(this._retry * 1000) + '\r\n\r\n';
this._write(handshake);
this._stream.on('drain', function() { self.emit('drain'); });
if (this._ping)
this._pingTimer = setInterval(function() { self.ping(); }, this._ping * 1000);
['error', 'end'].forEach(function(event) {
self._stream.on(event, function() { self.close(); });
});
};
util$2.inherits(EventSource, Stream);
EventSource.isEventSource = function(request) {
if (request.method !== 'GET') return false;
var accept = (request.headers.accept || '').split(/\s*,\s*/);
return accept.indexOf('text/event-stream') >= 0;
};
var instance = {
DEFAULT_PING: 10,
DEFAULT_RETRY: 5,
_write: function(chunk) {
if (!this.writable) return false;
try {
return this._stream.write(chunk, 'utf8');
} catch (e) {
return false;
}
},
_open: function() {
if (this.readyState !== API$1.CONNECTING) return;
this.readyState = API$1.OPEN;
var event = new Event('open');
event.initEvent('open', false, false);
this.dispatchEvent(event);
},
write: function(message) {
return this.send(message);
},
end: function(message) {
if (message !== undefined) this.write(message);
this.close();
},
send: function(message, options) {
if (this.readyState > API$1.OPEN) return false;
message = String(message).replace(/(\r\n|\r|\n)/g, '$1data: ');
options = options || {};
var frame = '';
if (options.event) frame += 'event: ' + options.event + '\r\n';
if (options.id) frame += 'id: ' + options.id + '\r\n';
frame += 'data: ' + message + '\r\n\r\n';
return this._write(frame);
},
ping: function() {
return this._write(':\r\n\r\n');
},
close: function() {
if (this.