Cancel WebSocket connection when trying to connect (JavaScript) - javascript

Is it possible to cancel WebSocket connection while trying to establish connection to the server?
Let's say user notified that it is a misspelled host and want to cancel request for establishing connection before onerror has raised like
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I tried to call close, but this does not cancel request. I even get warning in console:
failed: WebSocket is closed before the connection is established.

Unfortunately, this is not achievable using close(), and seems not possible at all.
Also, unlike XMLHttpRequest, WebSocket have no abort method to achieve this.
The WebSocket specs do not mention any way of doing this, and setting the object to null does not do the trick.
The following example illustrates this by setting the WebSocket object to null, but still getting connection error message.
var ws = new WebSocket('ws://unknownhost.local');
ws.onopen = function() {
console.log('ohai');
};
ws = null;
console.log(ws);
// > null
// > VM2346:35 WebSocket connection to 'ws://unknownhost.local/' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED

Since the two previous answers to this question have been posted the behaviour of close() seems to have changed.
Quoting the mozilla API docs:
The WebSocket.close() method closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing.
You could therefore do this:
var ws = new WebSocket('ws://unknownhost.local');
setTimeout(() => {
if (ws.readyState == WebSocket.CONNECTING) {
ws.close();
console.log("Connection cancelled.");
}
}, 1000);
Which would cancel the connection attempt if the readyState did not switch to OPEN yet.
I tried this, and it seems to work (tested on Firefox).

close() method only terminates the established connections.
For your case, you may use assigning your websocket handle to null where you want to stop it.
webSocketHanle = null;
By this assignment, your callbacks will not be activated.
But notice that it is quite fast process to getting response from server.

Related

Chrome WebSocket connection closes immediately

I have been trying to setup a wss server using nodejs, and have encountered a problem when trying to connect to it using chrome. The problem still occurs with all extensions disabled and in an incognito window so I've ruled that out as the problem.
When trying to connect using chrome, I get the error:
WebSocket connection to 'wss://www.domain-name.com/' failed:
with no reason given. On the server, socket.on('close') is called immediately with description "Connection dropped by remote peer" The close event has wasClean = false. This error does not occur when connecting from safari and Firefox so I'm not really sure where to look to see what's causing it. It's running on AWS Lightsail, and through an Apache proxy server.
The client code:
var socket = new WebSocket("wss://www.domain-name.com", 'JSON')
socket.onopen = function (event) {
console.log('open');
socket.send('socket opened')};
socket.onclose = function (event) {
console.log(event)};
socket.onmessage = function(message) {
console.log('receiving message from server...')};
And the server code:
const WebSocketServer = require('websocket').server;
app = express()
var server = app.listen(3000, () => {
console.log('Server started');
});
app.use(express.static('public'));
var wsServer = new WebSocketServer({
httpServer: server
});
wsServer.on('request', function(request){
console.log('New connection');
var connection = request.accept(null, request.origin);
connection.send('welcome from server...');
connection.on('message', function(message){
console.log(message)};
connection.on('close', function(reasonCode, description) {
console.log('disconnecting', reasonCode, description);
});
});
I also got the same error before switching to a secure WebSocket server. Any help would be appreciated, I've run out of places to look and ways to try and get more information to help out what the problem is.
EDIT: it seems to work on chrome on my phone, but not on chrome on my friends phone?
The problem was not specifying the protocol when accepting the connection. After about 20 hours working on the same bug and implementing an SSL certificate to get it to work, I changed:
request.accept(null, request.origin);
to:
request.accept('json', request.origin);
For some reason the chrome gives a really unhelpful error message. Microsoft edge the same error occurs, but gives a much more helpful error message so I could work out what was going on.
In my case, this was caused by passing an unused options value as the third parameter to the WebSocket constructor. The options parameter is supported by Node.js's ws module but not by browsers; however, instead of displaying a clean error message, Chrome closed the connection without a good description.

Connection to socket gets error "WebSocket opening handshake timed out" using Javascript and C#

About 4 hours of research...here we go.
I have a C# program that sends and listens for anything coming in a specific Socket. Using the sockets, C# can send stuff to it and can receive from it just fine. Now, going to my JavaScript file, I'm using the WebSocket interface to communicate with C#, but doesn't work (usually times out after a couple of minutes). When the Socket is online, the JavaScript code will take up to about 4 minutes then throw an error saying "WebSocket opening handshake timed out". The thing is I know that it can find because, when the port of the ip doesn't exist the JavaScript file throws an error in the next couple seconds.
Things I've done:
Turn off all firewalls, use both ws and wss at the beginning of the ip and port (ex: wss://xxx.xxx.x.xx:11111), change the port, change the ip to a valid ip still reachable, research for 4 hours.
C#:
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = IPAddress.Parse("ip");
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, 11111);
Socket listener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
Console.WriteLine("Waiting connection...");
Socket clientSocket = listener.Accept();
byte[] bytes = new Byte[1024];
string data = null;
while (true)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, numByte);
if (data.IndexOf("<EOF>") > -1)
{
break;
}
}
Console.WriteLine("Text received -> {0} ", data);
byte[] message = Encoding.ASCII.GetBytes("Test Server");
clientSocket.Send(message);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
JavaScript:
socket = new WebSocket("wss://ip:11111");
socket.onopen = function()
{
alert("Connected!");
}
socket.onerror = function()
{
alert("Connection Failed");
}
The ip is local
Long story short, C# can communicate with itself and JavaScript can find it but can't communicate with it.
Properly complete a handshake. (Or use a library / connection type that does.)
The WebSocket protocol (as original defined in RFC6455 - The WebSocket Protocol) does not open a plain unrestricted socket, in part for security reasons.
Since the handshake is not complete, the client WS request will timeout as the HTTP “Upgrade” response is never received. Until the handshake is complete, the WS will not be active over the underlying TCP connection.
Initiating a WebSocket connection (“the handshake”) is defined in section 4 of the RFC. It is also discussed in How JavaScript works: Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path.
The client establishes a WebSocket connection through a process known as the WebSocket handshake. This process starts with the client sending a regular HTTP request to the server. An Upgrade header is included in this request which informs the server that the client wishes to establish a WebSocket connection.
..
Now that [after] the handshake is complete the initial HTTP connection is replaced by a WebSocket connection that uses the same underlying TCP/IP connection. At this point, either party can start sending data.

A way to stop WebSocket errors to show up in browser's console

So the problem is when I try to initiate a new WebSocket to a remote host, sometimes the browser's console prints a red error message and complains about a refused connection, here is the message:
Error in connection establishment: net::ERR_CONNECTION_REFUSED
Having an error is fine since the remote host might be not responding sometimes, but the fact that I cannot handle this error message is very annoying.
Is there any way to either handle this error message or check whether the remote host accepts the WebSocket connection before initializing one in my JavaScript code??
Several possibilities come to mind:
Add a WebSocket.onerror error handler
myWebSocket.onerror = myEventHandler;
Wrap your "connect" in a try/catch block
try {
const connection = new WebSocket(myUrl);
...
}
catch(error) {
console.error(error);
}
Structure your code such that your I/O is event driven:
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Examples
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
// Handle errors
socket.addEventListener('error', function (event) {
console.log('WebSocket error observed:', event);
});
ADDENDUM:
The above methods allow you to completely handle a websockets exception.
Regardless of whether the exception is handled or not, the Chrome debugger will tell you if an exception has occurred. This is a Good Thing. It's called a "First-Chance Exception":
https://learn.microsoft.com/en-us/security-risk-detection/concepts/first-chance-exception
.. it is known a “first chance” exception – the debugger is given the
first chance of inspecting the exception prior to the application
handling it (or not).
In Microsoft's Visual Studio debugger, there's a little checkbox you can use to "gag" first chance exceptions. I'm not aware of any similar "checkbox" in Chrome debugger.
POSSIBLE SUGGESTIONS:
Chrome debugger has a "filter". EXAMPLE FILTER REGEX: ^((?!ERR_CONNECTION_REFUSED).)*$
This link suggests you might be able to use the filter to "Hide Network Messages" (I haven't tried it myself). See also this link.

How do I find out if connectNative failed or succeeded

I have managed to connect my extension to our native host:
var pulse_tracker_port = chrome.runtime.connectNative('com.cloudfactory.pulsetracker');
but how do I find out if the connection succeeded or not? The value of 'pulse_tracker_report.name' will always be an empty string no matter if the connection succeeded or not.
I also tried to add listeners to find out if the connection succeeded or not but none of these callbacks are being invoked:
chrome.runtime.onConnect.addListener(function(port)
{
console.log('Connected to "Pulse Tracker" #port: ' + port.name);
});
chrome.runtime.onConnectExternal.addListener(function(port)
{
console.log('Connected to "Pulse Tracker" #port: ' + port.name);
});
BTW this won't be invoked either:
pulse_tracker_port.onConnect.addListener(function(port)
{
console.log('Connected to "Pulse Tracker" #port: ' + port.name);
});
This is what I get when I try to do so:
main.js:26 Uncaught TypeError: Cannot read property 'addListener' of undefined
onConnectExternal works for cross-extension messaging between extensions but looks like it doesn't work for native message hosting. Any help would be appreciated. Thanks
chrome.runtime.onConnect and chrome.runtime.onConnectExternal are not relevant here, since they notify you about incoming connections, not about state of outgoing connections.
pulse_tracker_port is a Port object which does not have onConnect property.
What you need to do is to immediately assign a listener to onDisconnect event of the port object. If there was a problem with the connection, the listener will be called and chrome.runtime.lastError will be set:
var pulse_tracker_port = chrome.runtime.connectNative('com.cloudfactory.pulsetracker');
pulse_tracker_port.onDisconnect.addListener(function() {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
}
});
Otherwise, just try to use it, with .postMessage() and .onMessage event. For postMessage, it will throw an error if the port is disconnected.

NodeJS Sockets Sometimes Working

So, I have a node server, running expressjs io (uses socket.io), and I'm building a grid map that tracks coordinates in a database.
Only, I've run into a peculiar issue in that my sockets only listen sometimes.
At first there was no error message, and only by chance I let the page run and I got this error.
Uncaught TypeError: Cannot call method '0' of undefined UkPS99A_w96Ae0K570Nt?t=1395276358213&i=0:1
When I click on the file UkPS99A_w96Ae0K570Nt?t=1395276358213&i=0:1 I get this code:
io.j[0]("8::");
If I refresh the page, every few times it will suddenly work find for about 10 tile clicks, and then it stops working. My database is updating properly until the sockets basically die out.
Here is where I send the coordinates in my map:
io.emit("move", {x:this.x,y:this.y});
Server listening:
app.io.route('move', function(req) {
con.getConnection(function(err){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
});
});
and my socket script:
io.on("talk",function(data) {
console.log(data.x,data.y);
});
My script includes are at the bottom of the page in this order:
<script src="socket.io/socket.io.js"></script>
<script>io = io.connect();</script> <!-- open the socket so the other scripts can use it -->
<script src="../js/sock.js"></script>
<script src="../js/map.js"></script>
Is there something I'm doing wrong to that the socket seems to lose connection and throw some sort of error?
Update: I left the server running longer and a couple more error messages popped up in my console:
Uncaught TypeError: Cannot call method 'close' of null socket.io.js:1967
Uncaught TypeError: Cannot call method 'close' of null socket.io.js:1967
Uncaught TypeError: Cannot call method 'onClose' of null
More update: altered the connection line and added the proper CORS to my server.js
io = io.connect('http://sourceundead.com', {resource : 'socket.io'});
Still the same issue.
You seem to have a connection attrition as you never release them to the pool.
Assuming con is the (bad) name of your pool, instead of
app.io.route('move', function(req) {
con.getConnection(function(err){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
});
});
you should have something like
app.io.route('move', function(req) {
con.getConnection(function(err, connection){
if (err) console.log("Get Connection Error.. "+err);
//removed query because redundant
req.io.emit("talk", {x:req.data.x,y:req.data.y});
connection.release();
});
});
Be careful that using connections must be done with care to ensure they're always released, and it's a little tedious to do especially when handling errors as soon as you have a few queries to do when doing a task.
At some point you might want to use promises to make that easier. Here's a blog post about using bound promises to ease database querying in node.js.

Categories

Resources