Init. Map does not function and only working on backend at the moment.
This commit is contained in:
3
node_modules/engine.io-client/node_modules/debug/.jshintrc
generated
vendored
Normal file
3
node_modules/engine.io-client/node_modules/debug/.jshintrc
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"laxbreak": true
|
||||
}
|
7
node_modules/engine.io-client/node_modules/debug/.npmignore
generated
vendored
Normal file
7
node_modules/engine.io-client/node_modules/debug/.npmignore
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
support
|
||||
test
|
||||
examples
|
||||
example
|
||||
*.sock
|
||||
dist
|
||||
yarn.lock
|
235
node_modules/engine.io-client/node_modules/debug/CHANGELOG.md
generated
vendored
Normal file
235
node_modules/engine.io-client/node_modules/debug/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
2.3.3 / 2016-11-09
|
||||
==================
|
||||
|
||||
* Fix: Catch `JSON.stringify()` errors (#195, Jovan Alleyne)
|
||||
* Fix: Returning `localStorage` saved values (#331, Levi Thomason)
|
||||
* Improvement: Don't create an empty object when no `process` (Nathan Rajlich)
|
||||
|
||||
2.3.2 / 2016-11-09
|
||||
==================
|
||||
|
||||
* Fix: be super-safe in index.js as well (@TooTallNate)
|
||||
* Fix: should check whether process exists (Tom Newby)
|
||||
|
||||
2.3.1 / 2016-11-09
|
||||
==================
|
||||
|
||||
* Fix: Added electron compatibility (#324, @paulcbetts)
|
||||
* Improvement: Added performance optimizations (@tootallnate)
|
||||
* Readme: Corrected PowerShell environment variable example (#252, @gimre)
|
||||
* Misc: Removed yarn lock file from source control (#321, @fengmk2)
|
||||
|
||||
2.3.0 / 2016-11-07
|
||||
==================
|
||||
|
||||
* Fix: Consistent placement of ms diff at end of output (#215, @gorangajic)
|
||||
* Fix: Escaping of regex special characters in namespace strings (#250, @zacronos)
|
||||
* Fix: Fixed bug causing crash on react-native (#282, @vkarpov15)
|
||||
* Feature: Enabled ES6+ compatible import via default export (#212 @bucaran)
|
||||
* Feature: Added %O formatter to reflect Chrome's console.log capability (#279, @oncletom)
|
||||
* Package: Update "ms" to 0.7.2 (#315, @DevSide)
|
||||
* Package: removed superfluous version property from bower.json (#207 @kkirsche)
|
||||
* Readme: fix USE_COLORS to DEBUG_COLORS
|
||||
* Readme: Doc fixes for format string sugar (#269, @mlucool)
|
||||
* Readme: Updated docs for DEBUG_FD and DEBUG_COLORS environment variables (#232, @mattlyons0)
|
||||
* Readme: doc fixes for PowerShell (#271 #243, @exoticknight @unreadable)
|
||||
* Readme: better docs for browser support (#224, @matthewmueller)
|
||||
* Tooling: Added yarn integration for development (#317, @thebigredgeek)
|
||||
* Misc: Renamed History.md to CHANGELOG.md (@thebigredgeek)
|
||||
* Misc: Added license file (#226 #274, @CantemoInternal @sdaitzman)
|
||||
* Misc: Updated contributors (@thebigredgeek)
|
||||
|
||||
2.2.0 / 2015-05-09
|
||||
==================
|
||||
|
||||
* package: update "ms" to v0.7.1 (#202, @dougwilson)
|
||||
* README: add logging to file example (#193, @DanielOchoa)
|
||||
* README: fixed a typo (#191, @amir-s)
|
||||
* browser: expose `storage` (#190, @stephenmathieson)
|
||||
* Makefile: add a `distclean` target (#189, @stephenmathieson)
|
||||
|
||||
2.1.3 / 2015-03-13
|
||||
==================
|
||||
|
||||
* Updated stdout/stderr example (#186)
|
||||
* Updated example/stdout.js to match debug current behaviour
|
||||
* Renamed example/stderr.js to stdout.js
|
||||
* Update Readme.md (#184)
|
||||
* replace high intensity foreground color for bold (#182, #183)
|
||||
|
||||
2.1.2 / 2015-03-01
|
||||
==================
|
||||
|
||||
* dist: recompile
|
||||
* update "ms" to v0.7.0
|
||||
* package: update "browserify" to v9.0.3
|
||||
* component: fix "ms.js" repo location
|
||||
* changed bower package name
|
||||
* updated documentation about using debug in a browser
|
||||
* fix: security error on safari (#167, #168, @yields)
|
||||
|
||||
2.1.1 / 2014-12-29
|
||||
==================
|
||||
|
||||
* browser: use `typeof` to check for `console` existence
|
||||
* browser: check for `console.log` truthiness (fix IE 8/9)
|
||||
* browser: add support for Chrome apps
|
||||
* Readme: added Windows usage remarks
|
||||
* Add `bower.json` to properly support bower install
|
||||
|
||||
2.1.0 / 2014-10-15
|
||||
==================
|
||||
|
||||
* node: implement `DEBUG_FD` env variable support
|
||||
* package: update "browserify" to v6.1.0
|
||||
* package: add "license" field to package.json (#135, @panuhorsmalahti)
|
||||
|
||||
2.0.0 / 2014-09-01
|
||||
==================
|
||||
|
||||
* package: update "browserify" to v5.11.0
|
||||
* node: use stderr rather than stdout for logging (#29, @stephenmathieson)
|
||||
|
||||
1.0.4 / 2014-07-15
|
||||
==================
|
||||
|
||||
* dist: recompile
|
||||
* example: remove `console.info()` log usage
|
||||
* example: add "Content-Type" UTF-8 header to browser example
|
||||
* browser: place %c marker after the space character
|
||||
* browser: reset the "content" color via `color: inherit`
|
||||
* browser: add colors support for Firefox >= v31
|
||||
* debug: prefer an instance `log()` function over the global one (#119)
|
||||
* Readme: update documentation about styled console logs for FF v31 (#116, @wryk)
|
||||
|
||||
1.0.3 / 2014-07-09
|
||||
==================
|
||||
|
||||
* Add support for multiple wildcards in namespaces (#122, @seegno)
|
||||
* browser: fix lint
|
||||
|
||||
1.0.2 / 2014-06-10
|
||||
==================
|
||||
|
||||
* browser: update color palette (#113, @gscottolson)
|
||||
* common: make console logging function configurable (#108, @timoxley)
|
||||
* node: fix %o colors on old node <= 0.8.x
|
||||
* Makefile: find node path using shell/which (#109, @timoxley)
|
||||
|
||||
1.0.1 / 2014-06-06
|
||||
==================
|
||||
|
||||
* browser: use `removeItem()` to clear localStorage
|
||||
* browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777)
|
||||
* package: add "contributors" section
|
||||
* node: fix comment typo
|
||||
* README: list authors
|
||||
|
||||
1.0.0 / 2014-06-04
|
||||
==================
|
||||
|
||||
* make ms diff be global, not be scope
|
||||
* debug: ignore empty strings in enable()
|
||||
* node: make DEBUG_COLORS able to disable coloring
|
||||
* *: export the `colors` array
|
||||
* npmignore: don't publish the `dist` dir
|
||||
* Makefile: refactor to use browserify
|
||||
* package: add "browserify" as a dev dependency
|
||||
* Readme: add Web Inspector Colors section
|
||||
* node: reset terminal color for the debug content
|
||||
* node: map "%o" to `util.inspect()`
|
||||
* browser: map "%j" to `JSON.stringify()`
|
||||
* debug: add custom "formatters"
|
||||
* debug: use "ms" module for humanizing the diff
|
||||
* Readme: add "bash" syntax highlighting
|
||||
* browser: add Firebug color support
|
||||
* browser: add colors for WebKit browsers
|
||||
* node: apply log to `console`
|
||||
* rewrite: abstract common logic for Node & browsers
|
||||
* add .jshintrc file
|
||||
|
||||
0.8.1 / 2014-04-14
|
||||
==================
|
||||
|
||||
* package: re-add the "component" section
|
||||
|
||||
0.8.0 / 2014-03-30
|
||||
==================
|
||||
|
||||
* add `enable()` method for nodejs. Closes #27
|
||||
* change from stderr to stdout
|
||||
* remove unnecessary index.js file
|
||||
|
||||
0.7.4 / 2013-11-13
|
||||
==================
|
||||
|
||||
* remove "browserify" key from package.json (fixes something in browserify)
|
||||
|
||||
0.7.3 / 2013-10-30
|
||||
==================
|
||||
|
||||
* fix: catch localStorage security error when cookies are blocked (Chrome)
|
||||
* add debug(err) support. Closes #46
|
||||
* add .browser prop to package.json. Closes #42
|
||||
|
||||
0.7.2 / 2013-02-06
|
||||
==================
|
||||
|
||||
* fix package.json
|
||||
* fix: Mobile Safari (private mode) is broken with debug
|
||||
* fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript
|
||||
|
||||
0.7.1 / 2013-02-05
|
||||
==================
|
||||
|
||||
* add repository URL to package.json
|
||||
* add DEBUG_COLORED to force colored output
|
||||
* add browserify support
|
||||
* fix component. Closes #24
|
||||
|
||||
0.7.0 / 2012-05-04
|
||||
==================
|
||||
|
||||
* Added .component to package.json
|
||||
* Added debug.component.js build
|
||||
|
||||
0.6.0 / 2012-03-16
|
||||
==================
|
||||
|
||||
* Added support for "-" prefix in DEBUG [Vinay Pulim]
|
||||
* Added `.enabled` flag to the node version [TooTallNate]
|
||||
|
||||
0.5.0 / 2012-02-02
|
||||
==================
|
||||
|
||||
* Added: humanize diffs. Closes #8
|
||||
* Added `debug.disable()` to the CS variant
|
||||
* Removed padding. Closes #10
|
||||
* Fixed: persist client-side variant again. Closes #9
|
||||
|
||||
0.4.0 / 2012-02-01
|
||||
==================
|
||||
|
||||
* Added browser variant support for older browsers [TooTallNate]
|
||||
* Added `debug.enable('project:*')` to browser variant [TooTallNate]
|
||||
* Added padding to diff (moved it to the right)
|
||||
|
||||
0.3.0 / 2012-01-26
|
||||
==================
|
||||
|
||||
* Added millisecond diff when isatty, otherwise UTC string
|
||||
|
||||
0.2.0 / 2012-01-22
|
||||
==================
|
||||
|
||||
* Added wildcard support
|
||||
|
||||
0.1.0 / 2011-12-02
|
||||
==================
|
||||
|
||||
* Added: remove colors unless stderr isatty [TooTallNate]
|
||||
|
||||
0.0.1 / 2010-01-03
|
||||
==================
|
||||
|
||||
* Initial release
|
19
node_modules/engine.io-client/node_modules/debug/LICENSE
generated
vendored
Normal file
19
node_modules/engine.io-client/node_modules/debug/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the 'Software'), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
37
node_modules/engine.io-client/node_modules/debug/Makefile
generated
vendored
Normal file
37
node_modules/engine.io-client/node_modules/debug/Makefile
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
|
||||
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
||||
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
|
||||
|
||||
# BIN directory
|
||||
BIN := $(THIS_DIR)/node_modules/.bin
|
||||
|
||||
# applications
|
||||
NODE ?= $(shell which node)
|
||||
YARN ?= $(shell which yarn)
|
||||
PKG ?= $(if $(YARN),$(YARN),$(NODE) $(shell which npm))
|
||||
BROWSERIFY ?= $(NODE) $(BIN)/browserify
|
||||
|
||||
all: dist/debug.js
|
||||
|
||||
install: node_modules
|
||||
|
||||
clean:
|
||||
@rm -rf dist
|
||||
|
||||
dist:
|
||||
@mkdir -p $@
|
||||
|
||||
dist/debug.js: node_modules browser.js debug.js dist
|
||||
@$(BROWSERIFY) \
|
||||
--standalone debug \
|
||||
. > $@
|
||||
|
||||
distclean: clean
|
||||
@rm -rf node_modules
|
||||
|
||||
node_modules: package.json
|
||||
@NODE_ENV= $(PKG) install
|
||||
@touch node_modules
|
||||
|
||||
.PHONY: all install clean distclean
|
199
node_modules/engine.io-client/node_modules/debug/Readme.md
generated
vendored
Normal file
199
node_modules/engine.io-client/node_modules/debug/Readme.md
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
# debug
|
||||
|
||||
tiny node.js debugging utility modelled after node core's debugging technique.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install debug
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` [format string goodies](https://developer.chrome.com/devtools/docs/console-api#consolelogobject-object) you're used to work fine. A unique color is selected per-function for visibility.
|
||||
|
||||
Example _app.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug')('http')
|
||||
, http = require('http')
|
||||
, name = 'My App';
|
||||
|
||||
// fake app
|
||||
|
||||
debug('booting %s', name);
|
||||
|
||||
http.createServer(function(req, res){
|
||||
debug(req.method + ' ' + req.url);
|
||||
res.end('hello\n');
|
||||
}).listen(3000, function(){
|
||||
debug('listening');
|
||||
});
|
||||
|
||||
// fake worker of some kind
|
||||
|
||||
require('./worker');
|
||||
```
|
||||
|
||||
Example _worker.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug')('worker');
|
||||
|
||||
setInterval(function(){
|
||||
debug('doing some work');
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### Windows note
|
||||
|
||||
On Windows the environment variable is set using the `set` command.
|
||||
|
||||
```cmd
|
||||
set DEBUG=*,-not_this
|
||||
```
|
||||
|
||||
Note that PowerShell using different syntax to set environment variables.
|
||||
|
||||
```cmd
|
||||
$env:DEBUG = "*,-not_this"
|
||||
```
|
||||
|
||||
Then, run the program to be debugged as usual.
|
||||
|
||||
## Millisecond diff
|
||||
|
||||
When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
|
||||
|
||||

|
||||
|
||||
When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
|
||||
|
||||

|
||||
|
||||
## Conventions
|
||||
|
||||
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
|
||||
|
||||
## Wildcards
|
||||
|
||||
The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
|
||||
|
||||
You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".
|
||||
|
||||
## Browser support
|
||||
|
||||
Debug works in the browser as well, currently persisted by `localStorage`. Consider the situation shown below where you have `worker:a` and `worker:b`, and wish to debug both. You can enable this using `localStorage.debug`:
|
||||
|
||||
```js
|
||||
localStorage.debug = 'worker:*'
|
||||
```
|
||||
|
||||
And then refresh the page.
|
||||
|
||||
```js
|
||||
a = debug('worker:a');
|
||||
b = debug('worker:b');
|
||||
|
||||
setInterval(function(){
|
||||
a('doing some work');
|
||||
}, 1000);
|
||||
|
||||
setInterval(function(){
|
||||
b('doing some work');
|
||||
}, 1200);
|
||||
```
|
||||
|
||||
#### Web Inspector Colors
|
||||
|
||||
Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
|
||||
option. These are WebKit web inspectors, Firefox ([since version
|
||||
31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
|
||||
and the Firebug plugin for Firefox (any version).
|
||||
|
||||
Colored output looks something like:
|
||||
|
||||

|
||||
|
||||
## Output streams
|
||||
|
||||
|
||||
### stderr vs stdout
|
||||
By default `debug` will log to stderr, however this can be changed by setting the environment variable `DEBUG_FD` to `1` for stdout and `2` for stderr (the default value).
|
||||
|
||||
You can also set an alternative logging method per-namespace by overriding the `log` method on a per-namespace or globally:
|
||||
|
||||
Example _stdout.js_:
|
||||
|
||||
```js
|
||||
var debug = require('debug');
|
||||
var error = debug('app:error');
|
||||
|
||||
// by default stderr is used
|
||||
error('goes to stderr!');
|
||||
|
||||
var log = debug('app:log');
|
||||
// set this namespace to log via console.log
|
||||
log.log = console.log.bind(console); // don't forget to bind to console!
|
||||
log('goes to stdout');
|
||||
error('still goes to stderr!');
|
||||
|
||||
// set all output to go via console.info
|
||||
// overrides all per-namespace log settings
|
||||
debug.log = console.info.bind(console);
|
||||
error('now goes to stdout via console.info');
|
||||
log('still goes to stdout, but via console.info now');
|
||||
```
|
||||
|
||||
### Save debug output to a file
|
||||
|
||||
You can save all debug statements to a file by piping them.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
$ DEBUG_FD=3 node your-app.js 3> whatever.log
|
||||
```
|
||||
|
||||
### Terminal colors
|
||||
|
||||
By default colors will only be used in a TTY. However this can be overridden by setting the environment variable `DEBUG_COLORS` to `1`.
|
||||
|
||||
Note: Certain IDEs (such as WebStorm) don't support colors on stderr. In these cases you must set `DEBUG_COLORS` to `1` and additionally change `DEBUG_FD` to `1`.
|
||||
|
||||
## Authors
|
||||
|
||||
- TJ Holowaychuk
|
||||
- Nathan Rajlich
|
||||
- Andrew Rhyne
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014-2016 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
29
node_modules/engine.io-client/node_modules/debug/bower.json
generated
vendored
Normal file
29
node_modules/engine.io-client/node_modules/debug/bower.json
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "visionmedia-debug",
|
||||
"main": "dist/debug.js",
|
||||
"homepage": "https://github.com/visionmedia/debug",
|
||||
"authors": [
|
||||
"TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"Nathan Rajlich <nathan@tootallnate.net> (http://n8.io)",
|
||||
"Andrew Rhyne <rhyneandrew@gmail.com>"
|
||||
],
|
||||
"description": "visionmedia-debug",
|
||||
"moduleType": [
|
||||
"amd",
|
||||
"es6",
|
||||
"globals",
|
||||
"node"
|
||||
],
|
||||
"keywords": [
|
||||
"visionmedia",
|
||||
"debug"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
177
node_modules/engine.io-client/node_modules/debug/browser.js
generated
vendored
Normal file
177
node_modules/engine.io-client/node_modules/debug/browser.js
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
|
||||
/**
|
||||
* This is the web browser implementation of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = require('./debug');
|
||||
exports.log = log;
|
||||
exports.formatArgs = formatArgs;
|
||||
exports.save = save;
|
||||
exports.load = load;
|
||||
exports.useColors = useColors;
|
||||
exports.storage = 'undefined' != typeof chrome
|
||||
&& 'undefined' != typeof chrome.storage
|
||||
? chrome.storage.local
|
||||
: localstorage();
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
|
||||
exports.colors = [
|
||||
'lightseagreen',
|
||||
'forestgreen',
|
||||
'goldenrod',
|
||||
'dodgerblue',
|
||||
'darkorchid',
|
||||
'crimson'
|
||||
];
|
||||
|
||||
/**
|
||||
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||||
* and the Firebug extension (any Firefox version) are known
|
||||
* to support "%c" CSS customizations.
|
||||
*
|
||||
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||||
*/
|
||||
|
||||
function useColors() {
|
||||
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||||
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
|
||||
return (typeof document !== 'undefined' && 'WebkitAppearance' in document.documentElement.style) ||
|
||||
// is firebug? http://stackoverflow.com/a/398120/376773
|
||||
(window.console && (console.firebug || (console.exception && console.table))) ||
|
||||
// is firefox >= v31?
|
||||
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||||
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||||
*/
|
||||
|
||||
exports.formatters.j = function(v) {
|
||||
try {
|
||||
return JSON.stringify(v);
|
||||
} catch (err) {
|
||||
return '[UnexpectedJSONParseError]: ' + err.message;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Colorize log arguments if enabled.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function formatArgs() {
|
||||
var args = arguments;
|
||||
var useColors = this.useColors;
|
||||
|
||||
args[0] = (useColors ? '%c' : '')
|
||||
+ this.namespace
|
||||
+ (useColors ? ' %c' : ' ')
|
||||
+ args[0]
|
||||
+ (useColors ? '%c ' : ' ')
|
||||
+ '+' + exports.humanize(this.diff);
|
||||
|
||||
if (!useColors) return args;
|
||||
|
||||
var c = 'color: ' + this.color;
|
||||
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
|
||||
|
||||
// the final "%c" is somewhat tricky, because there could be other
|
||||
// arguments passed either before or after the %c, so we need to
|
||||
// figure out the correct index to insert the CSS into
|
||||
var index = 0;
|
||||
var lastC = 0;
|
||||
args[0].replace(/%[a-z%]/g, function(match) {
|
||||
if ('%%' === match) return;
|
||||
index++;
|
||||
if ('%c' === match) {
|
||||
// we only are interested in the *last* %c
|
||||
// (the user may have provided their own)
|
||||
lastC = index;
|
||||
}
|
||||
});
|
||||
|
||||
args.splice(lastC, 0, c);
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `console.log()` when available.
|
||||
* No-op when `console.log` is not a "function".
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function log() {
|
||||
// this hackery is required for IE8/9, where
|
||||
// the `console.log` function doesn't have 'apply'
|
||||
return 'object' === typeof console
|
||||
&& console.log
|
||||
&& Function.prototype.apply.call(console.log, console, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save `namespaces`.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function save(namespaces) {
|
||||
try {
|
||||
if (null == namespaces) {
|
||||
exports.storage.removeItem('debug');
|
||||
} else {
|
||||
exports.storage.debug = namespaces;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load `namespaces`.
|
||||
*
|
||||
* @return {String} returns the previously persisted debug modes
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function load() {
|
||||
var r;
|
||||
try {
|
||||
return exports.storage.debug;
|
||||
} catch(e) {}
|
||||
|
||||
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
|
||||
if (typeof process !== 'undefined' && 'env' in process) {
|
||||
return process.env.DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable namespaces listed in `localStorage.debug` initially.
|
||||
*/
|
||||
|
||||
exports.enable(load());
|
||||
|
||||
/**
|
||||
* Localstorage attempts to return the localstorage.
|
||||
*
|
||||
* This is necessary because safari throws
|
||||
* when a user disables cookies/localstorage
|
||||
* and you attempt to access it.
|
||||
*
|
||||
* @return {LocalStorage}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function localstorage(){
|
||||
try {
|
||||
return window.localStorage;
|
||||
} catch (e) {}
|
||||
}
|
19
node_modules/engine.io-client/node_modules/debug/component.json
generated
vendored
Normal file
19
node_modules/engine.io-client/node_modules/debug/component.json
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"repo": "visionmedia/debug",
|
||||
"description": "small debugging utility",
|
||||
"version": "2.3.3",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"log",
|
||||
"debugger"
|
||||
],
|
||||
"main": "browser.js",
|
||||
"scripts": [
|
||||
"browser.js",
|
||||
"debug.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"rauchg/ms.js": "0.7.1"
|
||||
}
|
||||
}
|
200
node_modules/engine.io-client/node_modules/debug/debug.js
generated
vendored
Normal file
200
node_modules/engine.io-client/node_modules/debug/debug.js
generated
vendored
Normal file
@ -0,0 +1,200 @@
|
||||
|
||||
/**
|
||||
* This is the common logic for both the Node.js and web browser
|
||||
* implementations of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = debug.debug = debug;
|
||||
exports.coerce = coerce;
|
||||
exports.disable = disable;
|
||||
exports.enable = enable;
|
||||
exports.enabled = enabled;
|
||||
exports.humanize = require('ms');
|
||||
|
||||
/**
|
||||
* The currently active debug mode names, and names to skip.
|
||||
*/
|
||||
|
||||
exports.names = [];
|
||||
exports.skips = [];
|
||||
|
||||
/**
|
||||
* Map of special "%n" handling functions, for the debug "format" argument.
|
||||
*
|
||||
* Valid key names are a single, lowercased letter, i.e. "n".
|
||||
*/
|
||||
|
||||
exports.formatters = {};
|
||||
|
||||
/**
|
||||
* Previously assigned color.
|
||||
*/
|
||||
|
||||
var prevColor = 0;
|
||||
|
||||
/**
|
||||
* Previous log timestamp.
|
||||
*/
|
||||
|
||||
var prevTime;
|
||||
|
||||
/**
|
||||
* Select a color.
|
||||
*
|
||||
* @return {Number}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function selectColor() {
|
||||
return exports.colors[prevColor++ % exports.colors.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a debugger with the given `namespace`.
|
||||
*
|
||||
* @param {String} namespace
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function debug(namespace) {
|
||||
|
||||
// define the `disabled` version
|
||||
function disabled() {
|
||||
}
|
||||
disabled.enabled = false;
|
||||
|
||||
// define the `enabled` version
|
||||
function enabled() {
|
||||
|
||||
var self = enabled;
|
||||
|
||||
// set `diff` timestamp
|
||||
var curr = +new Date();
|
||||
var ms = curr - (prevTime || curr);
|
||||
self.diff = ms;
|
||||
self.prev = prevTime;
|
||||
self.curr = curr;
|
||||
prevTime = curr;
|
||||
|
||||
// add the `color` if not set
|
||||
if (null == self.useColors) self.useColors = exports.useColors();
|
||||
if (null == self.color && self.useColors) self.color = selectColor();
|
||||
|
||||
var args = new Array(arguments.length);
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
args[i] = arguments[i];
|
||||
}
|
||||
|
||||
args[0] = exports.coerce(args[0]);
|
||||
|
||||
if ('string' !== typeof args[0]) {
|
||||
// anything else let's inspect with %o
|
||||
args = ['%o'].concat(args);
|
||||
}
|
||||
|
||||
// apply any `formatters` transformations
|
||||
var index = 0;
|
||||
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
|
||||
// if we encounter an escaped % then don't increase the array index
|
||||
if (match === '%%') return match;
|
||||
index++;
|
||||
var formatter = exports.formatters[format];
|
||||
if ('function' === typeof formatter) {
|
||||
var val = args[index];
|
||||
match = formatter.call(self, val);
|
||||
|
||||
// now we need to remove `args[index]` since it's inlined in the `format`
|
||||
args.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
// apply env-specific formatting
|
||||
args = exports.formatArgs.apply(self, args);
|
||||
|
||||
var logFn = enabled.log || exports.log || console.log.bind(console);
|
||||
logFn.apply(self, args);
|
||||
}
|
||||
enabled.enabled = true;
|
||||
|
||||
var fn = exports.enabled(namespace) ? enabled : disabled;
|
||||
|
||||
fn.namespace = namespace;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a debug mode by namespaces. This can include modes
|
||||
* separated by a colon and wildcards.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function enable(namespaces) {
|
||||
exports.save(namespaces);
|
||||
|
||||
var split = (namespaces || '').split(/[\s,]+/);
|
||||
var len = split.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (!split[i]) continue; // ignore empty strings
|
||||
namespaces = split[i].replace(/[\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*?');
|
||||
if (namespaces[0] === '-') {
|
||||
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||||
} else {
|
||||
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable debug output.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function disable() {
|
||||
exports.enable('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given mode name is enabled, false otherwise.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function enabled(name) {
|
||||
var i, len;
|
||||
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||||
if (exports.skips[i].test(name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (i = 0, len = exports.names.length; i < len; i++) {
|
||||
if (exports.names[i].test(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce `val`.
|
||||
*
|
||||
* @param {Mixed} val
|
||||
* @return {Mixed}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function coerce(val) {
|
||||
if (val instanceof Error) return val.stack || val.message;
|
||||
return val;
|
||||
}
|
10
node_modules/engine.io-client/node_modules/debug/index.js
generated
vendored
Normal file
10
node_modules/engine.io-client/node_modules/debug/index.js
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Detect Electron renderer process, which is node, but we should
|
||||
* treat as a browser.
|
||||
*/
|
||||
|
||||
if (typeof process !== 'undefined' && process.type === 'renderer') {
|
||||
module.exports = require('./browser.js');
|
||||
} else {
|
||||
module.exports = require('./node.js');
|
||||
}
|
213
node_modules/engine.io-client/node_modules/debug/node.js
generated
vendored
Normal file
213
node_modules/engine.io-client/node_modules/debug/node.js
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var tty = require('tty');
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* This is the Node.js implementation of `debug()`.
|
||||
*
|
||||
* Expose `debug()` as the module.
|
||||
*/
|
||||
|
||||
exports = module.exports = require('./debug');
|
||||
exports.log = log;
|
||||
exports.formatArgs = formatArgs;
|
||||
exports.save = save;
|
||||
exports.load = load;
|
||||
exports.useColors = useColors;
|
||||
|
||||
/**
|
||||
* Colors.
|
||||
*/
|
||||
|
||||
exports.colors = [6, 2, 3, 4, 5, 1];
|
||||
|
||||
/**
|
||||
* The file descriptor to write the `debug()` calls to.
|
||||
* Set the `DEBUG_FD` env variable to override with another value. i.e.:
|
||||
*
|
||||
* $ DEBUG_FD=3 node script.js 3>debug.log
|
||||
*/
|
||||
|
||||
var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
|
||||
var stream = 1 === fd ? process.stdout :
|
||||
2 === fd ? process.stderr :
|
||||
createWritableStdioStream(fd);
|
||||
|
||||
/**
|
||||
* Is stdout a TTY? Colored output is enabled when `true`.
|
||||
*/
|
||||
|
||||
function useColors() {
|
||||
var debugColors = (process.env.DEBUG_COLORS || '').trim().toLowerCase();
|
||||
if (0 === debugColors.length) {
|
||||
return tty.isatty(fd);
|
||||
} else {
|
||||
return '0' !== debugColors
|
||||
&& 'no' !== debugColors
|
||||
&& 'false' !== debugColors
|
||||
&& 'disabled' !== debugColors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map %o to `util.inspect()`, since Node doesn't do that out of the box.
|
||||
*/
|
||||
|
||||
var inspect = (4 === util.inspect.length ?
|
||||
// node <= 0.8.x
|
||||
function (v, colors) {
|
||||
return util.inspect(v, void 0, void 0, colors);
|
||||
} :
|
||||
// node > 0.8.x
|
||||
function (v, colors) {
|
||||
return util.inspect(v, { colors: colors });
|
||||
}
|
||||
);
|
||||
|
||||
exports.formatters.o = exports.formatters.O = function(v) {
|
||||
return inspect(v, this.useColors)
|
||||
.replace(/\s*\n\s*/g, ' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds ANSI color escape codes if enabled.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function formatArgs() {
|
||||
var len = arguments.length;
|
||||
var args = new Array(len);
|
||||
var useColors = this.useColors;
|
||||
var name = this.namespace;
|
||||
for (var i = 0; i < len; i++) {
|
||||
args[i] = arguments[i];
|
||||
}
|
||||
|
||||
if (useColors) {
|
||||
var c = this.color;
|
||||
|
||||
args[0] = ' \u001b[3' + c + ';1m' + name + ' '
|
||||
+ '\u001b[0m'
|
||||
+ args[0];
|
||||
args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
|
||||
} else {
|
||||
args[0] = new Date().toUTCString()
|
||||
+ ' ' + name + ' ' + args[0];
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `console.error()` with the specified arguments.
|
||||
*/
|
||||
|
||||
function log() {
|
||||
return stream.write(util.format.apply(this, arguments) + '\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save `namespaces`.
|
||||
*
|
||||
* @param {String} namespaces
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function save(namespaces) {
|
||||
if (null == namespaces) {
|
||||
// If you set a process.env field to null or undefined, it gets cast to the
|
||||
// string 'null' or 'undefined'. Just delete instead.
|
||||
delete process.env.DEBUG;
|
||||
} else {
|
||||
process.env.DEBUG = namespaces;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load `namespaces`.
|
||||
*
|
||||
* @return {String} returns the previously persisted debug modes
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function load() {
|
||||
return process.env.DEBUG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from `node/src/node.js`.
|
||||
*
|
||||
* XXX: It's lame that node doesn't expose this API out-of-the-box. It also
|
||||
* relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
|
||||
*/
|
||||
|
||||
function createWritableStdioStream (fd) {
|
||||
var stream;
|
||||
var tty_wrap = process.binding('tty_wrap');
|
||||
|
||||
// Note stream._type is used for test-module-load-list.js
|
||||
|
||||
switch (tty_wrap.guessHandleType(fd)) {
|
||||
case 'TTY':
|
||||
stream = new tty.WriteStream(fd);
|
||||
stream._type = 'tty';
|
||||
|
||||
// Hack to have stream not keep the event loop alive.
|
||||
// See https://github.com/joyent/node/issues/1726
|
||||
if (stream._handle && stream._handle.unref) {
|
||||
stream._handle.unref();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FILE':
|
||||
var fs = require('fs');
|
||||
stream = new fs.SyncWriteStream(fd, { autoClose: false });
|
||||
stream._type = 'fs';
|
||||
break;
|
||||
|
||||
case 'PIPE':
|
||||
case 'TCP':
|
||||
var net = require('net');
|
||||
stream = new net.Socket({
|
||||
fd: fd,
|
||||
readable: false,
|
||||
writable: true
|
||||
});
|
||||
|
||||
// FIXME Should probably have an option in net.Socket to create a
|
||||
// stream from an existing fd which is writable only. But for now
|
||||
// we'll just add this hack and set the `readable` member to false.
|
||||
// Test: ./node test/fixtures/echo.js < /etc/passwd
|
||||
stream.readable = false;
|
||||
stream.read = null;
|
||||
stream._type = 'pipe';
|
||||
|
||||
// FIXME Hack to have stream not keep the event loop alive.
|
||||
// See https://github.com/joyent/node/issues/1726
|
||||
if (stream._handle && stream._handle.unref) {
|
||||
stream._handle.unref();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Probably an error on in uv_guess_handle()
|
||||
throw new Error('Implement me. Unknown stream file type!');
|
||||
}
|
||||
|
||||
// For supporting legacy API we put the FD here.
|
||||
stream.fd = fd;
|
||||
|
||||
stream._isStdio = true;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable namespaces listed in `process.env.DEBUG` initially.
|
||||
*/
|
||||
|
||||
exports.enable(load());
|
35
node_modules/engine.io-client/node_modules/debug/package.json
generated
vendored
Normal file
35
node_modules/engine.io-client/node_modules/debug/package.json
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"version": "2.3.3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/visionmedia/debug.git"
|
||||
},
|
||||
"description": "small debugging utility",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"log",
|
||||
"debugger"
|
||||
],
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
"Nathan Rajlich <nathan@tootallnate.net> (http://n8.io)",
|
||||
"Andrew Rhyne <rhyneandrew@gmail.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "0.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "9.0.3",
|
||||
"mocha": "*"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"browser": "./browser.js",
|
||||
"component": {
|
||||
"scripts": {
|
||||
"debug/index.js": "browser.js",
|
||||
"debug/debug.js": "debug.js"
|
||||
}
|
||||
}
|
||||
}
|
141
node_modules/engine.io-client/node_modules/engine.io-parser/History.md
generated
vendored
Normal file
141
node_modules/engine.io-client/node_modules/engine.io-parser/History.md
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
|
||||
1.3.2 / 2016-12-07
|
||||
==================
|
||||
|
||||
* [chore] Bump dependencies (#78)
|
||||
|
||||
1.3.1 / 2016-10-20
|
||||
==================
|
||||
|
||||
* [fix] Add safety check for global object (#71)
|
||||
* [fix] decodePacket now accepts both Buffer and ArrayBuffer as data (#64)
|
||||
* [fix] Handle undefined case properly when decoding packet (#74)
|
||||
* [chore] Bump zuul to 3.11.0 & zuul-ngrok to 4.0.0 (#70)
|
||||
* [chore] Update zuul browser settings (#73)
|
||||
|
||||
1.3.0 / 2016-09-26
|
||||
==================
|
||||
|
||||
* [fix] Fix crashes in React Native "navigator is not defined" (#55)
|
||||
* [refactor] Require base64-arraybuffer module conditionally. (#58)
|
||||
* [perf] Split try catch into separate function (#65)
|
||||
* [chore] Use wtf-8 instead of utf8 to prevent lone surrogates from generating parsing error (#68)
|
||||
* [chore] Restrict files included in npm package (#67)
|
||||
* [chore] Update license and repository url (#66)
|
||||
* [chore] Update zuul browser settings following EOL notices (#62)
|
||||
* [chore] bump zuul (#56)
|
||||
|
||||
1.2.4 / 2015-12-04
|
||||
==================
|
||||
|
||||
* fix `ArrayBuffer` encoding in base64 string
|
||||
|
||||
1.2.3 / 2015-11-28
|
||||
==================
|
||||
|
||||
* fix encoding blob as base64
|
||||
|
||||
1.2.2 / 2015-09-09
|
||||
==================
|
||||
|
||||
* fixes for iojs/node
|
||||
|
||||
1.2.1 / 2015-01-17
|
||||
==================
|
||||
|
||||
* pass has-binary result to encodePacket [rase-]
|
||||
* Fix parse error [rase-]
|
||||
|
||||
1.2.0 / 2015-01-11
|
||||
==================
|
||||
|
||||
* fix return type for decodePacket
|
||||
* README fixes
|
||||
* use travis matrix for better test runs
|
||||
* encode into binary only if needed
|
||||
* add test cases for base64 object encoding.
|
||||
* add encodeBase64Object to encoder for browser
|
||||
* avoid sending Blobs on PhantomJS (as on Android)
|
||||
* test that utf8 encoding is not on by default but can be switched on manually
|
||||
|
||||
1.1.0 / 2014-07-16
|
||||
==================
|
||||
|
||||
* make utf8 encoding/decoding optional
|
||||
|
||||
1.0.8 / 2014-07-16
|
||||
==================
|
||||
|
||||
* adjust protocol revision
|
||||
* handle invalid utf8 errors gracefully
|
||||
* fix memory leak on browser
|
||||
|
||||
1.0.7 / 2014-06-24
|
||||
==================
|
||||
|
||||
* fix decodePayloadAsBinary memory leak [christophwitzko]
|
||||
* README improvements
|
||||
|
||||
1.0.6 / 2014-05-30
|
||||
==================
|
||||
|
||||
* utf8 fixes when using binary encoding [nkzawa]
|
||||
|
||||
1.0.5 / 2014-05-06
|
||||
==================
|
||||
|
||||
* fix range error
|
||||
|
||||
1.0.4 / 2014-04-13
|
||||
==================
|
||||
|
||||
* fix `encodePayloadAsBinary` method encodes packets to base64
|
||||
|
||||
1.0.3 / 2014-04-10
|
||||
==================
|
||||
|
||||
* Fix length calculation when encoding as binary [binlain]
|
||||
|
||||
1.0.2 / 2014-03-16
|
||||
==================
|
||||
|
||||
* fix binary for android due to a bug in Blob XHR2 implementation [Rase-]
|
||||
|
||||
1.0.1 / 2014-03-06
|
||||
==================
|
||||
|
||||
* implement `blob` module to simplify code
|
||||
* bump `arraybuffer.slice`
|
||||
* style fixes
|
||||
|
||||
1.0.0 / 2014-02-18
|
||||
==================
|
||||
|
||||
* parser: added binary encoding [Rase-]
|
||||
* parser: switched to an async interface [Rase-]
|
||||
|
||||
0.3.0 / 2013-03-16
|
||||
==================
|
||||
|
||||
* parser: if callback returns `false` ignore rest of payload
|
||||
* test: fixed all broken tests
|
||||
|
||||
0.2.1 / 2013-03-16
|
||||
==================
|
||||
|
||||
* added protocol version to index.js [albertyfwu]
|
||||
|
||||
0.2.0 / 2013-02-26
|
||||
==================
|
||||
|
||||
* Changed `decodePayload` to use a callback instead of returning an array [sweetieSong, albertyfwu]
|
||||
|
||||
0.1.1 / 2013-01-26
|
||||
==================
|
||||
|
||||
* package.json fixes
|
||||
|
||||
0.1.0 / 2013-01-19
|
||||
==================
|
||||
|
||||
* Initial release
|
22
node_modules/engine.io-client/node_modules/engine.io-parser/LICENSE
generated
vendored
Normal file
22
node_modules/engine.io-client/node_modules/engine.io-parser/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2016 Guillermo Rauch (@rauchg)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
202
node_modules/engine.io-client/node_modules/engine.io-parser/Readme.md
generated
vendored
Normal file
202
node_modules/engine.io-client/node_modules/engine.io-parser/Readme.md
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
# engine.io-parser
|
||||
|
||||
[](http://travis-ci.org/socketio/engine.io-parser)
|
||||
[](http://badge.fury.io/js/engine.io-parser)
|
||||
|
||||
This is the JavaScript parser for the engine.io protocol encoding,
|
||||
shared by both
|
||||
[engine.io-client](https://github.com/socketio/engine.io-client) and
|
||||
[engine.io](https://github.com/socketio/engine.io).
|
||||
|
||||
## How to use
|
||||
|
||||
### Standalone
|
||||
|
||||
The parser can encode/decode packets, payloads, and payloads as binary
|
||||
with the following methods: `encodePacket`, `decodePacket`, `encodePayload`,
|
||||
`decodePayload`, `encodePayloadAsBinary`, `decodePayloadAsBinary`.
|
||||
|
||||
The browser-side parser also includes `encodePayloadAsArrayBuffer` and `encodePayloadAsBlob`.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var parser = require('engine.io-parser');
|
||||
|
||||
var data = new Buffer(5);
|
||||
for (var i = 0; i < data.length; i++) { data[i] = i; }
|
||||
|
||||
parser.encodePacket({ type: 'message', data: data }, function(encoded) {
|
||||
var decodedData = parser.decodePacket(encoded); // { type: 'message', data: data }
|
||||
});
|
||||
```
|
||||
|
||||
### With browserify
|
||||
|
||||
Engine.IO Parser is a commonjs module, which means you can include it by using
|
||||
`require` on the browser and package using [browserify](http://browserify.org/):
|
||||
|
||||
1. install the parser package
|
||||
|
||||
```shell
|
||||
npm install engine.io-parser
|
||||
```
|
||||
|
||||
1. write your app code
|
||||
|
||||
```js
|
||||
var parser = require('engine.io-parser');
|
||||
|
||||
var testBuffer = new Int8Array(10);
|
||||
for (var i = 0; i < testBuffer.length; i++) testBuffer[i] = i;
|
||||
|
||||
var packets = [{ type: 'message', data: testBuffer.buffer }, { type: 'message', data: 'hello' }];
|
||||
|
||||
parser.encodePayload(packets, function(encoded) {
|
||||
parser.decodePayload(encoded,
|
||||
function(packet, index, total) {
|
||||
var isLast = index + 1 == total;
|
||||
if (!isLast) {
|
||||
var buffer = new Int8Array(packet.data); // testBuffer
|
||||
} else {
|
||||
var message = packet.data; // 'hello'
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
1. build your app bundle
|
||||
|
||||
```bash
|
||||
$ browserify app.js > bundle.js
|
||||
```
|
||||
|
||||
1. include on your page
|
||||
|
||||
```html
|
||||
<script src="/path/to/bundle.js"></script>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Runs on browser and node.js seamlessly
|
||||
- Runs inside HTML5 WebWorker
|
||||
- Can encode and decode packets
|
||||
- Encodes from/to ArrayBuffer or Blob when in browser, and Buffer or ArrayBuffer in Node
|
||||
|
||||
## API
|
||||
|
||||
Note: `cb(type)` means the type is a callback function that contains a parameter of type `type` when called.
|
||||
|
||||
### Node
|
||||
|
||||
- `encodePacket`
|
||||
- Encodes a packet.
|
||||
- **Parameters**
|
||||
- `Object`: the packet to encode, has `type` and `data`.
|
||||
- `data`: can be a `String`, `Number`, `Buffer`, `ArrayBuffer`
|
||||
- `Boolean`: optional, binary support
|
||||
- `Function`: callback, returns the encoded packet (`cb(String)`)
|
||||
- `decodePacket`
|
||||
- Decodes a packet. Data also available as an ArrayBuffer if requested.
|
||||
- Returns data as `String` or (`Blob` on browser, `ArrayBuffer` on Node)
|
||||
- **Parameters**
|
||||
- `String` | `ArrayBuffer`: the packet to decode, has `type` and `data`
|
||||
- `String`: optional, the binary type
|
||||
|
||||
- `encodeBase64Packet`
|
||||
- Encodes a packet with binary data in a base64 string (`String`)
|
||||
- **Parameters**
|
||||
- `Object`: the packet to encode, has `type` and `data`
|
||||
- `Function`: callback, returns the base64 encoded message (`cb(String)`)
|
||||
- `decodeBase64Packet`
|
||||
- Decodes a packet encoded in a base64 string.
|
||||
- **Parameters**
|
||||
- `String`: the base64 encoded message
|
||||
- `String`: optional, the binary type
|
||||
|
||||
- `encodePayload`
|
||||
- Encodes multiple messages (payload).
|
||||
- If any contents are binary, they will be encoded as base64 strings. Base64
|
||||
encoded strings are marked with a b before the length specifier
|
||||
- **Parameters**
|
||||
- `Array`: an array of packets
|
||||
- `Boolean`: optional, binary support
|
||||
- `Function`: callback, returns the encoded payload (`cb(String)`)
|
||||
- `decodePayload`
|
||||
- Decodes data when a payload is maybe expected. Possible binary contents are
|
||||
decoded from their base64 representation.
|
||||
- **Parameters**
|
||||
- `String`: the payload
|
||||
- `String`: optional, the binary type
|
||||
- `Function`: callback, returns (cb(`Object`: packet, `Number`:packet index, `Number`:packet total))
|
||||
|
||||
- `encodePayloadAsBinary`
|
||||
- Encodes multiple messages (payload) as binary.
|
||||
- **Parameters**
|
||||
- `Array`: an array of packets
|
||||
- `Function`: callback, returns the encoded payload (`cb(Buffer)`)
|
||||
- `decodePayloadAsBinary`
|
||||
- Decodes data when a payload is maybe expected. Strings are decoded by
|
||||
interpreting each byte as a key code for entries marked to start with 0. See
|
||||
description of encodePayloadAsBinary.
|
||||
- **Parameters**
|
||||
- `Buffer`: the buffer
|
||||
- `String`: optional, the binary type
|
||||
- `Function`: callback, returns the decoded packet (`cb(Object)`)
|
||||
|
||||
### Browser
|
||||
|
||||
- `encodePayloadAsArrayBuffer`
|
||||
- Encodes multiple messages (payload) as binary.
|
||||
- **Parameters**
|
||||
- `Array`: an array of packets
|
||||
- `Function`: callback, returns the encoded payload (`cb(ArrayBuffer)`)
|
||||
- `encodePayloadAsBlob`
|
||||
- Encodes multiple messages (payload) as blob.
|
||||
- **Parameters**
|
||||
- `Array`: an array of packets
|
||||
- `Function`: callback, returns the encoded payload (`cb(Blob)`)
|
||||
|
||||
## Tests
|
||||
|
||||
Standalone tests can be run with `make test` which will run both node.js and browser tests.
|
||||
|
||||
Browser tests are run using [zuul](https://github.com/defunctzombie/zuul).
|
||||
(You must have zuul setup with a saucelabs account.)
|
||||
|
||||
You can run the tests locally using the following command:
|
||||
|
||||
```
|
||||
./node_modules/.bin/zuul --local 8080 -- test/index.js
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
The support channels for `engine.io-parser` are the same as `socket.io`:
|
||||
- irc.freenode.net **#socket.io**
|
||||
- [Google Groups](http://groups.google.com/group/socket_io)
|
||||
- [Website](http://socket.io)
|
||||
|
||||
## Development
|
||||
|
||||
To contribute patches, run tests or benchmarks, make sure to clone the
|
||||
repository:
|
||||
|
||||
```bash
|
||||
git clone git://github.com/LearnBoost/engine.io-parser.git
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
cd engine.io-parser
|
||||
npm install
|
||||
```
|
||||
|
||||
See the `Tests` section above for how to run tests before submitting any patches.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
2
node_modules/engine.io-client/node_modules/engine.io-parser/index.js
generated
vendored
Normal file
2
node_modules/engine.io-client/node_modules/engine.io-parser/index.js
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
module.exports = require('./lib/');
|
609
node_modules/engine.io-client/node_modules/engine.io-parser/lib/browser.js
generated
vendored
Normal file
609
node_modules/engine.io-client/node_modules/engine.io-parser/lib/browser.js
generated
vendored
Normal file
@ -0,0 +1,609 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var keys = require('./keys');
|
||||
var hasBinary = require('has-binary');
|
||||
var sliceBuffer = require('arraybuffer.slice');
|
||||
var after = require('after');
|
||||
var utf8 = require('wtf-8');
|
||||
|
||||
var base64encoder;
|
||||
if (global && global.ArrayBuffer) {
|
||||
base64encoder = require('base64-arraybuffer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are running an android browser. That requires us to use
|
||||
* ArrayBuffer with polling transports...
|
||||
*
|
||||
* http://ghinda.net/jpeg-blob-ajax-android/
|
||||
*/
|
||||
|
||||
var isAndroid = typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent);
|
||||
|
||||
/**
|
||||
* Check if we are running in PhantomJS.
|
||||
* Uploading a Blob with PhantomJS does not work correctly, as reported here:
|
||||
* https://github.com/ariya/phantomjs/issues/11395
|
||||
* @type boolean
|
||||
*/
|
||||
var isPhantomJS = typeof navigator !== 'undefined' && /PhantomJS/i.test(navigator.userAgent);
|
||||
|
||||
/**
|
||||
* When true, avoids using Blobs to encode payloads.
|
||||
* @type boolean
|
||||
*/
|
||||
var dontSendBlobs = isAndroid || isPhantomJS;
|
||||
|
||||
/**
|
||||
* Current protocol version.
|
||||
*/
|
||||
|
||||
exports.protocol = 3;
|
||||
|
||||
/**
|
||||
* Packet types.
|
||||
*/
|
||||
|
||||
var packets = exports.packets = {
|
||||
open: 0 // non-ws
|
||||
, close: 1 // non-ws
|
||||
, ping: 2
|
||||
, pong: 3
|
||||
, message: 4
|
||||
, upgrade: 5
|
||||
, noop: 6
|
||||
};
|
||||
|
||||
var packetslist = keys(packets);
|
||||
|
||||
/**
|
||||
* Premade error packet.
|
||||
*/
|
||||
|
||||
var err = { type: 'error', data: 'parser error' };
|
||||
|
||||
/**
|
||||
* Create a blob api even for blob builder when vendor prefixes exist
|
||||
*/
|
||||
|
||||
var Blob = require('blob');
|
||||
|
||||
/**
|
||||
* Encodes a packet.
|
||||
*
|
||||
* <packet type id> [ <data> ]
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 5hello world
|
||||
* 3
|
||||
* 4
|
||||
*
|
||||
* Binary is encoded in an identical principle
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
|
||||
if ('function' == typeof supportsBinary) {
|
||||
callback = supportsBinary;
|
||||
supportsBinary = false;
|
||||
}
|
||||
|
||||
if ('function' == typeof utf8encode) {
|
||||
callback = utf8encode;
|
||||
utf8encode = null;
|
||||
}
|
||||
|
||||
var data = (packet.data === undefined)
|
||||
? undefined
|
||||
: packet.data.buffer || packet.data;
|
||||
|
||||
if (global.ArrayBuffer && data instanceof ArrayBuffer) {
|
||||
return encodeArrayBuffer(packet, supportsBinary, callback);
|
||||
} else if (Blob && data instanceof global.Blob) {
|
||||
return encodeBlob(packet, supportsBinary, callback);
|
||||
}
|
||||
|
||||
// might be an object with { base64: true, data: dataAsBase64String }
|
||||
if (data && data.base64) {
|
||||
return encodeBase64Object(packet, callback);
|
||||
}
|
||||
|
||||
// Sending data as a utf-8 string
|
||||
var encoded = packets[packet.type];
|
||||
|
||||
// data fragment is optional
|
||||
if (undefined !== packet.data) {
|
||||
encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
|
||||
}
|
||||
|
||||
return callback('' + encoded);
|
||||
|
||||
};
|
||||
|
||||
function encodeBase64Object(packet, callback) {
|
||||
// packet data is an object { base64: true, data: dataAsBase64String }
|
||||
var message = 'b' + exports.packets[packet.type] + packet.data.data;
|
||||
return callback(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packet helpers for binary types
|
||||
*/
|
||||
|
||||
function encodeArrayBuffer(packet, supportsBinary, callback) {
|
||||
if (!supportsBinary) {
|
||||
return exports.encodeBase64Packet(packet, callback);
|
||||
}
|
||||
|
||||
var data = packet.data;
|
||||
var contentArray = new Uint8Array(data);
|
||||
var resultBuffer = new Uint8Array(1 + data.byteLength);
|
||||
|
||||
resultBuffer[0] = packets[packet.type];
|
||||
for (var i = 0; i < contentArray.length; i++) {
|
||||
resultBuffer[i+1] = contentArray[i];
|
||||
}
|
||||
|
||||
return callback(resultBuffer.buffer);
|
||||
}
|
||||
|
||||
function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
|
||||
if (!supportsBinary) {
|
||||
return exports.encodeBase64Packet(packet, callback);
|
||||
}
|
||||
|
||||
var fr = new FileReader();
|
||||
fr.onload = function() {
|
||||
packet.data = fr.result;
|
||||
exports.encodePacket(packet, supportsBinary, true, callback);
|
||||
};
|
||||
return fr.readAsArrayBuffer(packet.data);
|
||||
}
|
||||
|
||||
function encodeBlob(packet, supportsBinary, callback) {
|
||||
if (!supportsBinary) {
|
||||
return exports.encodeBase64Packet(packet, callback);
|
||||
}
|
||||
|
||||
if (dontSendBlobs) {
|
||||
return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
|
||||
}
|
||||
|
||||
var length = new Uint8Array(1);
|
||||
length[0] = packets[packet.type];
|
||||
var blob = new Blob([length.buffer, packet.data]);
|
||||
|
||||
return callback(blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a packet with binary data in a base64 string
|
||||
*
|
||||
* @param {Object} packet, has `type` and `data`
|
||||
* @return {String} base64 encoded message
|
||||
*/
|
||||
|
||||
exports.encodeBase64Packet = function(packet, callback) {
|
||||
var message = 'b' + exports.packets[packet.type];
|
||||
if (Blob && packet.data instanceof global.Blob) {
|
||||
var fr = new FileReader();
|
||||
fr.onload = function() {
|
||||
var b64 = fr.result.split(',')[1];
|
||||
callback(message + b64);
|
||||
};
|
||||
return fr.readAsDataURL(packet.data);
|
||||
}
|
||||
|
||||
var b64data;
|
||||
try {
|
||||
b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
|
||||
} catch (e) {
|
||||
// iPhone Safari doesn't let you apply with typed arrays
|
||||
var typed = new Uint8Array(packet.data);
|
||||
var basic = new Array(typed.length);
|
||||
for (var i = 0; i < typed.length; i++) {
|
||||
basic[i] = typed[i];
|
||||
}
|
||||
b64data = String.fromCharCode.apply(null, basic);
|
||||
}
|
||||
message += global.btoa(b64data);
|
||||
return callback(message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a packet. Changes format to Blob if requested.
|
||||
*
|
||||
* @return {Object} with `type` and `data` (if any)
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.decodePacket = function (data, binaryType, utf8decode) {
|
||||
if (data === undefined) {
|
||||
return err;
|
||||
}
|
||||
// String data
|
||||
if (typeof data == 'string') {
|
||||
if (data.charAt(0) == 'b') {
|
||||
return exports.decodeBase64Packet(data.substr(1), binaryType);
|
||||
}
|
||||
|
||||
if (utf8decode) {
|
||||
data = tryDecode(data);
|
||||
if (data === false) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
var type = data.charAt(0);
|
||||
|
||||
if (Number(type) != type || !packetslist[type]) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data.length > 1) {
|
||||
return { type: packetslist[type], data: data.substring(1) };
|
||||
} else {
|
||||
return { type: packetslist[type] };
|
||||
}
|
||||
}
|
||||
|
||||
var asArray = new Uint8Array(data);
|
||||
var type = asArray[0];
|
||||
var rest = sliceBuffer(data, 1);
|
||||
if (Blob && binaryType === 'blob') {
|
||||
rest = new Blob([rest]);
|
||||
}
|
||||
return { type: packetslist[type], data: rest };
|
||||
};
|
||||
|
||||
function tryDecode(data) {
|
||||
try {
|
||||
data = utf8.decode(data);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a packet encoded in a base64 string
|
||||
*
|
||||
* @param {String} base64 encoded message
|
||||
* @return {Object} with `type` and `data` (if any)
|
||||
*/
|
||||
|
||||
exports.decodeBase64Packet = function(msg, binaryType) {
|
||||
var type = packetslist[msg.charAt(0)];
|
||||
if (!base64encoder) {
|
||||
return { type: type, data: { base64: true, data: msg.substr(1) } };
|
||||
}
|
||||
|
||||
var data = base64encoder.decode(msg.substr(1));
|
||||
|
||||
if (binaryType === 'blob' && Blob) {
|
||||
data = new Blob([data]);
|
||||
}
|
||||
|
||||
return { type: type, data: data };
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes multiple messages (payload).
|
||||
*
|
||||
* <length>:data
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 11:hello world2:hi
|
||||
*
|
||||
* If any contents are binary, they will be encoded as base64 strings. Base64
|
||||
* encoded strings are marked with a b before the length specifier
|
||||
*
|
||||
* @param {Array} packets
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePayload = function (packets, supportsBinary, callback) {
|
||||
if (typeof supportsBinary == 'function') {
|
||||
callback = supportsBinary;
|
||||
supportsBinary = null;
|
||||
}
|
||||
|
||||
var isBinary = hasBinary(packets);
|
||||
|
||||
if (supportsBinary && isBinary) {
|
||||
if (Blob && !dontSendBlobs) {
|
||||
return exports.encodePayloadAsBlob(packets, callback);
|
||||
}
|
||||
|
||||
return exports.encodePayloadAsArrayBuffer(packets, callback);
|
||||
}
|
||||
|
||||
if (!packets.length) {
|
||||
return callback('0:');
|
||||
}
|
||||
|
||||
function setLengthHeader(message) {
|
||||
return message.length + ':' + message;
|
||||
}
|
||||
|
||||
function encodeOne(packet, doneCallback) {
|
||||
exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function(message) {
|
||||
doneCallback(null, setLengthHeader(message));
|
||||
});
|
||||
}
|
||||
|
||||
map(packets, encodeOne, function(err, results) {
|
||||
return callback(results.join(''));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Async array map using after
|
||||
*/
|
||||
|
||||
function map(ary, each, done) {
|
||||
var result = new Array(ary.length);
|
||||
var next = after(ary.length, done);
|
||||
|
||||
var eachWithIndex = function(i, el, cb) {
|
||||
each(el, function(error, msg) {
|
||||
result[i] = msg;
|
||||
cb(error, result);
|
||||
});
|
||||
};
|
||||
|
||||
for (var i = 0; i < ary.length; i++) {
|
||||
eachWithIndex(i, ary[i], next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes data when a payload is maybe expected. Possible binary contents are
|
||||
* decoded from their base64 representation
|
||||
*
|
||||
* @param {String} data, callback method
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decodePayload = function (data, binaryType, callback) {
|
||||
if (typeof data != 'string') {
|
||||
return exports.decodePayloadAsBinary(data, binaryType, callback);
|
||||
}
|
||||
|
||||
if (typeof binaryType === 'function') {
|
||||
callback = binaryType;
|
||||
binaryType = null;
|
||||
}
|
||||
|
||||
var packet;
|
||||
if (data == '') {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
var length = ''
|
||||
, n, msg;
|
||||
|
||||
for (var i = 0, l = data.length; i < l; i++) {
|
||||
var chr = data.charAt(i);
|
||||
|
||||
if (':' != chr) {
|
||||
length += chr;
|
||||
} else {
|
||||
if ('' == length || (length != (n = Number(length)))) {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
msg = data.substr(i + 1, n);
|
||||
|
||||
if (length != msg.length) {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
if (msg.length) {
|
||||
packet = exports.decodePacket(msg, binaryType, true);
|
||||
|
||||
if (err.type == packet.type && err.data == packet.data) {
|
||||
// parser error in individual packet - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
var ret = callback(packet, i + n, l);
|
||||
if (false === ret) return;
|
||||
}
|
||||
|
||||
// advance cursor
|
||||
i += n;
|
||||
length = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (length != '') {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes multiple messages (payload) as binary.
|
||||
*
|
||||
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
|
||||
* 255><data>
|
||||
*
|
||||
* Example:
|
||||
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
|
||||
*
|
||||
* @param {Array} packets
|
||||
* @return {ArrayBuffer} encoded payload
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePayloadAsArrayBuffer = function(packets, callback) {
|
||||
if (!packets.length) {
|
||||
return callback(new ArrayBuffer(0));
|
||||
}
|
||||
|
||||
function encodeOne(packet, doneCallback) {
|
||||
exports.encodePacket(packet, true, true, function(data) {
|
||||
return doneCallback(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
map(packets, encodeOne, function(err, encodedPackets) {
|
||||
var totalLength = encodedPackets.reduce(function(acc, p) {
|
||||
var len;
|
||||
if (typeof p === 'string'){
|
||||
len = p.length;
|
||||
} else {
|
||||
len = p.byteLength;
|
||||
}
|
||||
return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
|
||||
}, 0);
|
||||
|
||||
var resultArray = new Uint8Array(totalLength);
|
||||
|
||||
var bufferIndex = 0;
|
||||
encodedPackets.forEach(function(p) {
|
||||
var isString = typeof p === 'string';
|
||||
var ab = p;
|
||||
if (isString) {
|
||||
var view = new Uint8Array(p.length);
|
||||
for (var i = 0; i < p.length; i++) {
|
||||
view[i] = p.charCodeAt(i);
|
||||
}
|
||||
ab = view.buffer;
|
||||
}
|
||||
|
||||
if (isString) { // not true binary
|
||||
resultArray[bufferIndex++] = 0;
|
||||
} else { // true binary
|
||||
resultArray[bufferIndex++] = 1;
|
||||
}
|
||||
|
||||
var lenStr = ab.byteLength.toString();
|
||||
for (var i = 0; i < lenStr.length; i++) {
|
||||
resultArray[bufferIndex++] = parseInt(lenStr[i]);
|
||||
}
|
||||
resultArray[bufferIndex++] = 255;
|
||||
|
||||
var view = new Uint8Array(ab);
|
||||
for (var i = 0; i < view.length; i++) {
|
||||
resultArray[bufferIndex++] = view[i];
|
||||
}
|
||||
});
|
||||
|
||||
return callback(resultArray.buffer);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode as Blob
|
||||
*/
|
||||
|
||||
exports.encodePayloadAsBlob = function(packets, callback) {
|
||||
function encodeOne(packet, doneCallback) {
|
||||
exports.encodePacket(packet, true, true, function(encoded) {
|
||||
var binaryIdentifier = new Uint8Array(1);
|
||||
binaryIdentifier[0] = 1;
|
||||
if (typeof encoded === 'string') {
|
||||
var view = new Uint8Array(encoded.length);
|
||||
for (var i = 0; i < encoded.length; i++) {
|
||||
view[i] = encoded.charCodeAt(i);
|
||||
}
|
||||
encoded = view.buffer;
|
||||
binaryIdentifier[0] = 0;
|
||||
}
|
||||
|
||||
var len = (encoded instanceof ArrayBuffer)
|
||||
? encoded.byteLength
|
||||
: encoded.size;
|
||||
|
||||
var lenStr = len.toString();
|
||||
var lengthAry = new Uint8Array(lenStr.length + 1);
|
||||
for (var i = 0; i < lenStr.length; i++) {
|
||||
lengthAry[i] = parseInt(lenStr[i]);
|
||||
}
|
||||
lengthAry[lenStr.length] = 255;
|
||||
|
||||
if (Blob) {
|
||||
var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
|
||||
doneCallback(null, blob);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map(packets, encodeOne, function(err, results) {
|
||||
return callback(new Blob(results));
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Decodes data when a payload is maybe expected. Strings are decoded by
|
||||
* interpreting each byte as a key code for entries marked to start with 0. See
|
||||
* description of encodePayloadAsBinary
|
||||
*
|
||||
* @param {ArrayBuffer} data, callback method
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decodePayloadAsBinary = function (data, binaryType, callback) {
|
||||
if (typeof binaryType === 'function') {
|
||||
callback = binaryType;
|
||||
binaryType = null;
|
||||
}
|
||||
|
||||
var bufferTail = data;
|
||||
var buffers = [];
|
||||
|
||||
var numberTooLong = false;
|
||||
while (bufferTail.byteLength > 0) {
|
||||
var tailArray = new Uint8Array(bufferTail);
|
||||
var isString = tailArray[0] === 0;
|
||||
var msgLength = '';
|
||||
|
||||
for (var i = 1; ; i++) {
|
||||
if (tailArray[i] == 255) break;
|
||||
|
||||
if (msgLength.length > 310) {
|
||||
numberTooLong = true;
|
||||
break;
|
||||
}
|
||||
|
||||
msgLength += tailArray[i];
|
||||
}
|
||||
|
||||
if(numberTooLong) return callback(err, 0, 1);
|
||||
|
||||
bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
|
||||
msgLength = parseInt(msgLength);
|
||||
|
||||
var msg = sliceBuffer(bufferTail, 0, msgLength);
|
||||
if (isString) {
|
||||
try {
|
||||
msg = String.fromCharCode.apply(null, new Uint8Array(msg));
|
||||
} catch (e) {
|
||||
// iPhone Safari doesn't let you apply to typed arrays
|
||||
var typed = new Uint8Array(msg);
|
||||
msg = '';
|
||||
for (var i = 0; i < typed.length; i++) {
|
||||
msg += String.fromCharCode(typed[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffers.push(msg);
|
||||
bufferTail = sliceBuffer(bufferTail, msgLength);
|
||||
}
|
||||
|
||||
var total = buffers.length;
|
||||
buffers.forEach(function(buffer, i) {
|
||||
callback(exports.decodePacket(buffer, binaryType, true), i, total);
|
||||
});
|
||||
};
|
474
node_modules/engine.io-client/node_modules/engine.io-parser/lib/index.js
generated
vendored
Normal file
474
node_modules/engine.io-client/node_modules/engine.io-parser/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utf8 = require('wtf-8');
|
||||
var after = require('after');
|
||||
var keys = require('./keys');
|
||||
|
||||
/**
|
||||
* Current protocol version.
|
||||
*/
|
||||
exports.protocol = 3;
|
||||
|
||||
/**
|
||||
* Packet types.
|
||||
*/
|
||||
|
||||
var packets = exports.packets = {
|
||||
open: 0 // non-ws
|
||||
, close: 1 // non-ws
|
||||
, ping: 2
|
||||
, pong: 3
|
||||
, message: 4
|
||||
, upgrade: 5
|
||||
, noop: 6
|
||||
};
|
||||
|
||||
var packetslist = keys(packets);
|
||||
|
||||
/**
|
||||
* Premade error packet.
|
||||
*/
|
||||
|
||||
var err = { type: 'error', data: 'parser error' };
|
||||
|
||||
/**
|
||||
* Encodes a packet.
|
||||
*
|
||||
* <packet type id> [ <data> ]
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 5hello world
|
||||
* 3
|
||||
* 4
|
||||
*
|
||||
* Binary is encoded in an identical principle
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
|
||||
if ('function' == typeof supportsBinary) {
|
||||
callback = supportsBinary;
|
||||
supportsBinary = null;
|
||||
}
|
||||
|
||||
if ('function' == typeof utf8encode ) {
|
||||
callback = utf8encode;
|
||||
utf8encode = null;
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(packet.data)) {
|
||||
return encodeBuffer(packet, supportsBinary, callback);
|
||||
} else if (packet.data && (packet.data.buffer || packet.data) instanceof ArrayBuffer) {
|
||||
packet.data = arrayBufferToBuffer(packet.data);
|
||||
return encodeBuffer(packet, supportsBinary, callback);
|
||||
}
|
||||
|
||||
// Sending data as a utf-8 string
|
||||
var encoded = packets[packet.type];
|
||||
|
||||
// data fragment is optional
|
||||
if (undefined !== packet.data) {
|
||||
encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
|
||||
}
|
||||
|
||||
return callback('' + encoded);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode Buffer data
|
||||
*/
|
||||
|
||||
function encodeBuffer(packet, supportsBinary, callback) {
|
||||
var data = packet.data;
|
||||
if (!supportsBinary) {
|
||||
return exports.encodeBase64Packet(packet, callback);
|
||||
}
|
||||
|
||||
var typeBuffer = new Buffer(1);
|
||||
typeBuffer[0] = packets[packet.type];
|
||||
return callback(Buffer.concat([typeBuffer, data]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a packet with binary data in a base64 string
|
||||
*
|
||||
* @param {Object} packet, has `type` and `data`
|
||||
* @return {String} base64 encoded message
|
||||
*/
|
||||
|
||||
exports.encodeBase64Packet = function(packet, callback){
|
||||
if (!Buffer.isBuffer(packet.data)) {
|
||||
packet.data = arrayBufferToBuffer(packet.data);
|
||||
}
|
||||
|
||||
var message = 'b' + packets[packet.type];
|
||||
message += packet.data.toString('base64');
|
||||
return callback(message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a packet. Data also available as an ArrayBuffer if requested.
|
||||
*
|
||||
* @return {Object} with `type` and `data` (if any)
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.decodePacket = function (data, binaryType, utf8decode) {
|
||||
if (data === undefined) {
|
||||
return err;
|
||||
}
|
||||
// String data
|
||||
if (typeof data == 'string') {
|
||||
if (data.charAt(0) == 'b') {
|
||||
return exports.decodeBase64Packet(data.substr(1), binaryType);
|
||||
}
|
||||
|
||||
var type = data.charAt(0);
|
||||
|
||||
if (utf8decode) {
|
||||
data = tryDecode(data);
|
||||
if (data === false) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (Number(type) != type || !packetslist[type]) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data.length > 1) {
|
||||
return { type: packetslist[type], data: data.substring(1) };
|
||||
} else {
|
||||
return { type: packetslist[type] };
|
||||
}
|
||||
}
|
||||
|
||||
// Binary data
|
||||
if (binaryType === 'arraybuffer') {
|
||||
// wrap Buffer/ArrayBuffer data into an Uint8Array
|
||||
var intArray = new Uint8Array(data);
|
||||
var type = intArray[0];
|
||||
return { type: packetslist[type], data: intArray.buffer.slice(1) };
|
||||
}
|
||||
|
||||
if (data instanceof ArrayBuffer) {
|
||||
data = arrayBufferToBuffer(data);
|
||||
}
|
||||
var type = data[0];
|
||||
return { type: packetslist[type], data: data.slice(1) };
|
||||
};
|
||||
|
||||
function tryDecode(data) {
|
||||
try {
|
||||
data = utf8.decode(data);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a packet encoded in a base64 string.
|
||||
*
|
||||
* @param {String} base64 encoded message
|
||||
* @return {Object} with `type` and `data` (if any)
|
||||
*/
|
||||
|
||||
exports.decodeBase64Packet = function(msg, binaryType) {
|
||||
var type = packetslist[msg.charAt(0)];
|
||||
var data = new Buffer(msg.substr(1), 'base64');
|
||||
if (binaryType === 'arraybuffer') {
|
||||
var abv = new Uint8Array(data.length);
|
||||
for (var i = 0; i < abv.length; i++){
|
||||
abv[i] = data[i];
|
||||
}
|
||||
data = abv.buffer;
|
||||
}
|
||||
return { type: type, data: data };
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes multiple messages (payload).
|
||||
*
|
||||
* <length>:data
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* 11:hello world2:hi
|
||||
*
|
||||
* If any contents are binary, they will be encoded as base64 strings. Base64
|
||||
* encoded strings are marked with a b before the length specifier
|
||||
*
|
||||
* @param {Array} packets
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePayload = function (packets, supportsBinary, callback) {
|
||||
if (typeof supportsBinary == 'function') {
|
||||
callback = supportsBinary;
|
||||
supportsBinary = null;
|
||||
}
|
||||
|
||||
if (supportsBinary) {
|
||||
return exports.encodePayloadAsBinary(packets, callback);
|
||||
}
|
||||
|
||||
if (!packets.length) {
|
||||
return callback('0:');
|
||||
}
|
||||
|
||||
function setLengthHeader(message) {
|
||||
return message.length + ':' + message;
|
||||
}
|
||||
|
||||
function encodeOne(packet, doneCallback) {
|
||||
exports.encodePacket(packet, supportsBinary, true, function(message) {
|
||||
doneCallback(null, setLengthHeader(message));
|
||||
});
|
||||
}
|
||||
|
||||
map(packets, encodeOne, function(err, results) {
|
||||
return callback(results.join(''));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Async array map using after
|
||||
*/
|
||||
|
||||
function map(ary, each, done) {
|
||||
var result = new Array(ary.length);
|
||||
var next = after(ary.length, done);
|
||||
|
||||
var eachWithIndex = function(i, el, cb) {
|
||||
each(el, function(error, msg) {
|
||||
result[i] = msg;
|
||||
cb(error, result);
|
||||
});
|
||||
};
|
||||
|
||||
for (var i = 0; i < ary.length; i++) {
|
||||
eachWithIndex(i, ary[i], next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes data when a payload is maybe expected. Possible binary contents are
|
||||
* decoded from their base64 representation
|
||||
*
|
||||
* @param {String} data, callback method
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decodePayload = function (data, binaryType, callback) {
|
||||
if ('string' != typeof data) {
|
||||
return exports.decodePayloadAsBinary(data, binaryType, callback);
|
||||
}
|
||||
|
||||
if (typeof binaryType === 'function') {
|
||||
callback = binaryType;
|
||||
binaryType = null;
|
||||
}
|
||||
|
||||
var packet;
|
||||
if (data == '') {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
var length = ''
|
||||
, n, msg;
|
||||
|
||||
for (var i = 0, l = data.length; i < l; i++) {
|
||||
var chr = data.charAt(i);
|
||||
|
||||
if (':' != chr) {
|
||||
length += chr;
|
||||
} else {
|
||||
if ('' == length || (length != (n = Number(length)))) {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
msg = data.substr(i + 1, n);
|
||||
|
||||
if (length != msg.length) {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
if (msg.length) {
|
||||
packet = exports.decodePacket(msg, binaryType, true);
|
||||
|
||||
if (err.type == packet.type && err.data == packet.data) {
|
||||
// parser error in individual packet - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
var ret = callback(packet, i + n, l);
|
||||
if (false === ret) return;
|
||||
}
|
||||
|
||||
// advance cursor
|
||||
i += n;
|
||||
length = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (length != '') {
|
||||
// parser error - ignoring payload
|
||||
return callback(err, 0, 1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Converts a buffer to a utf8.js encoded string
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function bufferToString(buffer) {
|
||||
var str = '';
|
||||
for (var i = 0; i < buffer.length; i++) {
|
||||
str += String.fromCharCode(buffer[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Converts a utf8.js encoded string to a buffer
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function stringToBuffer(string) {
|
||||
var buf = new Buffer(string.length);
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
buf.writeUInt8(string.charCodeAt(i), i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Converts an ArrayBuffer to a Buffer
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function arrayBufferToBuffer(data) {
|
||||
// data is either an ArrayBuffer or ArrayBufferView.
|
||||
var array = new Uint8Array(data.buffer || data);
|
||||
var length = data.byteLength || data.length;
|
||||
var offset = data.byteOffset || 0;
|
||||
var buffer = new Buffer(length);
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
buffer[i] = array[offset + i];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes multiple messages (payload) as binary.
|
||||
*
|
||||
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
|
||||
* 255><data>
|
||||
*
|
||||
* Example:
|
||||
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
|
||||
*
|
||||
* @param {Array} packets
|
||||
* @return {Buffer} encoded payload
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePayloadAsBinary = function (packets, callback) {
|
||||
if (!packets.length) {
|
||||
return callback(new Buffer(0));
|
||||
}
|
||||
|
||||
function encodeOne(p, doneCallback) {
|
||||
exports.encodePacket(p, true, true, function(packet) {
|
||||
|
||||
if (typeof packet === 'string') {
|
||||
var encodingLength = '' + packet.length;
|
||||
var sizeBuffer = new Buffer(encodingLength.length + 2);
|
||||
sizeBuffer[0] = 0; // is a string (not true binary = 0)
|
||||
for (var i = 0; i < encodingLength.length; i++) {
|
||||
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
|
||||
}
|
||||
sizeBuffer[sizeBuffer.length - 1] = 255;
|
||||
return doneCallback(null, Buffer.concat([sizeBuffer, stringToBuffer(packet)]));
|
||||
}
|
||||
|
||||
var encodingLength = '' + packet.length;
|
||||
var sizeBuffer = new Buffer(encodingLength.length + 2);
|
||||
sizeBuffer[0] = 1; // is binary (true binary = 1)
|
||||
for (var i = 0; i < encodingLength.length; i++) {
|
||||
sizeBuffer[i + 1] = parseInt(encodingLength[i], 10);
|
||||
}
|
||||
sizeBuffer[sizeBuffer.length - 1] = 255;
|
||||
doneCallback(null, Buffer.concat([sizeBuffer, packet]));
|
||||
});
|
||||
}
|
||||
|
||||
map(packets, encodeOne, function(err, results) {
|
||||
return callback(Buffer.concat(results));
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Decodes data when a payload is maybe expected. Strings are decoded by
|
||||
* interpreting each byte as a key code for entries marked to start with 0. See
|
||||
* description of encodePayloadAsBinary
|
||||
|
||||
* @param {Buffer} data, callback method
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decodePayloadAsBinary = function (data, binaryType, callback) {
|
||||
if (typeof binaryType === 'function') {
|
||||
callback = binaryType;
|
||||
binaryType = null;
|
||||
}
|
||||
|
||||
var bufferTail = data;
|
||||
var buffers = [];
|
||||
|
||||
while (bufferTail.length > 0) {
|
||||
var strLen = '';
|
||||
var isString = bufferTail[0] === 0;
|
||||
var numberTooLong = false;
|
||||
for (var i = 1; ; i++) {
|
||||
if (bufferTail[i] == 255) break;
|
||||
// 310 = char length of Number.MAX_VALUE
|
||||
if (strLen.length > 310) {
|
||||
numberTooLong = true;
|
||||
break;
|
||||
}
|
||||
strLen += '' + bufferTail[i];
|
||||
}
|
||||
if(numberTooLong) return callback(err, 0, 1);
|
||||
bufferTail = bufferTail.slice(strLen.length + 1);
|
||||
|
||||
var msgLength = parseInt(strLen, 10);
|
||||
|
||||
var msg = bufferTail.slice(1, msgLength + 1);
|
||||
if (isString) msg = bufferToString(msg);
|
||||
buffers.push(msg);
|
||||
bufferTail = bufferTail.slice(msgLength + 1);
|
||||
}
|
||||
|
||||
var total = buffers.length;
|
||||
buffers.forEach(function(buffer, i) {
|
||||
callback(exports.decodePacket(buffer, binaryType, true), i, total);
|
||||
});
|
||||
};
|
19
node_modules/engine.io-client/node_modules/engine.io-parser/lib/keys.js
generated
vendored
Normal file
19
node_modules/engine.io-client/node_modules/engine.io-parser/lib/keys.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
/**
|
||||
* Gets the keys for an object.
|
||||
*
|
||||
* @return {Array} keys
|
||||
* @api private
|
||||
*/
|
||||
|
||||
module.exports = Object.keys || function keys (obj){
|
||||
var arr = [];
|
||||
var has = Object.prototype.hasOwnProperty;
|
||||
|
||||
for (var i in obj) {
|
||||
if (has.call(obj, i)) {
|
||||
arr.push(i);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
33
node_modules/engine.io-client/node_modules/engine.io-parser/package.json
generated
vendored
Normal file
33
node_modules/engine.io-client/node_modules/engine.io-parser/package.json
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "engine.io-parser",
|
||||
"description": "Parser for the client for the realtime Engine",
|
||||
"license": "MIT",
|
||||
"version": "1.3.2",
|
||||
"homepage": "https://github.com/socketio/engine.io-parser",
|
||||
"devDependencies": {
|
||||
"expect.js": "0.3.1",
|
||||
"mocha": "3.2.0",
|
||||
"zuul": "3.11.1",
|
||||
"zuul-ngrok": "4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"after": "0.8.2",
|
||||
"arraybuffer.slice": "0.0.6",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"blob": "0.0.4",
|
||||
"has-binary": "0.1.7",
|
||||
"wtf-8": "1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:socketio/engine.io-parser.git"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib/"
|
||||
],
|
||||
"browser": "./lib/browser.js"
|
||||
}
|
21
node_modules/engine.io-client/node_modules/ms/LICENSE.md
generated
vendored
Normal file
21
node_modules/engine.io-client/node_modules/ms/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Zeit, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
52
node_modules/engine.io-client/node_modules/ms/README.md
generated
vendored
Normal file
52
node_modules/engine.io-client/node_modules/ms/README.md
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# ms
|
||||
|
||||
[](https://travis-ci.org/zeit/ms)
|
||||
[](https://github.com/sindresorhus/xo)
|
||||
[](https://zeit.chat/)
|
||||
|
||||
Use this package to easily convert various time formats to milliseconds.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
ms('2 days') // 172800000
|
||||
ms('1d') // 86400000
|
||||
ms('10h') // 36000000
|
||||
ms('2.5 hrs') // 9000000
|
||||
ms('2h') // 7200000
|
||||
ms('1m') // 60000
|
||||
ms('5s') // 5000
|
||||
ms('1y') // 31557600000
|
||||
ms('100') // 100
|
||||
```
|
||||
|
||||
### Convert from milliseconds
|
||||
|
||||
```js
|
||||
ms(60000) // "1m"
|
||||
ms(2 * 60000) // "2m"
|
||||
ms(ms('10 hours')) // "10h"
|
||||
```
|
||||
|
||||
### Time format written-out
|
||||
|
||||
```js
|
||||
ms(60000, { long: true }) // "1 minute"
|
||||
ms(2 * 60000, { long: true }) // "2 minutes"
|
||||
ms(ms('10 hours'), { long: true }) // "10 hours"
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Works both in [node](https://nodejs.org) and in the browser.
|
||||
- If a number is supplied to `ms`, a string with a unit is returned.
|
||||
- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`).
|
||||
- If you pass a string with a number and a valid unit, the number of equivalent ms is returned.
|
||||
|
||||
## Caught a bug?
|
||||
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
|
||||
2. Link the package to the global module directory: `npm link`
|
||||
3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, node will now use your clone of ms!
|
||||
|
||||
As always, you can run the tests using: `npm test`
|
149
node_modules/engine.io-client/node_modules/ms/index.js
generated
vendored
Normal file
149
node_modules/engine.io-client/node_modules/ms/index.js
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Helpers.
|
||||
*/
|
||||
|
||||
var s = 1000
|
||||
var m = s * 60
|
||||
var h = m * 60
|
||||
var d = h * 24
|
||||
var y = d * 365.25
|
||||
|
||||
/**
|
||||
* Parse or format the given `val`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `long` verbose formatting [false]
|
||||
*
|
||||
* @param {String|Number} val
|
||||
* @param {Object} options
|
||||
* @throws {Error} throw an error if val is not a non-empty string or a number
|
||||
* @return {String|Number}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function (val, options) {
|
||||
options = options || {}
|
||||
var type = typeof val
|
||||
if (type === 'string' && val.length > 0) {
|
||||
return parse(val)
|
||||
} else if (type === 'number' && isNaN(val) === false) {
|
||||
return options.long ?
|
||||
fmtLong(val) :
|
||||
fmtShort(val)
|
||||
}
|
||||
throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val))
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given `str` and return milliseconds.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Number}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function parse(str) {
|
||||
str = String(str)
|
||||
if (str.length > 10000) {
|
||||
return
|
||||
}
|
||||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str)
|
||||
if (!match) {
|
||||
return
|
||||
}
|
||||
var n = parseFloat(match[1])
|
||||
var type = (match[2] || 'ms').toLowerCase()
|
||||
switch (type) {
|
||||
case 'years':
|
||||
case 'year':
|
||||
case 'yrs':
|
||||
case 'yr':
|
||||
case 'y':
|
||||
return n * y
|
||||
case 'days':
|
||||
case 'day':
|
||||
case 'd':
|
||||
return n * d
|
||||
case 'hours':
|
||||
case 'hour':
|
||||
case 'hrs':
|
||||
case 'hr':
|
||||
case 'h':
|
||||
return n * h
|
||||
case 'minutes':
|
||||
case 'minute':
|
||||
case 'mins':
|
||||
case 'min':
|
||||
case 'm':
|
||||
return n * m
|
||||
case 'seconds':
|
||||
case 'second':
|
||||
case 'secs':
|
||||
case 'sec':
|
||||
case 's':
|
||||
return n * s
|
||||
case 'milliseconds':
|
||||
case 'millisecond':
|
||||
case 'msecs':
|
||||
case 'msec':
|
||||
case 'ms':
|
||||
return n
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Short format for `ms`.
|
||||
*
|
||||
* @param {Number} ms
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function fmtShort(ms) {
|
||||
if (ms >= d) {
|
||||
return Math.round(ms / d) + 'd'
|
||||
}
|
||||
if (ms >= h) {
|
||||
return Math.round(ms / h) + 'h'
|
||||
}
|
||||
if (ms >= m) {
|
||||
return Math.round(ms / m) + 'm'
|
||||
}
|
||||
if (ms >= s) {
|
||||
return Math.round(ms / s) + 's'
|
||||
}
|
||||
return ms + 'ms'
|
||||
}
|
||||
|
||||
/**
|
||||
* Long format for `ms`.
|
||||
*
|
||||
* @param {Number} ms
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function fmtLong(ms) {
|
||||
return plural(ms, d, 'day') ||
|
||||
plural(ms, h, 'hour') ||
|
||||
plural(ms, m, 'minute') ||
|
||||
plural(ms, s, 'second') ||
|
||||
ms + ' ms'
|
||||
}
|
||||
|
||||
/**
|
||||
* Pluralization helper.
|
||||
*/
|
||||
|
||||
function plural(ms, n, name) {
|
||||
if (ms < n) {
|
||||
return
|
||||
}
|
||||
if (ms < n * 1.5) {
|
||||
return Math.floor(ms / n) + ' ' + name
|
||||
}
|
||||
return Math.ceil(ms / n) + ' ' + name + 's'
|
||||
}
|
36
node_modules/engine.io-client/node_modules/ms/package.json
generated
vendored
Normal file
36
node_modules/engine.io-client/node_modules/ms/package.json
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "ms",
|
||||
"version": "0.7.2",
|
||||
"description": "Tiny milisecond conversion utility",
|
||||
"repository": "zeit/ms",
|
||||
"main": "./index",
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "xo && mocha test/index.js",
|
||||
"test-browser": "serve ./test"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"expect.js": "^0.3.1",
|
||||
"mocha": "^3.0.2",
|
||||
"serve": "^1.4.0",
|
||||
"xo": "^0.17.0"
|
||||
},
|
||||
"component": {
|
||||
"scripts": {
|
||||
"ms/index.js": "index.js"
|
||||
}
|
||||
},
|
||||
"xo": {
|
||||
"space": true,
|
||||
"semicolon": false,
|
||||
"envs": [
|
||||
"mocha"
|
||||
],
|
||||
"rules": {
|
||||
"complexity": 0
|
||||
}
|
||||
}
|
||||
}
|
235
node_modules/engine.io-client/node_modules/ws/README.md
generated
vendored
Normal file
235
node_modules/engine.io-client/node_modules/ws/README.md
generated
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
# ws: a node.js websocket library
|
||||
|
||||
[](https://travis-ci.org/websockets/ws)
|
||||
|
||||
`ws` is a simple to use WebSocket implementation, up-to-date against RFC-6455,
|
||||
and [probably the fastest WebSocket library for node.js][archive].
|
||||
|
||||
Passes the quite extensive Autobahn test suite. See http://websockets.github.com/ws
|
||||
for the full reports.
|
||||
|
||||
## Protocol support
|
||||
|
||||
* **Hixie draft 76** (Old and deprecated, but still in use by Safari and Opera.
|
||||
Added to ws version 0.4.2, but server only. Can be disabled by setting the
|
||||
`disableHixie` option to true.)
|
||||
* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
|
||||
* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
|
||||
|
||||
### Installing
|
||||
|
||||
```
|
||||
npm install --save ws
|
||||
```
|
||||
|
||||
### Opt-in for performance
|
||||
|
||||
There are 2 optional modules that can be installed along side with the `ws`
|
||||
module. These modules are binary addons which improve certain operations, but as
|
||||
they are binary addons they require compilation which can fail if no c++
|
||||
compiler is installed on the host system.
|
||||
|
||||
- `npm install --save bufferutil`: Improves internal buffer operations which
|
||||
allows for faster processing of masked WebSocket frames and general buffer
|
||||
operations.
|
||||
- `npm install --save utf-8-validate`: The specification requires validation of
|
||||
invalid UTF-8 chars, some of these validations could not be done in JavaScript
|
||||
hence the need for a binary addon. In most cases you will already be
|
||||
validating the input that you receive for security purposes leading to double
|
||||
validation. But if you want to be 100% spec-conforming and have fast
|
||||
validation of UTF-8 then this module is a must.
|
||||
|
||||
### Sending and receiving text data
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://www.host.com/path');
|
||||
|
||||
ws.on('open', function open() {
|
||||
ws.send('something');
|
||||
});
|
||||
|
||||
ws.on('message', function(data, flags) {
|
||||
// flags.binary will be set if a binary data is received.
|
||||
// flags.masked will be set if the data was masked.
|
||||
});
|
||||
```
|
||||
|
||||
### Sending binary data
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://www.host.com/path');
|
||||
|
||||
ws.on('open', function open() {
|
||||
var array = new Float32Array(5);
|
||||
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
array[i] = i / 2;
|
||||
}
|
||||
|
||||
ws.send(array, { binary: true, mask: true });
|
||||
});
|
||||
```
|
||||
|
||||
Setting `mask`, as done for the send options above, will cause the data to be
|
||||
masked according to the WebSocket protocol. The same option applies for text
|
||||
data.
|
||||
|
||||
### Server example
|
||||
|
||||
```js
|
||||
var WebSocketServer = require('ws').Server
|
||||
, wss = new WebSocketServer({ port: 8080 });
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('received: %s', message);
|
||||
});
|
||||
|
||||
ws.send('something');
|
||||
});
|
||||
```
|
||||
|
||||
### ExpressJS example
|
||||
|
||||
```js
|
||||
var server = require('http').createServer()
|
||||
, url = require('url')
|
||||
, WebSocketServer = require('ws').Server
|
||||
, wss = new WebSocketServer({ server: server })
|
||||
, express = require('express')
|
||||
, app = express()
|
||||
, port = 4080;
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send({ msg: "hello" });
|
||||
});
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
var location = url.parse(ws.upgradeReq.url, true);
|
||||
// you might use location.query.access_token to authenticate or share sessions
|
||||
// or ws.upgradeReq.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
|
||||
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('received: %s', message);
|
||||
});
|
||||
|
||||
ws.send('something');
|
||||
});
|
||||
|
||||
server.on('request', app);
|
||||
server.listen(port, function () { console.log('Listening on ' + server.address().port) });
|
||||
```
|
||||
|
||||
### Server sending broadcast data
|
||||
|
||||
```js
|
||||
var WebSocketServer = require('ws').Server
|
||||
, wss = new WebSocketServer({ port: 8080 });
|
||||
|
||||
wss.broadcast = function broadcast(data) {
|
||||
wss.clients.forEach(function each(client) {
|
||||
client.send(data);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### Error handling best practices
|
||||
|
||||
```js
|
||||
// If the WebSocket is closed before the following send is attempted
|
||||
ws.send('something');
|
||||
|
||||
// Errors (both immediate and async write errors) can be detected in an optional
|
||||
// callback. The callback is also the only way of being notified that data has
|
||||
// actually been sent.
|
||||
ws.send('something', function ack(error) {
|
||||
// if error is not defined, the send has been completed,
|
||||
// otherwise the error object will indicate what failed.
|
||||
});
|
||||
|
||||
// Immediate errors can also be handled with try/catch-blocks, but **note** that
|
||||
// since sends are inherently asynchronous, socket write failures will *not* be
|
||||
// captured when this technique is used.
|
||||
try { ws.send('something'); }
|
||||
catch (e) { /* handle error */ }
|
||||
```
|
||||
|
||||
### echo.websocket.org demo
|
||||
|
||||
```js
|
||||
var WebSocket = require('ws');
|
||||
var ws = new WebSocket('ws://echo.websocket.org/', {
|
||||
protocolVersion: 8,
|
||||
origin: 'http://websocket.org'
|
||||
});
|
||||
|
||||
ws.on('open', function open() {
|
||||
console.log('connected');
|
||||
ws.send(Date.now().toString(), {mask: true});
|
||||
});
|
||||
|
||||
ws.on('close', function close() {
|
||||
console.log('disconnected');
|
||||
});
|
||||
|
||||
ws.on('message', function message(data, flags) {
|
||||
console.log('Roundtrip time: ' + (Date.now() - parseInt(data)) + 'ms', flags);
|
||||
|
||||
setTimeout(function timeout() {
|
||||
ws.send(Date.now().toString(), {mask: true});
|
||||
}, 500);
|
||||
});
|
||||
```
|
||||
|
||||
### Other examples
|
||||
|
||||
For a full example with a browser client communicating with a ws server, see the
|
||||
examples folder.
|
||||
|
||||
Note that the usage together with Express 3.0 is quite different from Express
|
||||
2.x. The difference is expressed in the two different serverstats-examples.
|
||||
|
||||
Otherwise, see the test cases.
|
||||
|
||||
### Running the tests
|
||||
|
||||
```
|
||||
make test
|
||||
```
|
||||
|
||||
## API Docs
|
||||
|
||||
See [`/doc/ws.md`](https://github.com/websockets/ws/blob/master/doc/ws.md) for Node.js-like docs for the ws classes.
|
||||
|
||||
## Changelog
|
||||
|
||||
We're using the GitHub [`releases`](https://github.com/websockets/ws/releases) for changelog entries.
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[archive]: http://web.archive.org/web/20130314230536/http://hobbycoding.posterous.com/the-fastest-websocket-module-for-nodejs
|
49
node_modules/engine.io-client/node_modules/ws/index.js
generated
vendored
Normal file
49
node_modules/engine.io-client/node_modules/ws/index.js
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var WS = module.exports = require('./lib/WebSocket');
|
||||
|
||||
WS.Server = require('./lib/WebSocketServer');
|
||||
WS.Sender = require('./lib/Sender');
|
||||
WS.Receiver = require('./lib/Receiver');
|
||||
|
||||
/**
|
||||
* Create a new WebSocket server.
|
||||
*
|
||||
* @param {Object} options Server options
|
||||
* @param {Function} fn Optional connection listener.
|
||||
* @returns {WS.Server}
|
||||
* @api public
|
||||
*/
|
||||
WS.createServer = function createServer(options, fn) {
|
||||
var server = new WS.Server(options);
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
server.on('connection', fn);
|
||||
}
|
||||
|
||||
return server;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new WebSocket connection.
|
||||
*
|
||||
* @param {String} address The URL/address we need to connect to.
|
||||
* @param {Function} fn Open listener.
|
||||
* @returns {WS}
|
||||
* @api public
|
||||
*/
|
||||
WS.connect = WS.createConnection = function connect(address, fn) {
|
||||
var client = new WS(address);
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
client.on('open', fn);
|
||||
}
|
||||
|
||||
return client;
|
||||
};
|
BIN
node_modules/engine.io-client/node_modules/ws/lib/.DS_Store
generated
vendored
Normal file
BIN
node_modules/engine.io-client/node_modules/ws/lib/.DS_Store
generated
vendored
Normal file
Binary file not shown.
63
node_modules/engine.io-client/node_modules/ws/lib/BufferPool.js
generated
vendored
Normal file
63
node_modules/engine.io-client/node_modules/ws/lib/BufferPool.js
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
function BufferPool(initialSize, growStrategy, shrinkStrategy) {
|
||||
if (this instanceof BufferPool === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
|
||||
if (typeof initialSize === 'function') {
|
||||
shrinkStrategy = growStrategy;
|
||||
growStrategy = initialSize;
|
||||
initialSize = 0;
|
||||
}
|
||||
else if (typeof initialSize === 'undefined') {
|
||||
initialSize = 0;
|
||||
}
|
||||
this._growStrategy = (growStrategy || function(db, size) {
|
||||
return db.used + size;
|
||||
}).bind(null, this);
|
||||
this._shrinkStrategy = (shrinkStrategy || function(db) {
|
||||
return initialSize;
|
||||
}).bind(null, this);
|
||||
this._buffer = initialSize ? new Buffer(initialSize) : null;
|
||||
this._offset = 0;
|
||||
this._used = 0;
|
||||
this._changeFactor = 0;
|
||||
this.__defineGetter__('size', function(){
|
||||
return this._buffer == null ? 0 : this._buffer.length;
|
||||
});
|
||||
this.__defineGetter__('used', function(){
|
||||
return this._used;
|
||||
});
|
||||
}
|
||||
|
||||
BufferPool.prototype.get = function(length) {
|
||||
if (this._buffer == null || this._offset + length > this._buffer.length) {
|
||||
var newBuf = new Buffer(this._growStrategy(length));
|
||||
this._buffer = newBuf;
|
||||
this._offset = 0;
|
||||
}
|
||||
this._used += length;
|
||||
var buf = this._buffer.slice(this._offset, this._offset + length);
|
||||
this._offset += length;
|
||||
return buf;
|
||||
}
|
||||
|
||||
BufferPool.prototype.reset = function(forceNewBuffer) {
|
||||
var len = this._shrinkStrategy();
|
||||
if (len < this.size) this._changeFactor -= 1;
|
||||
if (forceNewBuffer || this._changeFactor < -2) {
|
||||
this._changeFactor = 0;
|
||||
this._buffer = len ? new Buffer(len) : null;
|
||||
}
|
||||
this._offset = 0;
|
||||
this._used = 0;
|
||||
}
|
||||
|
||||
module.exports = BufferPool;
|
47
node_modules/engine.io-client/node_modules/ws/lib/BufferUtil.fallback.js
generated
vendored
Normal file
47
node_modules/engine.io-client/node_modules/ws/lib/BufferUtil.fallback.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
exports.BufferUtil = {
|
||||
merge: function(mergedBuffer, buffers) {
|
||||
var offset = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
var buf = buffers[i];
|
||||
buf.copy(mergedBuffer, offset);
|
||||
offset += buf.length;
|
||||
}
|
||||
},
|
||||
mask: function(source, mask, output, offset, length) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var i = 0;
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ source.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
output.writeUInt32LE(num, offset + i, true);
|
||||
}
|
||||
switch (length % 4) {
|
||||
case 3: output[offset + i + 2] = source[i + 2] ^ mask[2];
|
||||
case 2: output[offset + i + 1] = source[i + 1] ^ mask[1];
|
||||
case 1: output[offset + i] = source[i] ^ mask[0];
|
||||
case 0:;
|
||||
}
|
||||
},
|
||||
unmask: function(data, mask) {
|
||||
var maskNum = mask.readUInt32LE(0, true);
|
||||
var length = data.length;
|
||||
var i = 0;
|
||||
for (; i < length - 3; i += 4) {
|
||||
var num = maskNum ^ data.readUInt32LE(i, true);
|
||||
if (num < 0) num = 4294967296 + num;
|
||||
data.writeUInt32LE(num, i, true);
|
||||
}
|
||||
switch (length % 4) {
|
||||
case 3: data[i + 2] = data[i + 2] ^ mask[2];
|
||||
case 2: data[i + 1] = data[i + 1] ^ mask[1];
|
||||
case 1: data[i] = data[i] ^ mask[0];
|
||||
case 0:;
|
||||
}
|
||||
}
|
||||
}
|
17
node_modules/engine.io-client/node_modules/ws/lib/BufferUtil.js
generated
vendored
Normal file
17
node_modules/engine.io-client/node_modules/ws/lib/BufferUtil.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var bufferUtil;
|
||||
|
||||
try {
|
||||
bufferUtil = require('bufferutil');
|
||||
} catch (e) {
|
||||
bufferUtil = require('./BufferUtil.fallback');
|
||||
}
|
||||
|
||||
module.exports = bufferUtil.BufferUtil || bufferUtil;
|
24
node_modules/engine.io-client/node_modules/ws/lib/ErrorCodes.js
generated
vendored
Normal file
24
node_modules/engine.io-client/node_modules/ws/lib/ErrorCodes.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
isValidErrorCode: function(code) {
|
||||
return (code >= 1000 && code <= 1011 && code != 1004 && code != 1005 && code != 1006) ||
|
||||
(code >= 3000 && code <= 4999);
|
||||
},
|
||||
1000: 'normal',
|
||||
1001: 'going away',
|
||||
1002: 'protocol error',
|
||||
1003: 'unsupported data',
|
||||
1004: 'reserved',
|
||||
1005: 'reserved for extensions',
|
||||
1006: 'reserved for extensions',
|
||||
1007: 'inconsistent or invalid data',
|
||||
1008: 'policy violation',
|
||||
1009: 'message too big',
|
||||
1010: 'extension handshake missing',
|
||||
1011: 'an unexpected condition prevented the request from being fulfilled',
|
||||
};
|
81
node_modules/engine.io-client/node_modules/ws/lib/Extensions.js
generated
vendored
Normal file
81
node_modules/engine.io-client/node_modules/ws/lib/Extensions.js
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
exports.parse = parse;
|
||||
exports.format = format;
|
||||
|
||||
/**
|
||||
* Parse extensions header value
|
||||
*/
|
||||
|
||||
function parse(value) {
|
||||
value = value || '';
|
||||
|
||||
var extensions = {};
|
||||
|
||||
value.split(',').forEach(function(v) {
|
||||
var params = v.split(';');
|
||||
var token = params.shift().trim();
|
||||
|
||||
if (extensions[token] === undefined) {
|
||||
extensions[token] = [];
|
||||
} else if (!extensions.hasOwnProperty(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parsedParams = {};
|
||||
|
||||
params.forEach(function(param) {
|
||||
var parts = param.trim().split('=');
|
||||
var key = parts[0];
|
||||
var value = parts[1];
|
||||
if (typeof value === 'undefined') {
|
||||
value = true;
|
||||
} else {
|
||||
// unquote value
|
||||
if (value[0] === '"') {
|
||||
value = value.slice(1);
|
||||
}
|
||||
if (value[value.length - 1] === '"') {
|
||||
value = value.slice(0, value.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedParams[key] === undefined) {
|
||||
parsedParams[key] = [value];
|
||||
} else if (parsedParams.hasOwnProperty(key)) {
|
||||
parsedParams[key].push(value);
|
||||
}
|
||||
});
|
||||
|
||||
extensions[token].push(parsedParams);
|
||||
});
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format extensions header value
|
||||
*/
|
||||
|
||||
function format(value) {
|
||||
return Object.keys(value).map(function(token) {
|
||||
var paramsList = value[token];
|
||||
if (!util.isArray(paramsList)) {
|
||||
paramsList = [paramsList];
|
||||
}
|
||||
return paramsList.map(function(params) {
|
||||
return [token].concat(Object.keys(params).map(function(k) {
|
||||
var p = params[k];
|
||||
if (!util.isArray(p)) p = [p];
|
||||
return p.map(function(v) {
|
||||
return v === true ? k : k + '=' + v;
|
||||
}).join('; ');
|
||||
})).join('; ');
|
||||
}).join(', ');
|
||||
}).join(', ');
|
||||
}
|
337
node_modules/engine.io-client/node_modules/ws/lib/PerMessageDeflate.js
generated
vendored
Normal file
337
node_modules/engine.io-client/node_modules/ws/lib/PerMessageDeflate.js
generated
vendored
Normal file
@ -0,0 +1,337 @@
|
||||
|
||||
var zlib = require('zlib');
|
||||
|
||||
var AVAILABLE_WINDOW_BITS = [8, 9, 10, 11, 12, 13, 14, 15];
|
||||
var DEFAULT_WINDOW_BITS = 15;
|
||||
var DEFAULT_MEM_LEVEL = 8;
|
||||
|
||||
PerMessageDeflate.extensionName = 'permessage-deflate';
|
||||
|
||||
/**
|
||||
* Per-message Compression Extensions implementation
|
||||
*/
|
||||
|
||||
function PerMessageDeflate(options, isServer,maxPayload) {
|
||||
if (this instanceof PerMessageDeflate === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
|
||||
this._options = options || {};
|
||||
this._isServer = !!isServer;
|
||||
this._inflate = null;
|
||||
this._deflate = null;
|
||||
this.params = null;
|
||||
this._maxPayload = maxPayload || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create extension parameters offer
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.offer = function() {
|
||||
var params = {};
|
||||
if (this._options.serverNoContextTakeover) {
|
||||
params.server_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover) {
|
||||
params.client_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.serverMaxWindowBits) {
|
||||
params.server_max_window_bits = this._options.serverMaxWindowBits;
|
||||
}
|
||||
if (this._options.clientMaxWindowBits) {
|
||||
params.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
} else if (this._options.clientMaxWindowBits == null) {
|
||||
params.client_max_window_bits = true;
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension offer
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.accept = function(paramsList) {
|
||||
paramsList = this.normalizeParams(paramsList);
|
||||
|
||||
var params;
|
||||
if (this._isServer) {
|
||||
params = this.acceptAsServer(paramsList);
|
||||
} else {
|
||||
params = this.acceptAsClient(paramsList);
|
||||
}
|
||||
|
||||
this.params = params;
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases all resources used by the extension
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.cleanup = function() {
|
||||
if (this._inflate) {
|
||||
if (this._inflate.writeInProgress) {
|
||||
this._inflate.pendingClose = true;
|
||||
} else {
|
||||
if (this._inflate.close) this._inflate.close();
|
||||
this._inflate = null;
|
||||
}
|
||||
}
|
||||
if (this._deflate) {
|
||||
if (this._deflate.writeInProgress) {
|
||||
this._deflate.pendingClose = true;
|
||||
} else {
|
||||
if (this._deflate.close) this._deflate.close();
|
||||
this._deflate = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension offer from client
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.acceptAsServer = function(paramsList) {
|
||||
var accepted = {};
|
||||
var result = paramsList.some(function(params) {
|
||||
accepted = {};
|
||||
if (this._options.serverNoContextTakeover === false && params.server_no_context_takeover) {
|
||||
return;
|
||||
}
|
||||
if (this._options.serverMaxWindowBits === false && params.server_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
if (typeof this._options.serverMaxWindowBits === 'number' &&
|
||||
typeof params.server_max_window_bits === 'number' &&
|
||||
this._options.serverMaxWindowBits > params.server_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number' && !params.client_max_window_bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._options.serverNoContextTakeover || params.server_no_context_takeover) {
|
||||
accepted.server_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover) {
|
||||
accepted.client_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover !== false && params.client_no_context_takeover) {
|
||||
accepted.client_no_context_takeover = true;
|
||||
}
|
||||
if (typeof this._options.serverMaxWindowBits === 'number') {
|
||||
accepted.server_max_window_bits = this._options.serverMaxWindowBits;
|
||||
} else if (typeof params.server_max_window_bits === 'number') {
|
||||
accepted.server_max_window_bits = params.server_max_window_bits;
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number') {
|
||||
accepted.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
} else if (this._options.clientMaxWindowBits !== false && typeof params.client_max_window_bits === 'number') {
|
||||
accepted.client_max_window_bits = params.client_max_window_bits;
|
||||
}
|
||||
return true;
|
||||
}, this);
|
||||
|
||||
if (!result) {
|
||||
throw new Error('Doesn\'t support the offered configuration');
|
||||
}
|
||||
|
||||
return accepted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept extension response from server
|
||||
*
|
||||
* @api privaye
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.acceptAsClient = function(paramsList) {
|
||||
var params = paramsList[0];
|
||||
if (this._options.clientNoContextTakeover != null) {
|
||||
if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) {
|
||||
throw new Error('Invalid value for "client_no_context_takeover"');
|
||||
}
|
||||
}
|
||||
if (this._options.clientMaxWindowBits != null) {
|
||||
if (this._options.clientMaxWindowBits === false && params.client_max_window_bits) {
|
||||
throw new Error('Invalid value for "client_max_window_bits"');
|
||||
}
|
||||
if (typeof this._options.clientMaxWindowBits === 'number' &&
|
||||
(!params.client_max_window_bits || params.client_max_window_bits > this._options.clientMaxWindowBits)) {
|
||||
throw new Error('Invalid value for "client_max_window_bits"');
|
||||
}
|
||||
}
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize extensions parameters
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.normalizeParams = function(paramsList) {
|
||||
return paramsList.map(function(params) {
|
||||
Object.keys(params).forEach(function(key) {
|
||||
var value = params[key];
|
||||
if (value.length > 1) {
|
||||
throw new Error('Multiple extension parameters for ' + key);
|
||||
}
|
||||
|
||||
value = value[0];
|
||||
|
||||
switch (key) {
|
||||
case 'server_no_context_takeover':
|
||||
case 'client_no_context_takeover':
|
||||
if (value !== true) {
|
||||
throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')');
|
||||
}
|
||||
params[key] = true;
|
||||
break;
|
||||
case 'server_max_window_bits':
|
||||
case 'client_max_window_bits':
|
||||
if (typeof value === 'string') {
|
||||
value = parseInt(value, 10);
|
||||
if (!~AVAILABLE_WINDOW_BITS.indexOf(value)) {
|
||||
throw new Error('invalid extension parameter value for ' + key + ' (' + value + ')');
|
||||
}
|
||||
}
|
||||
if (!this._isServer && value === true) {
|
||||
throw new Error('Missing extension parameter value for ' + key);
|
||||
}
|
||||
params[key] = value;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Not defined extension parameter (' + key + ')');
|
||||
}
|
||||
}, this);
|
||||
return params;
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decompress message
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.decompress = function (data, fin, callback) {
|
||||
var endpoint = this._isServer ? 'client' : 'server';
|
||||
|
||||
if (!this._inflate) {
|
||||
var maxWindowBits = this.params[endpoint + '_max_window_bits'];
|
||||
this._inflate = zlib.createInflateRaw({
|
||||
windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS
|
||||
});
|
||||
}
|
||||
this._inflate.writeInProgress = true;
|
||||
|
||||
var self = this;
|
||||
var buffers = [];
|
||||
var cumulativeBufferLength=0;
|
||||
|
||||
this._inflate.on('error', onError).on('data', onData);
|
||||
this._inflate.write(data);
|
||||
if (fin) {
|
||||
this._inflate.write(new Buffer([0x00, 0x00, 0xff, 0xff]));
|
||||
}
|
||||
this._inflate.flush(function() {
|
||||
cleanup();
|
||||
callback(null, Buffer.concat(buffers));
|
||||
});
|
||||
|
||||
function onError(err) {
|
||||
cleanup();
|
||||
callback(err);
|
||||
}
|
||||
|
||||
function onData(data) {
|
||||
if(self._maxPayload!==undefined && self._maxPayload!==null && self._maxPayload>0){
|
||||
cumulativeBufferLength+=data.length;
|
||||
if(cumulativeBufferLength>self._maxPayload){
|
||||
buffers=[];
|
||||
cleanup();
|
||||
var err={type:1009};
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buffers.push(data);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (!self._inflate) return;
|
||||
self._inflate.removeListener('error', onError);
|
||||
self._inflate.removeListener('data', onData);
|
||||
self._inflate.writeInProgress = false;
|
||||
if ((fin && self.params[endpoint + '_no_context_takeover']) || self._inflate.pendingClose) {
|
||||
if (self._inflate.close) self._inflate.close();
|
||||
self._inflate = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compress message
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
PerMessageDeflate.prototype.compress = function (data, fin, callback) {
|
||||
var endpoint = this._isServer ? 'server' : 'client';
|
||||
|
||||
if (!this._deflate) {
|
||||
var maxWindowBits = this.params[endpoint + '_max_window_bits'];
|
||||
this._deflate = zlib.createDeflateRaw({
|
||||
flush: zlib.Z_SYNC_FLUSH,
|
||||
windowBits: 'number' === typeof maxWindowBits ? maxWindowBits : DEFAULT_WINDOW_BITS,
|
||||
memLevel: this._options.memLevel || DEFAULT_MEM_LEVEL
|
||||
});
|
||||
}
|
||||
this._deflate.writeInProgress = true;
|
||||
|
||||
var self = this;
|
||||
var buffers = [];
|
||||
|
||||
this._deflate.on('error', onError).on('data', onData);
|
||||
this._deflate.write(data);
|
||||
this._deflate.flush(function() {
|
||||
cleanup();
|
||||
var data = Buffer.concat(buffers);
|
||||
if (fin) {
|
||||
data = data.slice(0, data.length - 4);
|
||||
}
|
||||
callback(null, data);
|
||||
});
|
||||
|
||||
function onError(err) {
|
||||
cleanup();
|
||||
callback(err);
|
||||
}
|
||||
|
||||
function onData(data) {
|
||||
buffers.push(data);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (!self._deflate) return;
|
||||
self._deflate.removeListener('error', onError);
|
||||
self._deflate.removeListener('data', onData);
|
||||
self._deflate.writeInProgress = false;
|
||||
if ((fin && self.params[endpoint + '_no_context_takeover']) || self._deflate.pendingClose) {
|
||||
if (self._deflate.close) self._deflate.close();
|
||||
self._deflate = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PerMessageDeflate;
|
194
node_modules/engine.io-client/node_modules/ws/lib/Receiver.hixie.js
generated
vendored
Normal file
194
node_modules/engine.io-client/node_modules/ws/lib/Receiver.hixie.js
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* State constants
|
||||
*/
|
||||
|
||||
var EMPTY = 0
|
||||
, BODY = 1;
|
||||
var BINARYLENGTH = 2
|
||||
, BINARYBODY = 3;
|
||||
|
||||
/**
|
||||
* Hixie Receiver implementation
|
||||
*/
|
||||
|
||||
function Receiver () {
|
||||
if (this instanceof Receiver === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
this.messageEnd = -1;
|
||||
this.spanLength = 0;
|
||||
this.dead = false;
|
||||
|
||||
this.onerror = function() {};
|
||||
this.ontext = function() {};
|
||||
this.onbinary = function() {};
|
||||
this.onclose = function() {};
|
||||
this.onping = function() {};
|
||||
this.onpong = function() {};
|
||||
}
|
||||
|
||||
module.exports = Receiver;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.add = function(data) {
|
||||
if (this.dead) return;
|
||||
var self = this;
|
||||
function doAdd() {
|
||||
if (self.state === EMPTY) {
|
||||
if (data.length == 2 && data[0] == 0xFF && data[1] == 0x00) {
|
||||
self.reset();
|
||||
self.onclose();
|
||||
return;
|
||||
}
|
||||
if (data[0] === 0x80) {
|
||||
self.messageEnd = 0;
|
||||
self.state = BINARYLENGTH;
|
||||
data = data.slice(1);
|
||||
} else {
|
||||
|
||||
if (data[0] !== 0x00) {
|
||||
self.error('payload must start with 0x00 byte', true);
|
||||
return;
|
||||
}
|
||||
data = data.slice(1);
|
||||
self.state = BODY;
|
||||
|
||||
}
|
||||
}
|
||||
if (self.state === BINARYLENGTH) {
|
||||
var i = 0;
|
||||
while ((i < data.length) && (data[i] & 0x80)) {
|
||||
self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
|
||||
++i;
|
||||
}
|
||||
if (i < data.length) {
|
||||
self.messageEnd = 128 * self.messageEnd + (data[i] & 0x7f);
|
||||
self.state = BINARYBODY;
|
||||
++i;
|
||||
}
|
||||
if (i > 0)
|
||||
data = data.slice(i);
|
||||
}
|
||||
if (self.state === BINARYBODY) {
|
||||
var dataleft = self.messageEnd - self.spanLength;
|
||||
if (data.length >= dataleft) {
|
||||
// consume the whole buffer to finish the frame
|
||||
self.buffers.push(data);
|
||||
self.spanLength += dataleft;
|
||||
self.messageEnd = dataleft;
|
||||
return self.parse();
|
||||
}
|
||||
// frame's not done even if we consume it all
|
||||
self.buffers.push(data);
|
||||
self.spanLength += data.length;
|
||||
return;
|
||||
}
|
||||
self.buffers.push(data);
|
||||
if ((self.messageEnd = bufferIndex(data, 0xFF)) != -1) {
|
||||
self.spanLength += self.messageEnd;
|
||||
return self.parse();
|
||||
}
|
||||
else self.spanLength += data.length;
|
||||
}
|
||||
while(data) data = doAdd();
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases all resources used by the receiver.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.cleanup = function() {
|
||||
this.dead = true;
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Process buffered data.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.parse = function() {
|
||||
var output = new Buffer(this.spanLength);
|
||||
var outputIndex = 0;
|
||||
for (var bi = 0, bl = this.buffers.length; bi < bl - 1; ++bi) {
|
||||
var buffer = this.buffers[bi];
|
||||
buffer.copy(output, outputIndex);
|
||||
outputIndex += buffer.length;
|
||||
}
|
||||
var lastBuffer = this.buffers[this.buffers.length - 1];
|
||||
if (this.messageEnd > 0) lastBuffer.copy(output, outputIndex, 0, this.messageEnd);
|
||||
if (this.state !== BODY) --this.messageEnd;
|
||||
var tail = null;
|
||||
if (this.messageEnd < lastBuffer.length - 1) {
|
||||
tail = lastBuffer.slice(this.messageEnd + 1);
|
||||
}
|
||||
this.reset();
|
||||
this.ontext(output.toString('utf8'));
|
||||
return tail;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.error = function (reason, terminate) {
|
||||
if (this.dead) return;
|
||||
this.reset();
|
||||
if(typeof reason == 'string'){
|
||||
this.onerror(new Error(reason), terminate);
|
||||
}
|
||||
else if(reason.constructor == Error){
|
||||
this.onerror(reason, terminate);
|
||||
}
|
||||
else{
|
||||
this.onerror(new Error("An error occured"),terminate);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset parser state
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.reset = function (reason) {
|
||||
if (this.dead) return;
|
||||
this.state = EMPTY;
|
||||
this.buffers = [];
|
||||
this.messageEnd = -1;
|
||||
this.spanLength = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal api
|
||||
*/
|
||||
|
||||
function bufferIndex(buffer, byte) {
|
||||
for (var i = 0, l = buffer.length; i < l; ++i) {
|
||||
if (buffer[i] === byte) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
793
node_modules/engine.io-client/node_modules/ws/lib/Receiver.js
generated
vendored
Normal file
793
node_modules/engine.io-client/node_modules/ws/lib/Receiver.js
generated
vendored
Normal file
@ -0,0 +1,793 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util')
|
||||
, isValidUTF8 = require('./Validation')
|
||||
, ErrorCodes = require('./ErrorCodes')
|
||||
, BufferPool = require('./BufferPool')
|
||||
, bufferUtil = require('./BufferUtil')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate');
|
||||
|
||||
/**
|
||||
* HyBi Receiver implementation
|
||||
*/
|
||||
|
||||
function Receiver (extensions,maxPayload) {
|
||||
if (this instanceof Receiver === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
if(typeof extensions==='number'){
|
||||
maxPayload=extensions;
|
||||
extensions={};
|
||||
}
|
||||
|
||||
|
||||
// memory pool for fragmented messages
|
||||
var fragmentedPoolPrevUsed = -1;
|
||||
this.fragmentedBufferPool = new BufferPool(1024, function(db, length) {
|
||||
return db.used + length;
|
||||
}, function(db) {
|
||||
return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ?
|
||||
Math.ceil((fragmentedPoolPrevUsed + db.used) / 2) :
|
||||
db.used;
|
||||
});
|
||||
|
||||
// memory pool for unfragmented messages
|
||||
var unfragmentedPoolPrevUsed = -1;
|
||||
this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) {
|
||||
return db.used + length;
|
||||
}, function(db) {
|
||||
return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ?
|
||||
Math.ceil((unfragmentedPoolPrevUsed + db.used) / 2) :
|
||||
db.used;
|
||||
});
|
||||
this.extensions = extensions || {};
|
||||
this.maxPayload = maxPayload || 0;
|
||||
this.currentPayloadLength = 0;
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0,
|
||||
fragmentedOperation: false
|
||||
};
|
||||
this.overflow = [];
|
||||
this.headerBuffer = new Buffer(10);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = [];
|
||||
this.currentMessageLength = 0;
|
||||
this.messageHandlers = [];
|
||||
this.expectHeader(2, this.processPacket);
|
||||
this.dead = false;
|
||||
this.processing = false;
|
||||
|
||||
this.onerror = function() {};
|
||||
this.ontext = function() {};
|
||||
this.onbinary = function() {};
|
||||
this.onclose = function() {};
|
||||
this.onping = function() {};
|
||||
this.onpong = function() {};
|
||||
}
|
||||
|
||||
module.exports = Receiver;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.add = function(data) {
|
||||
if (this.dead) return;
|
||||
var dataLength = data.length;
|
||||
if (dataLength == 0) return;
|
||||
if (this.expectBuffer == null) {
|
||||
this.overflow.push(data);
|
||||
return;
|
||||
}
|
||||
var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset);
|
||||
fastCopy(toRead, data, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += toRead;
|
||||
if (toRead < dataLength) {
|
||||
this.overflow.push(data.slice(toRead));
|
||||
}
|
||||
while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) {
|
||||
var bufferForHandler = this.expectBuffer;
|
||||
this.expectBuffer = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler.call(this, bufferForHandler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Releases all resources used by the receiver.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Receiver.prototype.cleanup = function() {
|
||||
this.dead = true;
|
||||
this.overflow = null;
|
||||
this.headerBuffer = null;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.unfragmentedBufferPool = null;
|
||||
this.fragmentedBufferPool = null;
|
||||
this.state = null;
|
||||
this.currentMessage = null;
|
||||
this.onerror = null;
|
||||
this.ontext = null;
|
||||
this.onbinary = null;
|
||||
this.onclose = null;
|
||||
this.onping = null;
|
||||
this.onpong = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of header bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.expectHeader = function(length, handler) {
|
||||
if (length == 0) {
|
||||
handler(null);
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length);
|
||||
this.expectHandler = handler;
|
||||
var toRead = length;
|
||||
while (toRead > 0 && this.overflow.length > 0) {
|
||||
var fromOverflow = this.overflow.pop();
|
||||
if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
|
||||
var read = Math.min(fromOverflow.length, toRead);
|
||||
fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += read;
|
||||
toRead -= read;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of data bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.expectData = function(length, handler) {
|
||||
if (length == 0) {
|
||||
handler(null);
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation);
|
||||
this.expectHandler = handler;
|
||||
var toRead = length;
|
||||
while (toRead > 0 && this.overflow.length > 0) {
|
||||
var fromOverflow = this.overflow.pop();
|
||||
if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
|
||||
var read = Math.min(fromOverflow.length, toRead);
|
||||
fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
|
||||
this.expectOffset += read;
|
||||
toRead -= read;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates memory from the buffer pool.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.allocateFromPool = function(length, isFragmented) {
|
||||
return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Start processing a new packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.processPacket = function (data) {
|
||||
if (this.extensions[PerMessageDeflate.extensionName]) {
|
||||
if ((data[0] & 0x30) != 0) {
|
||||
this.error('reserved fields (2, 3) must be empty', 1002);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((data[0] & 0x70) != 0) {
|
||||
this.error('reserved fields must be empty', 1002);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.state.lastFragment = (data[0] & 0x80) == 0x80;
|
||||
this.state.masked = (data[1] & 0x80) == 0x80;
|
||||
var compressed = (data[0] & 0x40) == 0x40;
|
||||
var opcode = data[0] & 0xf;
|
||||
if (opcode === 0) {
|
||||
if (compressed) {
|
||||
this.error('continuation frame cannot have the Per-message Compressed bits', 1002);
|
||||
return;
|
||||
}
|
||||
// continuation frame
|
||||
this.state.fragmentedOperation = true;
|
||||
this.state.opcode = this.state.activeFragmentedOperation;
|
||||
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
|
||||
this.error('continuation frame cannot follow current opcode', 1002);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (opcode < 3 && this.state.activeFragmentedOperation != null) {
|
||||
this.error('data frames after the initial data frame must have opcode 0', 1002);
|
||||
return;
|
||||
}
|
||||
if (opcode >= 8 && compressed) {
|
||||
this.error('control frames cannot have the Per-message Compressed bits', 1002);
|
||||
return;
|
||||
}
|
||||
this.state.compressed = compressed;
|
||||
this.state.opcode = opcode;
|
||||
if (this.state.lastFragment === false) {
|
||||
this.state.fragmentedOperation = true;
|
||||
this.state.activeFragmentedOperation = opcode;
|
||||
}
|
||||
else this.state.fragmentedOperation = false;
|
||||
}
|
||||
var handler = opcodes[this.state.opcode];
|
||||
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002);
|
||||
else {
|
||||
handler.start.call(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Endprocessing a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.endPacket = function() {
|
||||
if (this.dead) return;
|
||||
if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true);
|
||||
else if (this.state.lastFragment) this.fragmentedBufferPool.reset(true);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) {
|
||||
// end current fragmented operation
|
||||
this.state.activeFragmentedOperation = null;
|
||||
}
|
||||
this.currentPayloadLength = 0;
|
||||
this.state.lastFragment = false;
|
||||
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
|
||||
this.state.masked = false;
|
||||
this.expectHeader(2, this.processPacket);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the parser state.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.reset = function() {
|
||||
if (this.dead) return;
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0,
|
||||
fragmentedOperation: false
|
||||
};
|
||||
this.fragmentedBufferPool.reset(true);
|
||||
this.unfragmentedBufferPool.reset(true);
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.overflow = [];
|
||||
this.currentMessage = [];
|
||||
this.currentMessageLength = 0;
|
||||
this.messageHandlers = [];
|
||||
this.currentPayloadLength = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unmask received data.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.unmask = function (mask, buf, binary) {
|
||||
if (mask != null && buf != null) bufferUtil.unmask(buf, mask);
|
||||
if (binary) return buf;
|
||||
return buf != null ? buf.toString('utf8') : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.error = function (reason, protocolErrorCode) {
|
||||
if (this.dead) return;
|
||||
this.reset();
|
||||
if(typeof reason == 'string'){
|
||||
this.onerror(new Error(reason), protocolErrorCode);
|
||||
}
|
||||
else if(reason.constructor == Error){
|
||||
this.onerror(reason, protocolErrorCode);
|
||||
}
|
||||
else{
|
||||
this.onerror(new Error("An error occured"),protocolErrorCode);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute message handler buffers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.flush = function() {
|
||||
if (this.processing || this.dead) return;
|
||||
|
||||
var handler = this.messageHandlers.shift();
|
||||
if (!handler) return;
|
||||
|
||||
this.processing = true;
|
||||
var self = this;
|
||||
|
||||
handler(function() {
|
||||
self.processing = false;
|
||||
self.flush();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply extensions to message
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Receiver.prototype.applyExtensions = function(messageBuffer, fin, compressed, callback) {
|
||||
var self = this;
|
||||
if (compressed) {
|
||||
this.extensions[PerMessageDeflate.extensionName].decompress(messageBuffer, fin, function(err, buffer) {
|
||||
if (self.dead) return;
|
||||
if (err) {
|
||||
callback(new Error('invalid compressed data'));
|
||||
return;
|
||||
}
|
||||
callback(null, buffer);
|
||||
});
|
||||
} else {
|
||||
callback(null, messageBuffer);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks payload size, disconnects socket when it exceeds maxPayload
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
Receiver.prototype.maxPayloadExceeded = function(length) {
|
||||
if (this.maxPayload=== undefined || this.maxPayload === null || this.maxPayload < 1) {
|
||||
return false;
|
||||
}
|
||||
var fullLength = this.currentPayloadLength + length;
|
||||
if (fullLength < this.maxPayload) {
|
||||
this.currentPayloadLength = fullLength;
|
||||
return false;
|
||||
}
|
||||
this.error('payload cannot exceed ' + this.maxPayload + ' bytes', 1009);
|
||||
this.messageBuffer=[];
|
||||
this.cleanup();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer utilities
|
||||
*/
|
||||
|
||||
function readUInt16BE(start) {
|
||||
return (this[start]<<8) +
|
||||
this[start+1];
|
||||
}
|
||||
|
||||
function readUInt32BE(start) {
|
||||
return (this[start]<<24) +
|
||||
(this[start+1]<<16) +
|
||||
(this[start+2]<<8) +
|
||||
this[start+3];
|
||||
}
|
||||
|
||||
function fastCopy(length, srcBuffer, dstBuffer, dstOffset) {
|
||||
switch (length) {
|
||||
default: srcBuffer.copy(dstBuffer, dstOffset, 0, length); break;
|
||||
case 16: dstBuffer[dstOffset+15] = srcBuffer[15];
|
||||
case 15: dstBuffer[dstOffset+14] = srcBuffer[14];
|
||||
case 14: dstBuffer[dstOffset+13] = srcBuffer[13];
|
||||
case 13: dstBuffer[dstOffset+12] = srcBuffer[12];
|
||||
case 12: dstBuffer[dstOffset+11] = srcBuffer[11];
|
||||
case 11: dstBuffer[dstOffset+10] = srcBuffer[10];
|
||||
case 10: dstBuffer[dstOffset+9] = srcBuffer[9];
|
||||
case 9: dstBuffer[dstOffset+8] = srcBuffer[8];
|
||||
case 8: dstBuffer[dstOffset+7] = srcBuffer[7];
|
||||
case 7: dstBuffer[dstOffset+6] = srcBuffer[6];
|
||||
case 6: dstBuffer[dstOffset+5] = srcBuffer[5];
|
||||
case 5: dstBuffer[dstOffset+4] = srcBuffer[4];
|
||||
case 4: dstBuffer[dstOffset+3] = srcBuffer[3];
|
||||
case 3: dstBuffer[dstOffset+2] = srcBuffer[2];
|
||||
case 2: dstBuffer[dstOffset+1] = srcBuffer[1];
|
||||
case 1: dstBuffer[dstOffset] = srcBuffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
var cloned = {};
|
||||
for (var k in obj) {
|
||||
if (obj.hasOwnProperty(k)) {
|
||||
cloned[k] = obj[k];
|
||||
}
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opcode handlers
|
||||
*/
|
||||
|
||||
var opcodes = {
|
||||
// text
|
||||
'1': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
if (self.maxPayloadExceeded(firstLength)){
|
||||
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['1'].getData.call(self, firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expectHeader(2, function(data) {
|
||||
var length = readUInt16BE.call(data, 0);
|
||||
if (self.maxPayloadExceeded(length)){
|
||||
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['1'].getData.call(self, length);
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expectHeader(8, function(data) {
|
||||
if (readUInt32BE.call(data, 0) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
|
||||
return;
|
||||
}
|
||||
var length = readUInt32BE.call(data, 4);
|
||||
if (self.maxPayloadExceeded(length)){
|
||||
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['1'].getData.call(self, readUInt32BE.call(data, 4));
|
||||
});
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['1'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['1'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
var packet = this.unmask(mask, data, true) || new Buffer(0);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
|
||||
if (err) {
|
||||
if(err.type===1009){
|
||||
return self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
|
||||
}
|
||||
return self.error(err.message, 1007);
|
||||
}
|
||||
if (buffer != null) {
|
||||
if( self.maxPayload==0 || (self.maxPayload > 0 && (self.currentMessageLength + buffer.length) < self.maxPayload) ){
|
||||
self.currentMessage.push(buffer);
|
||||
}
|
||||
else{
|
||||
self.currentMessage=null;
|
||||
self.currentMessage = [];
|
||||
self.currentMessageLength = 0;
|
||||
self.error(new Error('Maximum payload exceeded. maxPayload: '+self.maxPayload), 1009);
|
||||
return;
|
||||
}
|
||||
self.currentMessageLength += buffer.length;
|
||||
}
|
||||
if (state.lastFragment) {
|
||||
var messageBuffer = Buffer.concat(self.currentMessage);
|
||||
self.currentMessage = [];
|
||||
self.currentMessageLength = 0;
|
||||
if (!isValidUTF8(messageBuffer)) {
|
||||
self.error('invalid utf8 sequence', 1007);
|
||||
return;
|
||||
}
|
||||
self.ontext(messageBuffer.toString('utf8'), {masked: state.masked, buffer: messageBuffer});
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// binary
|
||||
'2': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
if (self.maxPayloadExceeded(firstLength)){
|
||||
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['2'].getData.call(self, firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expectHeader(2, function(data) {
|
||||
var length = readUInt16BE.call(data, 0);
|
||||
if (self.maxPayloadExceeded(length)){
|
||||
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['2'].getData.call(self, length);
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expectHeader(8, function(data) {
|
||||
if (readUInt32BE.call(data, 0) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported', 1008);
|
||||
return;
|
||||
}
|
||||
var length = readUInt32BE.call(data, 4, true);
|
||||
if (self.maxPayloadExceeded(length)){
|
||||
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
|
||||
return;
|
||||
}
|
||||
opcodes['2'].getData.call(self, length);
|
||||
});
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['2'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['2'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
var packet = this.unmask(mask, data, true) || new Buffer(0);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
|
||||
if (err) {
|
||||
if(err.type===1009){
|
||||
return self.error('Max payload exceeded in compressed binary message. Aborting...', 1009);
|
||||
}
|
||||
return self.error(err.message, 1007);
|
||||
}
|
||||
if (buffer != null) {
|
||||
if( self.maxPayload==0 || (self.maxPayload > 0 && (self.currentMessageLength + buffer.length) < self.maxPayload) ){
|
||||
self.currentMessage.push(buffer);
|
||||
}
|
||||
else{
|
||||
self.currentMessage=null;
|
||||
self.currentMessage = [];
|
||||
self.currentMessageLength = 0;
|
||||
self.error(new Error('Maximum payload exceeded'), 1009);
|
||||
return;
|
||||
}
|
||||
self.currentMessageLength += buffer.length;
|
||||
}
|
||||
if (state.lastFragment) {
|
||||
var messageBuffer = Buffer.concat(self.currentMessage);
|
||||
self.currentMessage = [];
|
||||
self.currentMessageLength = 0;
|
||||
self.onbinary(messageBuffer, {masked: state.masked, buffer: messageBuffer});
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// close
|
||||
'8': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented close is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['8'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['8'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['8'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = self.unmask(mask, data, true);
|
||||
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function() {
|
||||
if (data && data.length == 1) {
|
||||
self.error('close packets with data must be at least two bytes long', 1002);
|
||||
return;
|
||||
}
|
||||
var code = data && data.length > 1 ? readUInt16BE.call(data, 0) : 1000;
|
||||
if (!ErrorCodes.isValidErrorCode(code)) {
|
||||
self.error('invalid error code', 1002);
|
||||
return;
|
||||
}
|
||||
var message = '';
|
||||
if (data && data.length > 2) {
|
||||
var messageBuffer = data.slice(2);
|
||||
if (!isValidUTF8(messageBuffer)) {
|
||||
self.error('invalid utf8 sequence', 1007);
|
||||
return;
|
||||
}
|
||||
message = messageBuffer.toString('utf8');
|
||||
}
|
||||
self.onclose(code, message, {masked: state.masked});
|
||||
self.reset();
|
||||
});
|
||||
this.flush();
|
||||
},
|
||||
},
|
||||
// ping
|
||||
'9': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented ping is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['9'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (self.state.masked) {
|
||||
self.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['9'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['9'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = this.unmask(mask, data, true);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.onping(data, {masked: state.masked, binary: true});
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
},
|
||||
// pong
|
||||
'10': {
|
||||
start: function(data) {
|
||||
var self = this;
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented pong is not supported', 1002);
|
||||
return;
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
opcodes['10'].getData.call(self, firstLength);
|
||||
}
|
||||
else {
|
||||
self.error('control frames cannot have more than 125 bytes of data', 1002);
|
||||
}
|
||||
},
|
||||
getData: function(length) {
|
||||
var self = this;
|
||||
if (this.state.masked) {
|
||||
this.expectHeader(4, function(data) {
|
||||
var mask = data;
|
||||
self.expectData(length, function(data) {
|
||||
opcodes['10'].finish.call(self, mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.expectData(length, function(data) {
|
||||
opcodes['10'].finish.call(self, null, data);
|
||||
});
|
||||
}
|
||||
},
|
||||
finish: function(mask, data) {
|
||||
var self = this;
|
||||
data = self.unmask(mask, data, true);
|
||||
var state = clone(this.state);
|
||||
this.messageHandlers.push(function(callback) {
|
||||
self.onpong(data, {masked: state.masked, binary: true});
|
||||
callback();
|
||||
});
|
||||
this.flush();
|
||||
this.endPacket();
|
||||
}
|
||||
}
|
||||
}
|
124
node_modules/engine.io-client/node_modules/ws/lib/Sender.hixie.js
generated
vendored
Normal file
124
node_modules/engine.io-client/node_modules/ws/lib/Sender.hixie.js
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var events = require('events')
|
||||
, util = require('util')
|
||||
, EventEmitter = events.EventEmitter;
|
||||
|
||||
/**
|
||||
* Hixie Sender implementation
|
||||
*/
|
||||
|
||||
function Sender(socket) {
|
||||
if (this instanceof Sender === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this.socket = socket;
|
||||
this.continuationFrame = false;
|
||||
this.isClosed = false;
|
||||
}
|
||||
|
||||
module.exports = Sender;
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(Sender, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Frames and writes data.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.send = function(data, options, cb) {
|
||||
if (this.isClosed) return;
|
||||
|
||||
var isString = typeof data == 'string'
|
||||
, length = isString ? Buffer.byteLength(data) : data.length
|
||||
, lengthbytes = (length > 127) ? 2 : 1 // assume less than 2**14 bytes
|
||||
, writeStartMarker = this.continuationFrame == false
|
||||
, writeEndMarker = !options || !(typeof options.fin != 'undefined' && !options.fin)
|
||||
, buffer = new Buffer((writeStartMarker ? ((options && options.binary) ? (1 + lengthbytes) : 1) : 0) + length + ((writeEndMarker && !(options && options.binary)) ? 1 : 0))
|
||||
, offset = writeStartMarker ? 1 : 0;
|
||||
|
||||
if (writeStartMarker) {
|
||||
if (options && options.binary) {
|
||||
buffer.write('\x80', 'binary');
|
||||
// assume length less than 2**14 bytes
|
||||
if (lengthbytes > 1)
|
||||
buffer.write(String.fromCharCode(128+length/128), offset++, 'binary');
|
||||
buffer.write(String.fromCharCode(length&0x7f), offset++, 'binary');
|
||||
} else
|
||||
buffer.write('\x00', 'binary');
|
||||
}
|
||||
|
||||
if (isString) buffer.write(data, offset, 'utf8');
|
||||
else data.copy(buffer, offset, 0);
|
||||
|
||||
if (writeEndMarker) {
|
||||
if (options && options.binary) {
|
||||
// sending binary, not writing end marker
|
||||
} else
|
||||
buffer.write('\xff', offset + length, 'binary');
|
||||
this.continuationFrame = false;
|
||||
}
|
||||
else this.continuationFrame = true;
|
||||
|
||||
try {
|
||||
this.socket.write(buffer, 'binary', cb);
|
||||
} catch (e) {
|
||||
this.error(e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a close instruction to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.close = function(code, data, mask, cb) {
|
||||
if (this.isClosed) return;
|
||||
this.isClosed = true;
|
||||
try {
|
||||
if (this.continuationFrame) this.socket.write(new Buffer([0xff], 'binary'));
|
||||
this.socket.write(new Buffer([0xff, 0x00]), 'binary', cb);
|
||||
} catch (e) {
|
||||
this.error(e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping message to the remote party. Not available for hixie.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.ping = function(data, options) {};
|
||||
|
||||
/**
|
||||
* Sends a pong message to the remote party. Not available for hixie.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.pong = function(data, options) {};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.error = function (reason) {
|
||||
this.emit('error', reason);
|
||||
return this;
|
||||
};
|
310
node_modules/engine.io-client/node_modules/ws/lib/Sender.js
generated
vendored
Normal file
310
node_modules/engine.io-client/node_modules/ws/lib/Sender.js
generated
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var events = require('events')
|
||||
, util = require('util')
|
||||
, crypto = require('crypto')
|
||||
, EventEmitter = events.EventEmitter
|
||||
, ErrorCodes = require('./ErrorCodes')
|
||||
, bufferUtil = require('./BufferUtil')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate');
|
||||
|
||||
/**
|
||||
* HyBi Sender implementation
|
||||
*/
|
||||
|
||||
function Sender(socket, extensions) {
|
||||
if (this instanceof Sender === false) {
|
||||
throw new TypeError("Classes can't be function-called");
|
||||
}
|
||||
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this._socket = socket;
|
||||
this.extensions = extensions || {};
|
||||
this.firstFragment = true;
|
||||
this.compress = false;
|
||||
this.messageHandlers = [];
|
||||
this.processing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(Sender, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Sends a close instruction to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.close = function(code, data, mask, cb) {
|
||||
if (typeof code !== 'undefined') {
|
||||
if (typeof code !== 'number' ||
|
||||
!ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number');
|
||||
}
|
||||
code = code || 1000;
|
||||
var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0));
|
||||
writeUInt16BE.call(dataBuffer, code, 0);
|
||||
if (dataBuffer.length > 2) dataBuffer.write(data, 2);
|
||||
|
||||
var self = this;
|
||||
this.messageHandlers.push(function() {
|
||||
self.frameAndSend(0x8, dataBuffer, true, mask);
|
||||
if (typeof cb == 'function') cb();
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping message to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.ping = function(data, options) {
|
||||
var mask = options && options.mask;
|
||||
var self = this;
|
||||
this.messageHandlers.push(function() {
|
||||
self.frameAndSend(0x9, data || '', true, mask);
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a pong message to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.pong = function(data, options) {
|
||||
var mask = options && options.mask;
|
||||
var self = this;
|
||||
this.messageHandlers.push(function() {
|
||||
self.frameAndSend(0xa, data || '', true, mask);
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends text or binary data to the remote party.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Sender.prototype.send = function(data, options, cb) {
|
||||
var finalFragment = options && options.fin === false ? false : true;
|
||||
var mask = options && options.mask;
|
||||
var compress = options && options.compress;
|
||||
var opcode = options && options.binary ? 2 : 1;
|
||||
if (this.firstFragment === false) {
|
||||
opcode = 0;
|
||||
compress = false;
|
||||
} else {
|
||||
this.firstFragment = false;
|
||||
this.compress = compress;
|
||||
}
|
||||
if (finalFragment) this.firstFragment = true
|
||||
|
||||
var compressFragment = this.compress;
|
||||
|
||||
var self = this;
|
||||
this.messageHandlers.push(function() {
|
||||
if (!data || !compressFragment) {
|
||||
self.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
self.processing = true;
|
||||
self.applyExtensions(data, finalFragment, compressFragment, function(err, data) {
|
||||
if (err) {
|
||||
if (typeof cb == 'function') cb(err);
|
||||
else self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
self.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
|
||||
self.processing = false;
|
||||
self.flush();
|
||||
});
|
||||
});
|
||||
this.flush();
|
||||
};
|
||||
|
||||
/**
|
||||
* Frames and sends a piece of data according to the HyBi WebSocket protocol.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, compressed, cb) {
|
||||
var canModifyData = false;
|
||||
|
||||
if (!data) {
|
||||
try {
|
||||
this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(data)) {
|
||||
canModifyData = true;
|
||||
if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) {
|
||||
data = getArrayBuffer(data);
|
||||
} else {
|
||||
//
|
||||
// If people want to send a number, this would allocate the number in
|
||||
// bytes as memory size instead of storing the number as buffer value. So
|
||||
// we need to transform it to string in order to prevent possible
|
||||
// vulnerabilities / memory attacks.
|
||||
//
|
||||
if (typeof data === 'number') data = data.toString();
|
||||
|
||||
data = new Buffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
var dataLength = data.length
|
||||
, dataOffset = maskData ? 6 : 2
|
||||
, secondByte = dataLength;
|
||||
|
||||
if (dataLength >= 65536) {
|
||||
dataOffset += 8;
|
||||
secondByte = 127;
|
||||
}
|
||||
else if (dataLength > 125) {
|
||||
dataOffset += 2;
|
||||
secondByte = 126;
|
||||
}
|
||||
|
||||
var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData);
|
||||
var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
|
||||
var outputBuffer = new Buffer(totalLength);
|
||||
outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
|
||||
if (compressed) outputBuffer[0] |= 0x40;
|
||||
|
||||
switch (secondByte) {
|
||||
case 126:
|
||||
writeUInt16BE.call(outputBuffer, dataLength, 2);
|
||||
break;
|
||||
case 127:
|
||||
writeUInt32BE.call(outputBuffer, 0, 2);
|
||||
writeUInt32BE.call(outputBuffer, dataLength, 6);
|
||||
}
|
||||
|
||||
if (maskData) {
|
||||
outputBuffer[1] = secondByte | 0x80;
|
||||
var mask = getRandomMask();
|
||||
outputBuffer[dataOffset - 4] = mask[0];
|
||||
outputBuffer[dataOffset - 3] = mask[1];
|
||||
outputBuffer[dataOffset - 2] = mask[2];
|
||||
outputBuffer[dataOffset - 1] = mask[3];
|
||||
if (mergeBuffers) {
|
||||
bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bufferUtil.mask(data, mask, data, 0, dataLength);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary');
|
||||
this._socket.write(data, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputBuffer[1] = secondByte;
|
||||
if (mergeBuffers) {
|
||||
data.copy(outputBuffer, dataOffset);
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
this._socket.write(outputBuffer, 'binary');
|
||||
this._socket.write(data, 'binary', cb);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof cb == 'function') cb(e);
|
||||
else this.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute message handler buffers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.flush = function() {
|
||||
while (!this.processing && this.messageHandlers.length) {
|
||||
this.messageHandlers.shift()();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply extensions to message
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Sender.prototype.applyExtensions = function(data, fin, compress, callback) {
|
||||
if ((data.buffer || data) instanceof ArrayBuffer) {
|
||||
data = getArrayBuffer(data);
|
||||
}
|
||||
this.extensions[PerMessageDeflate.extensionName].compress(data, fin, callback);
|
||||
};
|
||||
|
||||
module.exports = Sender;
|
||||
|
||||
function writeUInt16BE(value, offset) {
|
||||
this[offset] = (value & 0xff00)>>8;
|
||||
this[offset+1] = value & 0xff;
|
||||
}
|
||||
|
||||
function writeUInt32BE(value, offset) {
|
||||
this[offset] = (value & 0xff000000)>>24;
|
||||
this[offset+1] = (value & 0xff0000)>>16;
|
||||
this[offset+2] = (value & 0xff00)>>8;
|
||||
this[offset+3] = value & 0xff;
|
||||
}
|
||||
|
||||
function getArrayBuffer(data) {
|
||||
// data is either an ArrayBuffer or ArrayBufferView.
|
||||
var array = new Uint8Array(data.buffer || data)
|
||||
, l = data.byteLength || data.length
|
||||
, o = data.byteOffset || 0
|
||||
, buffer = new Buffer(l);
|
||||
for (var i = 0; i < l; ++i) {
|
||||
buffer[i] = array[o+i];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function getRandomMask() {
|
||||
return crypto.randomBytes(4);
|
||||
}
|
11
node_modules/engine.io-client/node_modules/ws/lib/Validation.fallback.js
generated
vendored
Normal file
11
node_modules/engine.io-client/node_modules/ws/lib/Validation.fallback.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
exports.Validation = {
|
||||
isValidUTF8: function(buffer) {
|
||||
return true;
|
||||
}
|
||||
};
|
19
node_modules/engine.io-client/node_modules/ws/lib/Validation.js
generated
vendored
Normal file
19
node_modules/engine.io-client/node_modules/ws/lib/Validation.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var isValidUTF8;
|
||||
|
||||
try {
|
||||
isValidUTF8 = require('utf-8-validate');
|
||||
} catch (e) {
|
||||
isValidUTF8 = require('./Validation.fallback');
|
||||
}
|
||||
|
||||
module.exports = typeof isValidUTF8 === 'object'
|
||||
? isValidUTF8.Validation.isValidUTF8
|
||||
: isValidUTF8;
|
987
node_modules/engine.io-client/node_modules/ws/lib/WebSocket.js
generated
vendored
Normal file
987
node_modules/engine.io-client/node_modules/ws/lib/WebSocket.js
generated
vendored
Normal file
@ -0,0 +1,987 @@
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var url = require('url')
|
||||
, util = require('util')
|
||||
, http = require('http')
|
||||
, https = require('https')
|
||||
, crypto = require('crypto')
|
||||
, stream = require('stream')
|
||||
, Ultron = require('ultron')
|
||||
, Options = require('options')
|
||||
, Sender = require('./Sender')
|
||||
, Receiver = require('./Receiver')
|
||||
, SenderHixie = require('./Sender.hixie')
|
||||
, ReceiverHixie = require('./Receiver.hixie')
|
||||
, Extensions = require('./Extensions')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate')
|
||||
, EventEmitter = require('events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
|
||||
// Default protocol version
|
||||
|
||||
var protocolVersion = 13;
|
||||
|
||||
// Close timeout
|
||||
|
||||
var closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly
|
||||
|
||||
/**
|
||||
* WebSocket implementation
|
||||
*
|
||||
* @constructor
|
||||
* @param {String} address Connection address.
|
||||
* @param {String|Array} protocols WebSocket protocols.
|
||||
* @param {Object} options Additional connection options.
|
||||
* @api public
|
||||
*/
|
||||
function WebSocket(address, protocols, options) {
|
||||
if (this instanceof WebSocket === false) {
|
||||
return new WebSocket(address, protocols, options);
|
||||
}
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) {
|
||||
// accept the "options" Object as the 2nd argument
|
||||
options = protocols;
|
||||
protocols = null;
|
||||
}
|
||||
|
||||
if ('string' === typeof protocols) {
|
||||
protocols = [ protocols ];
|
||||
}
|
||||
|
||||
if (!Array.isArray(protocols)) {
|
||||
protocols = [];
|
||||
}
|
||||
|
||||
this._socket = null;
|
||||
this._ultron = null;
|
||||
this._closeReceived = false;
|
||||
this.bytesReceived = 0;
|
||||
this.readyState = null;
|
||||
this.supports = {};
|
||||
this.extensions = {};
|
||||
this._binaryType = 'nodebuffer';
|
||||
|
||||
if (Array.isArray(address)) {
|
||||
initAsServerClient.apply(this, address.concat(options));
|
||||
} else {
|
||||
initAsClient.apply(this, [address, protocols, options]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
util.inherits(WebSocket, EventEmitter);
|
||||
|
||||
/**
|
||||
* Ready States
|
||||
*/
|
||||
["CONNECTING", "OPEN", "CLOSING", "CLOSED"].forEach(function each(state, index) {
|
||||
WebSocket.prototype[state] = WebSocket[state] = index;
|
||||
});
|
||||
|
||||
/**
|
||||
* Gracefully closes the connection, after sending a description message to the server
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.close = function close(code, data) {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
if (this.readyState === WebSocket.CONNECTING) {
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.readyState === WebSocket.CLOSING) {
|
||||
if (this._closeReceived && this._isServer) {
|
||||
this.terminate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
try {
|
||||
this.readyState = WebSocket.CLOSING;
|
||||
this._closeCode = code;
|
||||
this._closeMessage = data;
|
||||
var mask = !this._isServer;
|
||||
this._sender.close(code, data, mask, function(err) {
|
||||
if (err) self.emit('error', err);
|
||||
|
||||
if (self._closeReceived && self._isServer) {
|
||||
self.terminate();
|
||||
} else {
|
||||
// ensure that the connection is cleaned up even when no response of closing handshake.
|
||||
clearTimeout(self._closeTimer);
|
||||
self._closeTimer = setTimeout(cleanupWebsocketResources.bind(self, true), closeTimeout);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.emit('error', e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause the client stream
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.pause = function pauser() {
|
||||
if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
|
||||
return this._socket.pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a ping
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean
|
||||
* @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.ping = function ping(data, options, dontFailWhenClosed) {
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (dontFailWhenClosed === true) return;
|
||||
throw new Error('not opened');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
|
||||
this._sender.ping(data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a pong
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean
|
||||
* @param {boolean} dontFailWhenClosed indicates whether or not to throw if the connection isnt open
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.pong = function(data, options, dontFailWhenClosed) {
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (dontFailWhenClosed === true) return;
|
||||
throw new Error('not opened');
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
|
||||
this._sender.pong(data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resume the client stream
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.resume = function resume() {
|
||||
if (this.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
|
||||
return this._socket.resume();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a piece of data
|
||||
*
|
||||
* @param {Object} data to be sent to the server
|
||||
* @param {Object} Members - mask: boolean, binary: boolean, compress: boolean
|
||||
* @param {function} Optional callback which is executed after the send completes
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.send = function send(data, options, cb) {
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else throw new Error('not opened');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data) data = '';
|
||||
if (this._queue) {
|
||||
var self = this;
|
||||
this._queue.push(function() { self.send(data, options, cb); });
|
||||
return;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
options.fin = true;
|
||||
|
||||
if (typeof options.binary === 'undefined') {
|
||||
options.binary = (data instanceof ArrayBuffer || data instanceof Buffer ||
|
||||
data instanceof Uint8Array ||
|
||||
data instanceof Uint16Array ||
|
||||
data instanceof Uint32Array ||
|
||||
data instanceof Int8Array ||
|
||||
data instanceof Int16Array ||
|
||||
data instanceof Int32Array ||
|
||||
data instanceof Float32Array ||
|
||||
data instanceof Float64Array);
|
||||
}
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
if (typeof options.compress === 'undefined') options.compress = true;
|
||||
if (!this.extensions[PerMessageDeflate.extensionName]) {
|
||||
options.compress = false;
|
||||
}
|
||||
|
||||
var readable = typeof stream.Readable === 'function'
|
||||
? stream.Readable
|
||||
: stream.Stream;
|
||||
|
||||
if (data instanceof readable) {
|
||||
startQueue(this);
|
||||
var self = this;
|
||||
|
||||
sendStream(this, data, options, function send(error) {
|
||||
process.nextTick(function tock() {
|
||||
executeQueueSends(self);
|
||||
});
|
||||
|
||||
if (typeof cb === 'function') cb(error);
|
||||
});
|
||||
} else {
|
||||
this._sender.send(data, options, cb);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Streams data through calls to a user supplied function
|
||||
*
|
||||
* @param {Object} Members - mask: boolean, binary: boolean, compress: boolean
|
||||
* @param {function} 'function (error, send)' which is executed on successive ticks of which send is 'function (data, final)'.
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.stream = function stream(options, cb) {
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (typeof cb !== 'function') throw new Error('callback must be provided');
|
||||
|
||||
if (this.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else throw new Error('not opened');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._queue) {
|
||||
this._queue.push(function () { self.stream(options, cb); });
|
||||
return;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (typeof options.mask === 'undefined') options.mask = !this._isServer;
|
||||
if (typeof options.compress === 'undefined') options.compress = true;
|
||||
if (!this.extensions[PerMessageDeflate.extensionName]) {
|
||||
options.compress = false;
|
||||
}
|
||||
|
||||
startQueue(this);
|
||||
|
||||
function send(data, final) {
|
||||
try {
|
||||
if (self.readyState !== WebSocket.OPEN) throw new Error('not opened');
|
||||
options.fin = final === true;
|
||||
self._sender.send(data, options);
|
||||
if (!final) process.nextTick(cb.bind(null, null, send));
|
||||
else executeQueueSends(self);
|
||||
} catch (e) {
|
||||
if (typeof cb === 'function') cb(e);
|
||||
else {
|
||||
delete self._queue;
|
||||
self.emit('error', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.nextTick(cb.bind(null, null, send));
|
||||
};
|
||||
|
||||
/**
|
||||
* Immediately shuts down the connection
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.terminate = function terminate() {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
if (this._socket) {
|
||||
this.readyState = WebSocket.CLOSING;
|
||||
|
||||
// End the connection
|
||||
try { this._socket.end(); }
|
||||
catch (e) {
|
||||
// Socket error during end() call, so just destroy it right now
|
||||
cleanupWebsocketResources.call(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a timeout to ensure that the connection is completely
|
||||
// cleaned up within 30 seconds, even if the clean close procedure
|
||||
// fails for whatever reason
|
||||
// First cleanup any pre-existing timeout from an earlier "terminate" call,
|
||||
// if one exists. Otherwise terminate calls in quick succession will leak timeouts
|
||||
// and hold the program open for `closeTimout` time.
|
||||
if (this._closeTimer) { clearTimeout(this._closeTimer); }
|
||||
this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout);
|
||||
} else if (this.readyState === WebSocket.CONNECTING) {
|
||||
cleanupWebsocketResources.call(this, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose bufferedAmount
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
Object.defineProperty(WebSocket.prototype, 'bufferedAmount', {
|
||||
get: function get() {
|
||||
var amount = 0;
|
||||
if (this._socket) {
|
||||
amount = this._socket.bufferSize || 0;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Expose binaryType
|
||||
*
|
||||
* This deviates from the W3C interface since ws doesn't support the required
|
||||
* default "blob" type (instead we define a custom "nodebuffer" type).
|
||||
*
|
||||
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||||
* @api public
|
||||
*/
|
||||
Object.defineProperty(WebSocket.prototype, 'binaryType', {
|
||||
get: function get() {
|
||||
return this._binaryType;
|
||||
},
|
||||
set: function set(type) {
|
||||
if (type === 'arraybuffer' || type === 'nodebuffer')
|
||||
this._binaryType = type;
|
||||
else
|
||||
throw new SyntaxError('unsupported binaryType: must be either "nodebuffer" or "arraybuffer"');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Emulates the W3C Browser based WebSocket interface using function members.
|
||||
*
|
||||
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||||
* @api public
|
||||
*/
|
||||
['open', 'error', 'close', 'message'].forEach(function(method) {
|
||||
Object.defineProperty(WebSocket.prototype, 'on' + method, {
|
||||
/**
|
||||
* Returns the current listener
|
||||
*
|
||||
* @returns {Mixed} the set function or undefined
|
||||
* @api public
|
||||
*/
|
||||
get: function get() {
|
||||
var listener = this.listeners(method)[0];
|
||||
return listener ? (listener._listener ? listener._listener : listener) : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start listening for events
|
||||
*
|
||||
* @param {Function} listener the listener
|
||||
* @returns {Mixed} the set function or undefined
|
||||
* @api public
|
||||
*/
|
||||
set: function set(listener) {
|
||||
this.removeAllListeners(method);
|
||||
this.addEventListener(method, listener);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Emulates the W3C Browser based WebSocket interface using addEventListener.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en/DOM/element.addEventListener
|
||||
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||||
* @api public
|
||||
*/
|
||||
WebSocket.prototype.addEventListener = function(method, listener) {
|
||||
var target = this;
|
||||
|
||||
function onMessage (data, flags) {
|
||||
if (flags.binary && this.binaryType === 'arraybuffer')
|
||||
data = new Uint8Array(data).buffer;
|
||||
listener.call(target, new MessageEvent(data, !!flags.binary, target));
|
||||
}
|
||||
|
||||
function onClose (code, message) {
|
||||
listener.call(target, new CloseEvent(code, message, target));
|
||||
}
|
||||
|
||||
function onError (event) {
|
||||
event.type = 'error';
|
||||
event.target = target;
|
||||
listener.call(target, event);
|
||||
}
|
||||
|
||||
function onOpen () {
|
||||
listener.call(target, new OpenEvent(target));
|
||||
}
|
||||
|
||||
if (typeof listener === 'function') {
|
||||
if (method === 'message') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onMessage._listener = listener;
|
||||
this.on(method, onMessage);
|
||||
} else if (method === 'close') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onClose._listener = listener;
|
||||
this.on(method, onClose);
|
||||
} else if (method === 'error') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onError._listener = listener;
|
||||
this.on(method, onError);
|
||||
} else if (method === 'open') {
|
||||
// store a reference so we can return the original function from the
|
||||
// addEventListener hook
|
||||
onOpen._listener = listener;
|
||||
this.on(method, onOpen);
|
||||
} else {
|
||||
this.on(method, listener);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = WebSocket;
|
||||
module.exports.buildHostHeader = buildHostHeader
|
||||
|
||||
/**
|
||||
* W3C MessageEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function MessageEvent(dataArg, isBinary, target) {
|
||||
this.type = 'message';
|
||||
this.data = dataArg;
|
||||
this.target = target;
|
||||
this.binary = isBinary; // non-standard.
|
||||
}
|
||||
|
||||
/**
|
||||
* W3C CloseEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function CloseEvent(code, reason, target) {
|
||||
this.type = 'close';
|
||||
this.wasClean = (typeof code === 'undefined' || code === 1000);
|
||||
this.code = code;
|
||||
this.reason = reason;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* W3C OpenEvent
|
||||
*
|
||||
* @see http://www.w3.org/TR/html5/comms.html
|
||||
* @constructor
|
||||
* @api private
|
||||
*/
|
||||
function OpenEvent(target) {
|
||||
this.type = 'open';
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
// Append port number to Host header, only if specified in the url
|
||||
// and non-default
|
||||
function buildHostHeader(isSecure, hostname, port) {
|
||||
var headerHost = hostname;
|
||||
if (hostname) {
|
||||
if ((isSecure && (port != 443)) || (!isSecure && (port != 80))){
|
||||
headerHost = headerHost + ':' + port;
|
||||
}
|
||||
}
|
||||
return headerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entirely private apis,
|
||||
* which may or may not be bound to a sepcific WebSocket instance.
|
||||
*/
|
||||
function initAsServerClient(req, socket, upgradeHead, options) {
|
||||
options = new Options({
|
||||
protocolVersion: protocolVersion,
|
||||
protocol: null,
|
||||
extensions: {},
|
||||
maxPayload: 0
|
||||
}).merge(options);
|
||||
|
||||
// expose state properties
|
||||
this.protocol = options.value.protocol;
|
||||
this.protocolVersion = options.value.protocolVersion;
|
||||
this.extensions = options.value.extensions;
|
||||
this.supports.binary = (this.protocolVersion !== 'hixie-76');
|
||||
this.upgradeReq = req;
|
||||
this.readyState = WebSocket.CONNECTING;
|
||||
this._isServer = true;
|
||||
this.maxPayload = options.value.maxPayload;
|
||||
// establish connection
|
||||
if (options.value.protocolVersion === 'hixie-76') {
|
||||
establishConnection.call(this, ReceiverHixie, SenderHixie, socket, upgradeHead);
|
||||
} else {
|
||||
establishConnection.call(this, Receiver, Sender, socket, upgradeHead);
|
||||
}
|
||||
}
|
||||
|
||||
function initAsClient(address, protocols, options) {
|
||||
options = new Options({
|
||||
origin: null,
|
||||
protocolVersion: protocolVersion,
|
||||
host: null,
|
||||
headers: null,
|
||||
protocol: protocols.join(','),
|
||||
agent: null,
|
||||
|
||||
// ssl-related options
|
||||
pfx: null,
|
||||
key: null,
|
||||
passphrase: null,
|
||||
cert: null,
|
||||
ca: null,
|
||||
ciphers: null,
|
||||
rejectUnauthorized: null,
|
||||
perMessageDeflate: true,
|
||||
localAddress: null
|
||||
}).merge(options);
|
||||
|
||||
if (options.value.protocolVersion !== 8 && options.value.protocolVersion !== 13) {
|
||||
throw new Error('unsupported protocol version');
|
||||
}
|
||||
|
||||
// verify URL and establish http class
|
||||
var serverUrl = url.parse(address);
|
||||
var isUnixSocket = serverUrl.protocol === 'ws+unix:';
|
||||
if (!serverUrl.host && !isUnixSocket) throw new Error('invalid url');
|
||||
var isSecure = serverUrl.protocol === 'wss:' || serverUrl.protocol === 'https:';
|
||||
var httpObj = isSecure ? https : http;
|
||||
var port = serverUrl.port || (isSecure ? 443 : 80);
|
||||
var auth = serverUrl.auth;
|
||||
|
||||
// prepare extensions
|
||||
var extensionsOffer = {};
|
||||
var perMessageDeflate;
|
||||
if (options.value.perMessageDeflate) {
|
||||
perMessageDeflate = new PerMessageDeflate(typeof options.value.perMessageDeflate !== true ? options.value.perMessageDeflate : {}, false);
|
||||
extensionsOffer[PerMessageDeflate.extensionName] = perMessageDeflate.offer();
|
||||
}
|
||||
|
||||
// expose state properties
|
||||
this._isServer = false;
|
||||
this.url = address;
|
||||
this.protocolVersion = options.value.protocolVersion;
|
||||
this.supports.binary = (this.protocolVersion !== 'hixie-76');
|
||||
|
||||
// begin handshake
|
||||
var key = new Buffer(options.value.protocolVersion + '-' + Date.now()).toString('base64');
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
|
||||
var expectedServerKey = shasum.digest('base64');
|
||||
|
||||
var agent = options.value.agent;
|
||||
|
||||
var headerHost = buildHostHeader(isSecure, serverUrl.hostname, port)
|
||||
|
||||
var requestOptions = {
|
||||
port: port,
|
||||
host: serverUrl.hostname,
|
||||
headers: {
|
||||
'Connection': 'Upgrade',
|
||||
'Upgrade': 'websocket',
|
||||
'Host': headerHost,
|
||||
'Sec-WebSocket-Version': options.value.protocolVersion,
|
||||
'Sec-WebSocket-Key': key
|
||||
}
|
||||
};
|
||||
|
||||
// If we have basic auth.
|
||||
if (auth) {
|
||||
requestOptions.headers.Authorization = 'Basic ' + new Buffer(auth).toString('base64');
|
||||
}
|
||||
|
||||
if (options.value.protocol) {
|
||||
requestOptions.headers['Sec-WebSocket-Protocol'] = options.value.protocol;
|
||||
}
|
||||
|
||||
if (options.value.host) {
|
||||
requestOptions.headers.Host = options.value.host;
|
||||
}
|
||||
|
||||
if (options.value.headers) {
|
||||
for (var header in options.value.headers) {
|
||||
if (options.value.headers.hasOwnProperty(header)) {
|
||||
requestOptions.headers[header] = options.value.headers[header];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(extensionsOffer).length) {
|
||||
requestOptions.headers['Sec-WebSocket-Extensions'] = Extensions.format(extensionsOffer);
|
||||
}
|
||||
|
||||
if (options.isDefinedAndNonNull('pfx')
|
||||
|| options.isDefinedAndNonNull('key')
|
||||
|| options.isDefinedAndNonNull('passphrase')
|
||||
|| options.isDefinedAndNonNull('cert')
|
||||
|| options.isDefinedAndNonNull('ca')
|
||||
|| options.isDefinedAndNonNull('ciphers')
|
||||
|| options.isDefinedAndNonNull('rejectUnauthorized')) {
|
||||
|
||||
if (options.isDefinedAndNonNull('pfx')) requestOptions.pfx = options.value.pfx;
|
||||
if (options.isDefinedAndNonNull('key')) requestOptions.key = options.value.key;
|
||||
if (options.isDefinedAndNonNull('passphrase')) requestOptions.passphrase = options.value.passphrase;
|
||||
if (options.isDefinedAndNonNull('cert')) requestOptions.cert = options.value.cert;
|
||||
if (options.isDefinedAndNonNull('ca')) requestOptions.ca = options.value.ca;
|
||||
if (options.isDefinedAndNonNull('ciphers')) requestOptions.ciphers = options.value.ciphers;
|
||||
if (options.isDefinedAndNonNull('rejectUnauthorized')) requestOptions.rejectUnauthorized = options.value.rejectUnauthorized;
|
||||
|
||||
if (!agent) {
|
||||
// global agent ignores client side certificates
|
||||
agent = new httpObj.Agent(requestOptions);
|
||||
}
|
||||
}
|
||||
|
||||
requestOptions.path = serverUrl.path || '/';
|
||||
|
||||
if (agent) {
|
||||
requestOptions.agent = agent;
|
||||
}
|
||||
|
||||
if (isUnixSocket) {
|
||||
requestOptions.socketPath = serverUrl.pathname;
|
||||
}
|
||||
|
||||
if (options.value.localAddress) {
|
||||
requestOptions.localAddress = options.value.localAddress;
|
||||
}
|
||||
|
||||
if (options.value.origin) {
|
||||
if (options.value.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.value.origin;
|
||||
else requestOptions.headers.Origin = options.value.origin;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var req = httpObj.request(requestOptions);
|
||||
|
||||
req.on('error', function onerror(error) {
|
||||
self.emit('error', error);
|
||||
cleanupWebsocketResources.call(self, error);
|
||||
});
|
||||
|
||||
req.once('response', function response(res) {
|
||||
var error;
|
||||
|
||||
if (!self.emit('unexpected-response', req, res)) {
|
||||
error = new Error('unexpected server response (' + res.statusCode + ')');
|
||||
req.abort();
|
||||
self.emit('error', error);
|
||||
}
|
||||
|
||||
cleanupWebsocketResources.call(self, error);
|
||||
});
|
||||
|
||||
req.once('upgrade', function upgrade(res, socket, upgradeHead) {
|
||||
if (self.readyState === WebSocket.CLOSED) {
|
||||
// client closed before server accepted connection
|
||||
self.emit('close');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var serverKey = res.headers['sec-websocket-accept'];
|
||||
if (typeof serverKey === 'undefined' || serverKey !== expectedServerKey) {
|
||||
self.emit('error', 'invalid server key');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var serverProt = res.headers['sec-websocket-protocol'];
|
||||
var protList = (options.value.protocol || "").split(/, */);
|
||||
var protError = null;
|
||||
|
||||
if (!options.value.protocol && serverProt) {
|
||||
protError = 'server sent a subprotocol even though none requested';
|
||||
} else if (options.value.protocol && !serverProt) {
|
||||
protError = 'server sent no subprotocol even though requested';
|
||||
} else if (serverProt && protList.indexOf(serverProt) === -1) {
|
||||
protError = 'server responded with an invalid protocol';
|
||||
}
|
||||
|
||||
if (protError) {
|
||||
self.emit('error', protError);
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
} else if (serverProt) {
|
||||
self.protocol = serverProt;
|
||||
}
|
||||
|
||||
var serverExtensions = Extensions.parse(res.headers['sec-websocket-extensions']);
|
||||
if (perMessageDeflate && serverExtensions[PerMessageDeflate.extensionName]) {
|
||||
try {
|
||||
perMessageDeflate.accept(serverExtensions[PerMessageDeflate.extensionName]);
|
||||
} catch (err) {
|
||||
self.emit('error', 'invalid extension parameter');
|
||||
self.removeAllListeners();
|
||||
socket.end();
|
||||
return;
|
||||
}
|
||||
self.extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
||||
}
|
||||
|
||||
establishConnection.call(self, Receiver, Sender, socket, upgradeHead);
|
||||
|
||||
// perform cleanup on http resources
|
||||
req.removeAllListeners();
|
||||
req = null;
|
||||
agent = null;
|
||||
});
|
||||
|
||||
req.end();
|
||||
this.readyState = WebSocket.CONNECTING;
|
||||
}
|
||||
|
||||
function establishConnection(ReceiverClass, SenderClass, socket, upgradeHead) {
|
||||
var ultron = this._ultron = new Ultron(socket)
|
||||
, called = false
|
||||
, self = this;
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
|
||||
this._receiver = new ReceiverClass(this.extensions,this.maxPayload);
|
||||
this._socket = socket;
|
||||
|
||||
// socket cleanup handlers
|
||||
ultron.on('end', cleanupWebsocketResources.bind(this));
|
||||
ultron.on('close', cleanupWebsocketResources.bind(this));
|
||||
ultron.on('error', cleanupWebsocketResources.bind(this));
|
||||
|
||||
// ensure that the upgradeHead is added to the receiver
|
||||
function firstHandler(data) {
|
||||
if (called || self.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
called = true;
|
||||
socket.removeListener('data', firstHandler);
|
||||
ultron.on('data', realHandler);
|
||||
|
||||
if (upgradeHead && upgradeHead.length > 0) {
|
||||
realHandler(upgradeHead);
|
||||
upgradeHead = null;
|
||||
}
|
||||
|
||||
if (data) realHandler(data);
|
||||
}
|
||||
|
||||
// subsequent packets are pushed straight to the receiver
|
||||
function realHandler(data) {
|
||||
self.bytesReceived += data.length;
|
||||
self._receiver.add(data);
|
||||
}
|
||||
|
||||
ultron.on('data', firstHandler);
|
||||
|
||||
// if data was passed along with the http upgrade,
|
||||
// this will schedule a push of that on to the receiver.
|
||||
// this has to be done on next tick, since the caller
|
||||
// hasn't had a chance to set event handlers on this client
|
||||
// object yet.
|
||||
process.nextTick(firstHandler);
|
||||
|
||||
// receiver event handlers
|
||||
self._receiver.ontext = function ontext(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self.emit('message', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onbinary = function onbinary(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
flags.binary = true;
|
||||
self.emit('message', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onping = function onping(data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self.pong(data, {
|
||||
mask: !self._isServer,
|
||||
binary: flags.binary === true
|
||||
}, true);
|
||||
|
||||
self.emit('ping', data, flags);
|
||||
};
|
||||
|
||||
self._receiver.onpong = function onpong(data, flags) {
|
||||
self.emit('pong', data, flags || {});
|
||||
};
|
||||
|
||||
self._receiver.onclose = function onclose(code, data, flags) {
|
||||
flags = flags || {};
|
||||
|
||||
self._closeReceived = true;
|
||||
self.close(code, data);
|
||||
};
|
||||
|
||||
self._receiver.onerror = function onerror(reason, errorCode) {
|
||||
// close the connection when the receiver reports a HyBi error code
|
||||
self.close(typeof errorCode !== 'undefined' ? errorCode : 1002, '');
|
||||
self.emit('error', (reason instanceof Error) ? reason : (new Error(reason)));
|
||||
};
|
||||
|
||||
// finalize the client
|
||||
this._sender = new SenderClass(socket, this.extensions);
|
||||
this._sender.on('error', function onerror(error) {
|
||||
self.close(1002, '');
|
||||
self.emit('error', error);
|
||||
});
|
||||
|
||||
this.readyState = WebSocket.OPEN;
|
||||
this.emit('open');
|
||||
}
|
||||
|
||||
function startQueue(instance) {
|
||||
instance._queue = instance._queue || [];
|
||||
}
|
||||
|
||||
function executeQueueSends(instance) {
|
||||
var queue = instance._queue;
|
||||
if (typeof queue === 'undefined') return;
|
||||
|
||||
delete instance._queue;
|
||||
for (var i = 0, l = queue.length; i < l; ++i) {
|
||||
queue[i]();
|
||||
}
|
||||
}
|
||||
|
||||
function sendStream(instance, stream, options, cb) {
|
||||
stream.on('data', function incoming(data) {
|
||||
if (instance.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else {
|
||||
delete instance._queue;
|
||||
instance.emit('error', new Error('not opened'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
options.fin = false;
|
||||
instance._sender.send(data, options);
|
||||
});
|
||||
|
||||
stream.on('end', function end() {
|
||||
if (instance.readyState !== WebSocket.OPEN) {
|
||||
if (typeof cb === 'function') cb(new Error('not opened'));
|
||||
else {
|
||||
delete instance._queue;
|
||||
instance.emit('error', new Error('not opened'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
options.fin = true;
|
||||
instance._sender.send(null, options);
|
||||
|
||||
if (typeof cb === 'function') cb(null);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupWebsocketResources(error) {
|
||||
if (this.readyState === WebSocket.CLOSED) return;
|
||||
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
|
||||
clearTimeout(this._closeTimer);
|
||||
this._closeTimer = null;
|
||||
|
||||
// If the connection was closed abnormally (with an error), or if
|
||||
// the close control frame was not received then the close code
|
||||
// must default to 1006.
|
||||
if (error || !this._closeReceived) {
|
||||
this._closeCode = 1006;
|
||||
}
|
||||
this.emit('close', this._closeCode || 1000, this._closeMessage || '');
|
||||
|
||||
if (this._socket) {
|
||||
if (this._ultron) this._ultron.destroy();
|
||||
this._socket.on('error', function onerror() {
|
||||
try { this.destroy(); }
|
||||
catch (e) {}
|
||||
});
|
||||
|
||||
try {
|
||||
if (!error) this._socket.end();
|
||||
else this._socket.destroy();
|
||||
} catch (e) { /* Ignore termination errors */ }
|
||||
|
||||
this._socket = null;
|
||||
this._ultron = null;
|
||||
}
|
||||
|
||||
if (this._sender) {
|
||||
this._sender.removeAllListeners();
|
||||
this._sender = null;
|
||||
}
|
||||
|
||||
if (this._receiver) {
|
||||
this._receiver.cleanup();
|
||||
this._receiver = null;
|
||||
}
|
||||
|
||||
if (this.extensions[PerMessageDeflate.extensionName]) {
|
||||
this.extensions[PerMessageDeflate.extensionName].cleanup();
|
||||
}
|
||||
|
||||
this.extensions = null;
|
||||
|
||||
this.removeAllListeners();
|
||||
this.on('error', function onerror() {}); // catch all errors after this
|
||||
delete this._queue;
|
||||
}
|
554
node_modules/engine.io-client/node_modules/ws/lib/WebSocketServer.js
generated
vendored
Normal file
554
node_modules/engine.io-client/node_modules/ws/lib/WebSocketServer.js
generated
vendored
Normal file
@ -0,0 +1,554 @@
|
||||
/*!
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
var util = require('util')
|
||||
, events = require('events')
|
||||
, http = require('http')
|
||||
, crypto = require('crypto')
|
||||
, Options = require('options')
|
||||
, WebSocket = require('./WebSocket')
|
||||
, Extensions = require('./Extensions')
|
||||
, PerMessageDeflate = require('./PerMessageDeflate')
|
||||
, tls = require('tls')
|
||||
, url = require('url');
|
||||
|
||||
/**
|
||||
* WebSocket Server implementation
|
||||
*/
|
||||
|
||||
function WebSocketServer(options, callback) {
|
||||
if (this instanceof WebSocketServer === false) {
|
||||
return new WebSocketServer(options, callback);
|
||||
}
|
||||
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
options = new Options({
|
||||
host: '0.0.0.0',
|
||||
port: null,
|
||||
server: null,
|
||||
verifyClient: null,
|
||||
handleProtocols: null,
|
||||
path: null,
|
||||
noServer: false,
|
||||
disableHixie: false,
|
||||
clientTracking: true,
|
||||
perMessageDeflate: true,
|
||||
maxPayload: 100 * 1024 * 1024
|
||||
}).merge(options);
|
||||
|
||||
if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) {
|
||||
throw new TypeError('`port` or a `server` must be provided');
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (options.isDefinedAndNonNull('port')) {
|
||||
this._server = http.createServer(function (req, res) {
|
||||
var body = http.STATUS_CODES[426];
|
||||
res.writeHead(426, {
|
||||
'Content-Length': body.length,
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
res.end(body);
|
||||
});
|
||||
this._server.allowHalfOpen = false;
|
||||
this._server.listen(options.value.port, options.value.host, callback);
|
||||
this._closeServer = function() { if (self._server) self._server.close(); };
|
||||
}
|
||||
else if (options.value.server) {
|
||||
this._server = options.value.server;
|
||||
if (options.value.path) {
|
||||
// take note of the path, to avoid collisions when multiple websocket servers are
|
||||
// listening on the same http server
|
||||
if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) {
|
||||
throw new Error('two instances of WebSocketServer cannot listen on the same http server path');
|
||||
}
|
||||
if (typeof this._server._webSocketPaths !== 'object') {
|
||||
this._server._webSocketPaths = {};
|
||||
}
|
||||
this._server._webSocketPaths[options.value.path] = 1;
|
||||
}
|
||||
}
|
||||
if (this._server) {
|
||||
this._onceServerListening = function() { self.emit('listening'); };
|
||||
this._server.once('listening', this._onceServerListening);
|
||||
}
|
||||
|
||||
if (typeof this._server != 'undefined') {
|
||||
this._onServerError = function(error) { self.emit('error', error) };
|
||||
this._server.on('error', this._onServerError);
|
||||
this._onServerUpgrade = function(req, socket, upgradeHead) {
|
||||
//copy upgradeHead to avoid retention of large slab buffers used in node core
|
||||
var head = new Buffer(upgradeHead.length);
|
||||
upgradeHead.copy(head);
|
||||
|
||||
self.handleUpgrade(req, socket, head, function(client) {
|
||||
self.emit('connection'+req.url, client);
|
||||
self.emit('connection', client);
|
||||
});
|
||||
};
|
||||
this._server.on('upgrade', this._onServerUpgrade);
|
||||
}
|
||||
|
||||
this.options = options.value;
|
||||
this.path = options.value.path;
|
||||
this.clients = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
util.inherits(WebSocketServer, events.EventEmitter);
|
||||
|
||||
/**
|
||||
* Immediately shuts down the connection.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocketServer.prototype.close = function(callback) {
|
||||
// terminate all associated clients
|
||||
var error = null;
|
||||
try {
|
||||
for (var i = 0, l = this.clients.length; i < l; ++i) {
|
||||
this.clients[i].terminate();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
// remove path descriptor, if any
|
||||
if (this.path && this._server._webSocketPaths) {
|
||||
delete this._server._webSocketPaths[this.path];
|
||||
if (Object.keys(this._server._webSocketPaths).length == 0) {
|
||||
delete this._server._webSocketPaths;
|
||||
}
|
||||
}
|
||||
|
||||
// close the http server if it was internally created
|
||||
try {
|
||||
if (typeof this._closeServer !== 'undefined') {
|
||||
this._closeServer();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (this._server) {
|
||||
this._server.removeListener('listening', this._onceServerListening);
|
||||
this._server.removeListener('error', this._onServerError);
|
||||
this._server.removeListener('upgrade', this._onServerUpgrade);
|
||||
}
|
||||
delete this._server;
|
||||
}
|
||||
if(callback)
|
||||
callback(error);
|
||||
else if(error)
|
||||
throw error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a HTTP Upgrade request.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocketServer.prototype.handleUpgrade = function(req, socket, upgradeHead, cb) {
|
||||
// check for wrong path
|
||||
if (this.options.path) {
|
||||
var u = url.parse(req.url);
|
||||
if (u && u.pathname !== this.options.path) return;
|
||||
}
|
||||
|
||||
if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments);
|
||||
else handleHybiUpgrade.apply(this, arguments);
|
||||
}
|
||||
|
||||
module.exports = WebSocketServer;
|
||||
|
||||
/**
|
||||
* Entirely private apis,
|
||||
* which may or may not be bound to a sepcific WebSocket instance.
|
||||
*/
|
||||
|
||||
function handleHybiUpgrade(req, socket, upgradeHead, cb) {
|
||||
// handle premature socket errors
|
||||
var errorHandler = function() {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
socket.on('error', errorHandler);
|
||||
|
||||
// verify key presence
|
||||
if (!req.headers['sec-websocket-key']) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify version
|
||||
var version = parseInt(req.headers['sec-websocket-version']);
|
||||
if ([8, 13].indexOf(version) === -1) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify protocol
|
||||
var protocols = req.headers['sec-websocket-protocol'];
|
||||
|
||||
// verify client
|
||||
var origin = version < 13 ?
|
||||
req.headers['sec-websocket-origin'] :
|
||||
req.headers['origin'];
|
||||
|
||||
// handle extensions offer
|
||||
var extensionsOffer = Extensions.parse(req.headers['sec-websocket-extensions']);
|
||||
|
||||
// handler to call when the connection sequence completes
|
||||
var self = this;
|
||||
var completeHybiUpgrade2 = function(protocol) {
|
||||
|
||||
// calc key
|
||||
var key = req.headers['sec-websocket-key'];
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
key = shasum.digest('base64');
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: websocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Accept: ' + key
|
||||
];
|
||||
|
||||
if (typeof protocol != 'undefined') {
|
||||
headers.push('Sec-WebSocket-Protocol: ' + protocol);
|
||||
}
|
||||
|
||||
var extensions = {};
|
||||
try {
|
||||
extensions = acceptExtensions.call(self, extensionsOffer);
|
||||
} catch (err) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object.keys(extensions).length) {
|
||||
var serverExtensions = {};
|
||||
Object.keys(extensions).forEach(function(token) {
|
||||
serverExtensions[token] = [extensions[token].params]
|
||||
});
|
||||
headers.push('Sec-WebSocket-Extensions: ' + Extensions.format(serverExtensions));
|
||||
}
|
||||
|
||||
// allows external modification/inspection of handshake headers
|
||||
self.emit('headers', headers);
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
try {
|
||||
socket.write(headers.concat('', '').join('\r\n'));
|
||||
}
|
||||
catch (e) {
|
||||
// if the upgrade write fails, shut the connection down hard
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new WebSocket([req, socket, upgradeHead], {
|
||||
protocolVersion: version,
|
||||
protocol: protocol,
|
||||
extensions: extensions,
|
||||
maxPayload: self.options.maxPayload
|
||||
});
|
||||
|
||||
if (self.options.clientTracking) {
|
||||
self.clients.push(client);
|
||||
client.on('close', function() {
|
||||
var index = self.clients.indexOf(client);
|
||||
if (index != -1) {
|
||||
self.clients.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// signal upgrade complete
|
||||
socket.removeListener('error', errorHandler);
|
||||
cb(client);
|
||||
}
|
||||
|
||||
// optionally call external protocol selection handler before
|
||||
// calling completeHybiUpgrade2
|
||||
var completeHybiUpgrade1 = function() {
|
||||
// choose from the sub-protocols
|
||||
if (typeof self.options.handleProtocols == 'function') {
|
||||
var protList = (protocols || "").split(/, */);
|
||||
var callbackCalled = false;
|
||||
var res = self.options.handleProtocols(protList, function(result, protocol) {
|
||||
callbackCalled = true;
|
||||
if (!result) abortConnection(socket, 401, 'Unauthorized');
|
||||
else completeHybiUpgrade2(protocol);
|
||||
});
|
||||
if (!callbackCalled) {
|
||||
// the handleProtocols handler never called our callback
|
||||
abortConnection(socket, 501, 'Could not process protocols');
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (typeof protocols !== 'undefined') {
|
||||
completeHybiUpgrade2(protocols.split(/, */)[0]);
|
||||
}
|
||||
else {
|
||||
completeHybiUpgrade2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// optionally call external client verification handler
|
||||
if (typeof this.options.verifyClient == 'function') {
|
||||
var info = {
|
||||
origin: origin,
|
||||
secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined',
|
||||
req: req
|
||||
};
|
||||
if (this.options.verifyClient.length == 2) {
|
||||
this.options.verifyClient(info, function(result, code, name) {
|
||||
if (typeof code === 'undefined') code = 401;
|
||||
if (typeof name === 'undefined') name = http.STATUS_CODES[code];
|
||||
|
||||
if (!result) abortConnection(socket, code, name);
|
||||
else completeHybiUpgrade1();
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if (!this.options.verifyClient(info)) {
|
||||
abortConnection(socket, 401, 'Unauthorized');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
completeHybiUpgrade1();
|
||||
}
|
||||
|
||||
function handleHixieUpgrade(req, socket, upgradeHead, cb) {
|
||||
// handle premature socket errors
|
||||
var errorHandler = function() {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
socket.on('error', errorHandler);
|
||||
|
||||
// bail if options prevent hixie
|
||||
if (this.options.disableHixie) {
|
||||
abortConnection(socket, 401, 'Hixie support disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
// verify key presence
|
||||
if (!req.headers['sec-websocket-key2']) {
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = req.headers['origin']
|
||||
, self = this;
|
||||
|
||||
// setup handshake completion to run after client has been verified
|
||||
var onClientVerified = function() {
|
||||
var wshost;
|
||||
if (!req.headers['x-forwarded-host'])
|
||||
wshost = req.headers.host;
|
||||
else
|
||||
wshost = req.headers['x-forwarded-host'];
|
||||
var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url
|
||||
, protocol = req.headers['sec-websocket-protocol'];
|
||||
|
||||
// build the response header and return a Buffer
|
||||
var buildResponseHeader = function() {
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: WebSocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Location: ' + location
|
||||
];
|
||||
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
|
||||
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
|
||||
|
||||
return new Buffer(headers.concat('', '').join('\r\n'));
|
||||
};
|
||||
|
||||
// send handshake response before receiving the nonce
|
||||
var handshakeResponse = function() {
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
|
||||
var headerBuffer = buildResponseHeader();
|
||||
|
||||
try {
|
||||
socket.write(headerBuffer, 'binary', function(err) {
|
||||
// remove listener if there was an error
|
||||
if (err) socket.removeListener('data', handler);
|
||||
return;
|
||||
});
|
||||
} catch (e) {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
// handshake completion code to run once nonce has been successfully retrieved
|
||||
var completeHandshake = function(nonce, rest, headerBuffer) {
|
||||
// calculate key
|
||||
var k1 = req.headers['sec-websocket-key1']
|
||||
, k2 = req.headers['sec-websocket-key2']
|
||||
, md5 = crypto.createHash('md5');
|
||||
|
||||
[k1, k2].forEach(function (k) {
|
||||
var n = parseInt(k.replace(/[^\d]/g, ''))
|
||||
, spaces = k.replace(/[^ ]/g, '').length;
|
||||
if (spaces === 0 || n % spaces !== 0){
|
||||
abortConnection(socket, 400, 'Bad Request');
|
||||
return;
|
||||
}
|
||||
n /= spaces;
|
||||
md5.update(String.fromCharCode(
|
||||
n >> 24 & 0xFF,
|
||||
n >> 16 & 0xFF,
|
||||
n >> 8 & 0xFF,
|
||||
n & 0xFF));
|
||||
});
|
||||
md5.update(nonce.toString('binary'));
|
||||
|
||||
socket.setTimeout(0);
|
||||
socket.setNoDelay(true);
|
||||
|
||||
try {
|
||||
var hashBuffer = new Buffer(md5.digest('binary'), 'binary');
|
||||
var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length);
|
||||
headerBuffer.copy(handshakeBuffer, 0);
|
||||
hashBuffer.copy(handshakeBuffer, headerBuffer.length);
|
||||
|
||||
// do a single write, which - upon success - causes a new client websocket to be setup
|
||||
socket.write(handshakeBuffer, 'binary', function(err) {
|
||||
if (err) return; // do not create client if an error happens
|
||||
var client = new WebSocket([req, socket, rest], {
|
||||
protocolVersion: 'hixie-76',
|
||||
protocol: protocol
|
||||
});
|
||||
if (self.options.clientTracking) {
|
||||
self.clients.push(client);
|
||||
client.on('close', function() {
|
||||
var index = self.clients.indexOf(client);
|
||||
if (index != -1) {
|
||||
self.clients.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// signal upgrade complete
|
||||
socket.removeListener('error', errorHandler);
|
||||
cb(client);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve nonce
|
||||
var nonceLength = 8;
|
||||
if (upgradeHead && upgradeHead.length >= nonceLength) {
|
||||
var nonce = upgradeHead.slice(0, nonceLength);
|
||||
var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null;
|
||||
completeHandshake.call(self, nonce, rest, buildResponseHeader());
|
||||
}
|
||||
else {
|
||||
// nonce not present in upgradeHead
|
||||
var nonce = new Buffer(nonceLength);
|
||||
upgradeHead.copy(nonce, 0);
|
||||
var received = upgradeHead.length;
|
||||
var rest = null;
|
||||
var handler = function (data) {
|
||||
var toRead = Math.min(data.length, nonceLength - received);
|
||||
if (toRead === 0) return;
|
||||
data.copy(nonce, received, 0, toRead);
|
||||
received += toRead;
|
||||
if (received == nonceLength) {
|
||||
socket.removeListener('data', handler);
|
||||
if (toRead < data.length) rest = data.slice(toRead);
|
||||
|
||||
// complete the handshake but send empty buffer for headers since they have already been sent
|
||||
completeHandshake.call(self, nonce, rest, new Buffer(0));
|
||||
}
|
||||
}
|
||||
|
||||
// handle additional data as we receive it
|
||||
socket.on('data', handler);
|
||||
|
||||
// send header response before we have the nonce to fix haproxy buffering
|
||||
handshakeResponse();
|
||||
}
|
||||
}
|
||||
|
||||
// verify client
|
||||
if (typeof this.options.verifyClient == 'function') {
|
||||
var info = {
|
||||
origin: origin,
|
||||
secure: typeof req.connection.authorized !== 'undefined' || typeof req.connection.encrypted !== 'undefined',
|
||||
req: req
|
||||
};
|
||||
if (this.options.verifyClient.length == 2) {
|
||||
var self = this;
|
||||
this.options.verifyClient(info, function(result, code, name) {
|
||||
if (typeof code === 'undefined') code = 401;
|
||||
if (typeof name === 'undefined') name = http.STATUS_CODES[code];
|
||||
|
||||
if (!result) abortConnection(socket, code, name);
|
||||
else onClientVerified.apply(self);
|
||||
});
|
||||
return;
|
||||
}
|
||||
else if (!this.options.verifyClient(info)) {
|
||||
abortConnection(socket, 401, 'Unauthorized');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no client verification required
|
||||
onClientVerified();
|
||||
}
|
||||
|
||||
function acceptExtensions(offer) {
|
||||
var extensions = {};
|
||||
var options = this.options.perMessageDeflate;
|
||||
var maxPayload = this.options.maxPayload;
|
||||
if (options && offer[PerMessageDeflate.extensionName]) {
|
||||
var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true, maxPayload);
|
||||
perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);
|
||||
extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
function abortConnection(socket, code, name) {
|
||||
try {
|
||||
var response = [
|
||||
'HTTP/1.1 ' + code + ' ' + name,
|
||||
'Content-type: text/html'
|
||||
];
|
||||
socket.write(response.concat('', '').join('\r\n'));
|
||||
}
|
||||
catch (e) { /* ignore errors - we've aborted this connection */ }
|
||||
finally {
|
||||
// ensure that an early aborted connection is shut down completely
|
||||
try { socket.destroy(); } catch (e) {}
|
||||
}
|
||||
}
|
42
node_modules/engine.io-client/node_modules/ws/package.json
generated
vendored
Normal file
42
node_modules/engine.io-client/node_modules/ws/package.json
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "ws",
|
||||
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
|
||||
"version": "1.1.5",
|
||||
"keywords": [
|
||||
"Hixie",
|
||||
"HyBi",
|
||||
"Push",
|
||||
"RFC-6455",
|
||||
"WebSocket",
|
||||
"WebSockets",
|
||||
"real-time"
|
||||
],
|
||||
"homepage": "https://github.com/websockets/ws",
|
||||
"bugs": "https://github.com/websockets/ws/issues",
|
||||
"repository": "websockets/ws",
|
||||
"author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)",
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"dependencies": {
|
||||
"options": ">=0.0.5",
|
||||
"ultron": "1.0.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ansi": "0.3.x",
|
||||
"benchmark": "0.3.x",
|
||||
"bufferutil": "1.2.x",
|
||||
"expect.js": "0.3.x",
|
||||
"istanbul": "^0.4.1",
|
||||
"mocha": "2.3.x",
|
||||
"should": "8.0.x",
|
||||
"tinycolor": "0.0.x",
|
||||
"utf-8-validate": "1.2.x"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user