quitando basura del index
[VSoRC/.git] / node_modules / websocket / lib / WebSocketRequest.js
diff --git a/node_modules/websocket/lib/WebSocketRequest.js b/node_modules/websocket/lib/WebSocketRequest.js
deleted file mode 100644 (file)
index f4d9655..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/************************************************************************
- *  Copyright 2010-2015 Brian McKelvey.
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- ***********************************************************************/
-
-var crypto = require('crypto');
-var util = require('util');
-var url = require('url');
-var EventEmitter = require('events').EventEmitter;
-var WebSocketConnection = require('./WebSocketConnection');
-
-var headerValueSplitRegExp = /,\s*/;
-var headerParamSplitRegExp = /;\s*/;
-var headerSanitizeRegExp = /[\r\n]/g;
-var xForwardedForSeparatorRegExp = /,\s*/;
-var separators = [
-    '(', ')', '<', '>', '@',
-    ',', ';', ':', '\\', '\"',
-    '/', '[', ']', '?', '=',
-    '{', '}', ' ', String.fromCharCode(9)
-];
-var controlChars = [String.fromCharCode(127) /* DEL */];
-for (var i=0; i < 31; i ++) {
-    /* US-ASCII Control Characters */
-    controlChars.push(String.fromCharCode(i));
-}
-
-var cookieNameValidateRegEx = /([\x00-\x20\x22\x28\x29\x2c\x2f\x3a-\x3f\x40\x5b-\x5e\x7b\x7d\x7f])/;
-var cookieValueValidateRegEx = /[^\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]/;
-var cookieValueDQuoteValidateRegEx = /^"[^"]*"$/;
-var controlCharsAndSemicolonRegEx = /[\x00-\x20\x3b]/g;
-
-var cookieSeparatorRegEx = /[;,] */;
-
-var httpStatusDescriptions = {
-    100: 'Continue',
-    101: 'Switching Protocols',
-    200: 'OK',
-    201: 'Created',
-    203: 'Non-Authoritative Information',
-    204: 'No Content',
-    205: 'Reset Content',
-    206: 'Partial Content',
-    300: 'Multiple Choices',
-    301: 'Moved Permanently',
-    302: 'Found',
-    303: 'See Other',
-    304: 'Not Modified',
-    305: 'Use Proxy',
-    307: 'Temporary Redirect',
-    400: 'Bad Request',
-    401: 'Unauthorized',
-    402: 'Payment Required',
-    403: 'Forbidden',
-    404: 'Not Found',
-    406: 'Not Acceptable',
-    407: 'Proxy Authorization Required',
-    408: 'Request Timeout',
-    409: 'Conflict',
-    410: 'Gone',
-    411: 'Length Required',
-    412: 'Precondition Failed',
-    413: 'Request Entity Too Long',
-    414: 'Request-URI Too Long',
-    415: 'Unsupported Media Type',
-    416: 'Requested Range Not Satisfiable',
-    417: 'Expectation Failed',
-    426: 'Upgrade Required',
-    500: 'Internal Server Error',
-    501: 'Not Implemented',
-    502: 'Bad Gateway',
-    503: 'Service Unavailable',
-    504: 'Gateway Timeout',
-    505: 'HTTP Version Not Supported'
-};
-
-function WebSocketRequest(socket, httpRequest, serverConfig) {
-    // Superclass Constructor
-    EventEmitter.call(this);
-
-    this.socket = socket;
-    this.httpRequest = httpRequest;
-    this.resource = httpRequest.url;
-    this.remoteAddress = socket.remoteAddress;
-    this.remoteAddresses = [this.remoteAddress];
-    this.serverConfig = serverConfig;
-    
-    // Watch for the underlying TCP socket closing before we call accept
-    this._socketIsClosing = false;
-    this._socketCloseHandler = this._handleSocketCloseBeforeAccept.bind(this);
-    this.socket.on('end', this._socketCloseHandler);
-    this.socket.on('close', this._socketCloseHandler);
-    
-    this._resolved = false;
-}
-
-util.inherits(WebSocketRequest, EventEmitter);
-
-WebSocketRequest.prototype.readHandshake = function() {
-    var self = this;
-    var request = this.httpRequest;
-
-    // Decode URL
-    this.resourceURL = url.parse(this.resource, true);
-
-    this.host = request.headers['host'];
-    if (!this.host) {
-        throw new Error('Client must provide a Host header.');
-    }
-
-    this.key = request.headers['sec-websocket-key'];
-    if (!this.key) {
-        throw new Error('Client must provide a value for Sec-WebSocket-Key.');
-    }
-
-    this.webSocketVersion = parseInt(request.headers['sec-websocket-version'], 10);
-
-    if (!this.webSocketVersion || isNaN(this.webSocketVersion)) {
-        throw new Error('Client must provide a value for Sec-WebSocket-Version.');
-    }
-
-    switch (this.webSocketVersion) {
-        case 8:
-        case 13:
-            break;
-        default:
-            var e = new Error('Unsupported websocket client version: ' + this.webSocketVersion +
-                              'Only versions 8 and 13 are supported.');
-            e.httpCode = 426;
-            e.headers = {
-                'Sec-WebSocket-Version': '13'
-            };
-            throw e;
-    }
-
-    if (this.webSocketVersion === 13) {
-        this.origin = request.headers['origin'];
-    }
-    else if (this.webSocketVersion === 8) {
-        this.origin = request.headers['sec-websocket-origin'];
-    }
-
-    // Protocol is optional.
-    var protocolString = request.headers['sec-websocket-protocol'];
-    this.protocolFullCaseMap = {};
-    this.requestedProtocols = [];
-    if (protocolString) {
-        var requestedProtocolsFullCase = protocolString.split(headerValueSplitRegExp);
-        requestedProtocolsFullCase.forEach(function(protocol) {
-            var lcProtocol = protocol.toLocaleLowerCase();
-            self.requestedProtocols.push(lcProtocol);
-            self.protocolFullCaseMap[lcProtocol] = protocol;
-        });
-    }
-
-    if (!this.serverConfig.ignoreXForwardedFor &&
-        request.headers['x-forwarded-for']) {
-        var immediatePeerIP = this.remoteAddress;
-        this.remoteAddresses = request.headers['x-forwarded-for']
-            .split(xForwardedForSeparatorRegExp);
-        this.remoteAddresses.push(immediatePeerIP);
-        this.remoteAddress = this.remoteAddresses[0];
-    }
-
-    // Extensions are optional.
-    var extensionsString = request.headers['sec-websocket-extensions'];
-    this.requestedExtensions = this.parseExtensions(extensionsString);
-
-    // Cookies are optional
-    var cookieString = request.headers['cookie'];
-    this.cookies = this.parseCookies(cookieString);
-};
-
-WebSocketRequest.prototype.parseExtensions = function(extensionsString) {
-    if (!extensionsString || extensionsString.length === 0) {
-        return [];
-    }
-    var extensions = extensionsString.toLocaleLowerCase().split(headerValueSplitRegExp);
-    extensions.forEach(function(extension, index, array) {
-        var params = extension.split(headerParamSplitRegExp);
-        var extensionName = params[0];
-        var extensionParams = params.slice(1);
-        extensionParams.forEach(function(rawParam, index, array) {
-            var arr = rawParam.split('=');
-            var obj = {
-                name: arr[0],
-                value: arr[1]
-            };
-            array.splice(index, 1, obj);
-        });
-        var obj = {
-            name: extensionName,
-            params: extensionParams
-        };
-        array.splice(index, 1, obj);
-    });
-    return extensions;
-};
-
-// This function adapted from node-cookie
-// https://github.com/shtylman/node-cookie
-WebSocketRequest.prototype.parseCookies = function(str) {
-    // Sanity Check
-    if (!str || typeof(str) !== 'string') {
-        return [];
-    }
-
-    var cookies = [];
-    var pairs = str.split(cookieSeparatorRegEx);
-
-    pairs.forEach(function(pair) {
-        var eq_idx = pair.indexOf('=');
-        if (eq_idx === -1) {
-            cookies.push({
-                name: pair,
-                value: null
-            });
-            return;
-        }
-
-        var key = pair.substr(0, eq_idx).trim();
-        var val = pair.substr(++eq_idx, pair.length).trim();
-
-        // quoted values
-        if ('"' === val[0]) {
-            val = val.slice(1, -1);
-        }
-
-        cookies.push({
-            name: key,
-            value: decodeURIComponent(val)
-        });
-    });
-
-    return cookies;
-};
-
-WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, cookies) {
-    this._verifyResolution();
-    
-    // TODO: Handle extensions
-
-    var protocolFullCase;
-
-    if (acceptedProtocol) {
-        protocolFullCase = this.protocolFullCaseMap[acceptedProtocol.toLocaleLowerCase()];
-        if (typeof(protocolFullCase) === 'undefined') {
-            protocolFullCase = acceptedProtocol;
-        }
-    }
-    else {
-        protocolFullCase = acceptedProtocol;
-    }
-    this.protocolFullCaseMap = null;
-
-    // Create key validation hash
-    var sha1 = crypto.createHash('sha1');
-    sha1.update(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
-    var acceptKey = sha1.digest('base64');
-
-    var response = 'HTTP/1.1 101 Switching Protocols\r\n' +
-                   'Upgrade: websocket\r\n' +
-                   'Connection: Upgrade\r\n' +
-                   'Sec-WebSocket-Accept: ' + acceptKey + '\r\n';
-
-    if (protocolFullCase) {
-        // validate protocol
-        for (var i=0; i < protocolFullCase.length; i++) {
-            var charCode = protocolFullCase.charCodeAt(i);
-            var character = protocolFullCase.charAt(i);
-            if (charCode < 0x21 || charCode > 0x7E || separators.indexOf(character) !== -1) {
-                this.reject(500);
-                throw new Error('Illegal character "' + String.fromCharCode(character) + '" in subprotocol.');
-            }
-        }
-        if (this.requestedProtocols.indexOf(acceptedProtocol) === -1) {
-            this.reject(500);
-            throw new Error('Specified protocol was not requested by the client.');
-        }
-
-        protocolFullCase = protocolFullCase.replace(headerSanitizeRegExp, '');
-        response += 'Sec-WebSocket-Protocol: ' + protocolFullCase + '\r\n';
-    }
-    this.requestedProtocols = null;
-
-    if (allowedOrigin) {
-        allowedOrigin = allowedOrigin.replace(headerSanitizeRegExp, '');
-        if (this.webSocketVersion === 13) {
-            response += 'Origin: ' + allowedOrigin + '\r\n';
-        }
-        else if (this.webSocketVersion === 8) {
-            response += 'Sec-WebSocket-Origin: ' + allowedOrigin + '\r\n';
-        }
-    }
-
-    if (cookies) {
-        if (!Array.isArray(cookies)) {
-            this.reject(500);
-            throw new Error('Value supplied for "cookies" argument must be an array.');
-        }
-        var seenCookies = {};
-        cookies.forEach(function(cookie) {
-            if (!cookie.name || !cookie.value) {
-                this.reject(500);
-                throw new Error('Each cookie to set must at least provide a "name" and "value"');
-            }
-
-            // Make sure there are no \r\n sequences inserted
-            cookie.name = cookie.name.replace(controlCharsAndSemicolonRegEx, '');
-            cookie.value = cookie.value.replace(controlCharsAndSemicolonRegEx, '');
-
-            if (seenCookies[cookie.name]) {
-                this.reject(500);
-                throw new Error('You may not specify the same cookie name twice.');
-            }
-            seenCookies[cookie.name] = true;
-
-            // token (RFC 2616, Section 2.2)
-            var invalidChar = cookie.name.match(cookieNameValidateRegEx);
-            if (invalidChar) {
-                this.reject(500);
-                throw new Error('Illegal character ' + invalidChar[0] + ' in cookie name');
-            }
-
-            // RFC 6265, Section 4.1.1
-            // *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) | %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
-            if (cookie.value.match(cookieValueDQuoteValidateRegEx)) {
-                invalidChar = cookie.value.slice(1, -1).match(cookieValueValidateRegEx);
-            } else {
-                invalidChar = cookie.value.match(cookieValueValidateRegEx);
-            }
-            if (invalidChar) {
-                this.reject(500);
-                throw new Error('Illegal character ' + invalidChar[0] + ' in cookie value');
-            }
-
-            var cookieParts = [cookie.name + '=' + cookie.value];
-
-            // RFC 6265, Section 4.1.1
-            // 'Path=' path-value | <any CHAR except CTLs or ';'>
-            if(cookie.path){
-                invalidChar = cookie.path.match(controlCharsAndSemicolonRegEx);
-                if (invalidChar) {
-                    this.reject(500);
-                    throw new Error('Illegal character ' + invalidChar[0] + ' in cookie path');
-                }
-                cookieParts.push('Path=' + cookie.path);
-            }
-
-            // RFC 6265, Section 4.1.2.3
-            // 'Domain=' subdomain
-            if (cookie.domain) {
-                if (typeof(cookie.domain) !== 'string') {
-                    this.reject(500);
-                    throw new Error('Domain must be specified and must be a string.');
-                }
-                invalidChar = cookie.domain.match(controlCharsAndSemicolonRegEx);
-                if (invalidChar) {
-                    this.reject(500);
-                    throw new Error('Illegal character ' + invalidChar[0] + ' in cookie domain');
-                }
-                cookieParts.push('Domain=' + cookie.domain.toLowerCase());
-            }
-
-            // RFC 6265, Section 4.1.1
-            //'Expires=' sane-cookie-date | Force Date object requirement by using only epoch
-            if (cookie.expires) {
-                if (!(cookie.expires instanceof Date)){
-                    this.reject(500);
-                    throw new Error('Value supplied for cookie "expires" must be a vaild date object');
-                }
-                cookieParts.push('Expires=' + cookie.expires.toGMTString());
-            }
-
-            // RFC 6265, Section 4.1.1
-            //'Max-Age=' non-zero-digit *DIGIT
-            if (cookie.maxage) {
-                var maxage = cookie.maxage;
-                if (typeof(maxage) === 'string') {
-                    maxage = parseInt(maxage, 10);
-                }
-                if (isNaN(maxage) || maxage <= 0 ) {
-                    this.reject(500);
-                    throw new Error('Value supplied for cookie "maxage" must be a non-zero number');
-                }
-                maxage = Math.round(maxage);
-                cookieParts.push('Max-Age=' + maxage.toString(10));
-            }
-
-            // RFC 6265, Section 4.1.1
-            //'Secure;'
-            if (cookie.secure) {
-                if (typeof(cookie.secure) !== 'boolean') {
-                    this.reject(500);
-                    throw new Error('Value supplied for cookie "secure" must be of type boolean');
-                }
-                cookieParts.push('Secure');
-            }
-
-            // RFC 6265, Section 4.1.1
-            //'HttpOnly;'
-            if (cookie.httponly) {
-                if (typeof(cookie.httponly) !== 'boolean') {
-                    this.reject(500);
-                    throw new Error('Value supplied for cookie "httponly" must be of type boolean');
-                }
-                cookieParts.push('HttpOnly');
-            }
-
-            response += ('Set-Cookie: ' + cookieParts.join(';') + '\r\n');
-        }.bind(this));
-    }
-
-    // TODO: handle negotiated extensions
-    // if (negotiatedExtensions) {
-    //     response += 'Sec-WebSocket-Extensions: ' + negotiatedExtensions.join(', ') + '\r\n';
-    // }
-    
-    // Mark the request resolved now so that the user can't call accept or
-    // reject a second time.
-    this._resolved = true;
-    this.emit('requestResolved', this);
-    
-    response += '\r\n';
-
-    var connection = new WebSocketConnection(this.socket, [], acceptedProtocol, false, this.serverConfig);
-    connection.webSocketVersion = this.webSocketVersion;
-    connection.remoteAddress = this.remoteAddress;
-    connection.remoteAddresses = this.remoteAddresses;
-    
-    var self = this;
-    
-    if (this._socketIsClosing) {
-        // Handle case when the client hangs up before we get a chance to
-        // accept the connection and send our side of the opening handshake.
-        cleanupFailedConnection(connection);
-    }
-    else {
-        this.socket.write(response, 'ascii', function(error) {
-            if (error) {
-                cleanupFailedConnection(connection);
-                return;
-            }
-            
-            self._removeSocketCloseListeners();
-            connection._addSocketEventListeners();
-        });
-    }
-
-    this.emit('requestAccepted', connection);
-    return connection;
-};
-
-WebSocketRequest.prototype.reject = function(status, reason, extraHeaders) {
-    this._verifyResolution();
-    
-    // Mark the request resolved now so that the user can't call accept or
-    // reject a second time.
-    this._resolved = true;
-    this.emit('requestResolved', this);
-    
-    if (typeof(status) !== 'number') {
-        status = 403;
-    }
-    var response = 'HTTP/1.1 ' + status + ' ' + httpStatusDescriptions[status] + '\r\n' +
-                   'Connection: close\r\n';
-    if (reason) {
-        reason = reason.replace(headerSanitizeRegExp, '');
-        response += 'X-WebSocket-Reject-Reason: ' + reason + '\r\n';
-    }
-
-    if (extraHeaders) {
-        for (var key in extraHeaders) {
-            var sanitizedValue = extraHeaders[key].toString().replace(headerSanitizeRegExp, '');
-            var sanitizedKey = key.replace(headerSanitizeRegExp, '');
-            response += (sanitizedKey + ': ' + sanitizedValue + '\r\n');
-        }
-    }
-
-    response += '\r\n';
-    this.socket.end(response, 'ascii');
-
-    this.emit('requestRejected', this);
-};
-
-WebSocketRequest.prototype._handleSocketCloseBeforeAccept = function() {
-    this._socketIsClosing = true;
-    this._removeSocketCloseListeners();
-};
-
-WebSocketRequest.prototype._removeSocketCloseListeners = function() {
-    this.socket.removeListener('end', this._socketCloseHandler);
-    this.socket.removeListener('close', this._socketCloseHandler);
-};
-
-WebSocketRequest.prototype._verifyResolution = function() {
-    if (this._resolved) {
-        throw new Error('WebSocketRequest may only be accepted or rejected one time.');
-    }
-};
-
-function cleanupFailedConnection(connection) {
-    // Since we have to return a connection object even if the socket is
-    // already dead in order not to break the API, we schedule a 'close'
-    // event on the connection object to occur immediately.
-    process.nextTick(function() {
-        // WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006
-        // Third param: Skip sending the close frame to a dead socket
-        connection.drop(1006, 'TCP connection lost before handshake completed.', true);
-    });
-}
-
-module.exports = WebSocketRequest;