Files
RoboCommander/node_modules/neo4j-driver/lib/v1/internal/ch-websocket.js
2026-04-05 16:14:49 -04:00

269 lines
9.2 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _buf = require('./buf');
var _error = require('./../error');
var _util = require('./util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Create a new WebSocketChannel to be used in web browsers.
* @access private
*/
var WebSocketChannel = function () {
/**
* Create new instance
* @param {ChannelConfig} config - configuration for this channel.
*/
function WebSocketChannel(config) {
(0, _classCallCheck3.default)(this, WebSocketChannel);
this._open = true;
this._pending = [];
this._error = null;
this._handleConnectionError = this._handleConnectionError.bind(this);
this._config = config;
var scheme = "ws";
//Allow boolean for backwards compatibility
if (config.encrypted === true || config.encrypted === _util.ENCRYPTION_ON) {
if (!config.trust || config.trust === 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES') {
scheme = "wss";
} else {
this._error = (0, _error.newError)("The browser version of this driver only supports one trust " + 'strategy, \'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES\'. ' + config.trust + ' is not supported. Please ' + "either use TRUST_CUSTOM_CA_SIGNED_CERTIFICATES or disable encryption by setting " + "`encrypted:\"" + _util.ENCRYPTION_OFF + "\"` in the driver configuration.");
return;
}
}
this._ws = createWebSocket(scheme, config.url);
this._ws.binaryType = "arraybuffer";
var self = this;
//All connection errors are not sent to the error handler
//we must also check for dirty close calls
this._ws.onclose = function (e) {
if (!e.wasClean) {
self._handleConnectionError();
}
};
this._ws.onopen = function () {
// Connected! Cancel the connection timeout
self._clearConnectionTimeout();
// Drain all pending messages
var pending = self._pending;
self._pending = null;
for (var i = 0; i < pending.length; i++) {
self.write(pending[i]);
}
};
this._ws.onmessage = function (event) {
if (self.onmessage) {
var b = new _buf.HeapBuffer(event.data);
self.onmessage(b);
}
};
this._ws.onerror = this._handleConnectionError;
this._connectionTimeoutFired = false;
this._connectionTimeoutId = this._setupConnectionTimeout();
}
(0, _createClass3.default)(WebSocketChannel, [{
key: '_handleConnectionError',
value: function _handleConnectionError() {
if (this._connectionTimeoutFired) {
// timeout fired - not connected within configured time
this._error = (0, _error.newError)('Failed to establish connection in ' + this._config.connectionTimeout + 'ms', this._config.connectionErrorCode);
if (this.onerror) {
this.onerror(this._error);
}
return;
}
// onerror triggers on websocket close as well.. don't get me started.
if (this._open) {
// http://stackoverflow.com/questions/25779831/how-to-catch-websocket-connection-to-ws-xxxnn-failed-connection-closed-be
this._error = (0, _error.newError)("WebSocket connection failure. Due to security " + "constraints in your web browser, the reason for the failure is not available " + "to this Neo4j Driver. Please use your browsers development console to determine " + "the root cause of the failure. Common reasons include the database being " + "unavailable, using the wrong connection URL or temporary network problems. " + "If you have enabled encryption, ensure your browser is configured to trust the " + 'certificate Neo4j is configured to use. WebSocket `readyState` is: ' + this._ws.readyState, this._config.connectionErrorCode);
if (this.onerror) {
this.onerror(this._error);
}
}
}
}, {
key: 'isEncrypted',
value: function isEncrypted() {
return this._config.encrypted;
}
/**
* Write the passed in buffer to connection
* @param {HeapBuffer} buffer - Buffer to write
*/
}, {
key: 'write',
value: function write(buffer) {
// If there is a pending queue, push this on that queue. This means
// we are not yet connected, so we queue things locally.
if (this._pending !== null) {
this._pending.push(buffer);
} else if (buffer instanceof _buf.HeapBuffer) {
this._ws.send(buffer._buffer);
} else {
throw (0, _error.newError)("Don't know how to send buffer: " + buffer);
}
}
/**
* Close the connection
* @param {function} cb - Function to call on close.
*/
}, {
key: 'close',
value: function close() {
var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {
return null;
};
this._open = false;
this._clearConnectionTimeout();
this._ws.close();
this._ws.onclose = cb;
}
/**
* Set connection timeout on the given WebSocket, if configured.
* @return {number} the timeout id or null.
* @private
*/
}, {
key: '_setupConnectionTimeout',
value: function _setupConnectionTimeout() {
var _this = this;
var timeout = this._config.connectionTimeout;
if (timeout) {
var webSocket = this._ws;
return setTimeout(function () {
if (webSocket.readyState !== WebSocket.OPEN) {
_this._connectionTimeoutFired = true;
webSocket.close();
}
}, timeout);
}
return null;
}
/**
* Remove active connection timeout, if any.
* @private
*/
}, {
key: '_clearConnectionTimeout',
value: function _clearConnectionTimeout() {
var timeoutId = this._connectionTimeoutId;
if (timeoutId || timeoutId === 0) {
this._connectionTimeoutFired = false;
this._connectionTimeoutId = null;
clearTimeout(timeoutId);
}
}
}]);
return WebSocketChannel;
}(); /**
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* 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 available = typeof WebSocket !== 'undefined';
var _websocketChannelModule = { channel: WebSocketChannel, available: available };
function createWebSocket(scheme, parsedUrl) {
var url = scheme + '://' + parsedUrl.hostAndPort;
try {
return new WebSocket(url);
} catch (error) {
if (isIPv6AddressIssueOnWindows(error, parsedUrl)) {
// WebSocket in IE and Edge browsers on Windows do not support regular IPv6 address syntax because they contain ':'.
// It's an invalid character for UNC (https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_UNC_path_names)
// and Windows requires IPv6 to be changes in the following way:
// 1) replace all ':' with '-'
// 2) replace '%' with 's' for link-local address
// 3) append '.ipv6-literal.net' suffix
// only then resulting string can be considered a valid IPv6 address. Yes, this is extremely weird!
// For more details see:
// https://social.msdn.microsoft.com/Forums/ie/en-US/06cca73b-63c2-4bf9-899b-b229c50449ff/whether-ie10-websocket-support-ipv6?forum=iewebdevelopment
// https://www.itdojo.com/ipv6-addresses-and-unc-path-names-overcoming-illegal/
// Creation of WebSocket with unconverted address results in SyntaxError without message or stacktrace.
// That is why here we "catch" SyntaxError and rewrite IPv6 address if needed.
var windowsFriendlyUrl = asWindowsFriendlyIPv6Address(scheme, parsedUrl);
return new WebSocket(windowsFriendlyUrl);
} else {
throw error;
}
}
}
function isIPv6AddressIssueOnWindows(error, parsedUrl) {
return error.name === 'SyntaxError' && isIPv6Address(parsedUrl);
}
function isIPv6Address(parsedUrl) {
var hostAndPort = parsedUrl.hostAndPort;
return hostAndPort.charAt(0) === '[' && hostAndPort.indexOf(']') !== -1;
}
function asWindowsFriendlyIPv6Address(scheme, parsedUrl) {
// replace all ':' with '-'
var hostWithoutColons = parsedUrl.host.replace(new RegExp(':', 'g'), '-');
// replace '%' with 's' for link-local IPv6 address like 'fe80::1%lo0'
var hostWithoutPercent = hostWithoutColons.replace('%', 's');
// append magic '.ipv6-literal.net' suffix
var ipv6Host = hostWithoutPercent + '.ipv6-literal.net';
return scheme + '://' + ipv6Host + ':' + parsedUrl.port;
}
exports.default = _websocketChannelModule;