Javascript doesn't catch error in WebSocket instantiation - javascript

My socket currently throws net::ERR_CONNECTION_REFUSED because the server isn't running, which I want it to do at the moment.
The problem is that the following piece of code doesn't catch the error. In the console I see an exception on line 2 (with net::ERR_CONNECTION_REFUSED) which I believe shouldn't happen as it's within a try statement.
1 try {
2 ws = new WebSocket('ws://'+ host + ':' + port + '/');
3 }
4 catch (err) {
5 console.log('This never prints');
6 }
7 ws.onerror = function (error) {
8 console.log(error);
9 };
So my question is why is it not being caught?
What I ultimately want is the error message to be displayed elsewhere, but I can't catch it, and line 8 prints an "event" object which doesn't mention net::ERR_CONNECTION_REFUSED, so I'm not sure how to get the error message out.

The WebSocket's connection-time error causes a dispatched event, not a thrown value. This is because throw operations must be synchronous. In order to handle all connection-time errors as thrown errors, the WebSocket constructor would need to completely suspend all script execution and UI interaction until the entire WebSocket handshake had completed. Instead, the connection process runs asynchronously, thereby allowing the browser thread to continue working while the WebSocket connection initializes in the background. Because of the connection's asynchronous nature, the WebSocket must report errors via error events, since the synchronous new WebSocket operation has already finished by the time the asynchronous connection task encounters an error.
The ERR_CONNECTION_REFUSED message you see is purely for the benefit of developers; it is not accessible to the script in any way. It does not have any representation within the JavaScript environment. It's just a red-colored message that appears in your console to inform you, the human looking at the browser, about an error.
The error handler event is the correct place to respond to failure, but the lack of script-readable connection-time error information is by design. From the WHATWG spec for the WebSocket API:
User agents must not convey any failure information to scripts in a way that would allow a script to distinguish the following situations:
A server whose host name could not be resolved.
A server to which packets could not successfully be routed.
A server that refused the connection on the specified port.
A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be verified).
A server that did not complete the opening handshake (e.g. because it was not a WebSocket server).
A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer).
A WebSocket server that abruptly closed the connection after successfully completing the opening handshake.
[...] Allowing a script to distinguish these cases would allow a script to probe the user's local network in preparation for an attack.
The browser is deliberately omitting any useful information as required by the spec. The spec authors are concerned that access to this information could allow a malicious Web page to gain information about your network, so they require browsers report all connection-time errors in an indistinguishable way.

I tried creating fiddle with it
and I am able to see line printed.
host='localhost';
port=100;
try {
ws = new WebSocket('ws://'+ host + ':' + port + '/');
}
catch (err) {
console.log('This never prints');
}
ws.onerror = function (error) {
console.log(error);
};
https://jsfiddle.net/xzumgag0/

Chrome based browsers: In my case I just wanted to get rid of the error message from the console. In which case you can enter this regex into the console filter:
-/Websocket\sconnection.*failed/

Related

Web application using websockets “Could not establish connection. Receiving end does not exist."

Java server, javascript client, no special libraries, plain text HTTP/1.1 and websocket connections.
Server side written (in Eclipse) using JDK 16 and a websocket jar found in Tomcat, version 10.0.2. (Many permutations of other JDKs and websocket jars have also been tried.)
Two web applications. Tomcat 10.0.2 on PC, 10.0.7 on server. Both apps run on Windows 10. Deployed to a Ubuntu 20.04 server. Both programs display the initial HTTP data. One program gets a websocket connection and works, the other fails to get the websocket connection. Both use the same code to calculate the target URL for the websocket connection:
window.onload = function() {
var target = "ws://" + location.host + "/[context]/[endpoint]";
console.log("target: " + target);
try {
if ('WebSocket' in window) {
socket = new WebSocket(target);
} else if ('MozWebSocket' in window) {
socket = new MozWebSocket(target);
} else {
alert('WebSocket is not supported by this browser.');
return;
}
} catch (e) {
console.log("websocket connection exception: " + e.description);
}
...
Where only [context] and [endpoint] differ. Recall that these URLs work on a PC. I believe they are “well-formed”/valid.
Results for the web app that fails:
Firefox:
uncaught exception: Could not establish connection. Receiving end does not exist.
GET ws://35.xxx.xx.xx:8080/Memory/MemoryEndpoint[HTTP/1.1 404 70ms]
Firefox can’t establish a connection to the server at ws://35.xxx.xx.xx:8080/Memory/MemoryEndpoint.
Chrome:
Error handling response: TypeError: Cannot read property 'encrypt' of undefined
at Object.13 (chrome-extension://bkdgflcldnnnapblkhphbgpggdiikppg/public/js/content-scripts/autofill.js:1427:33)
. . .
game.js:31 WebSocket connection to 'ws://xxx.xx.xx.xx:8080/Memory/MemoryEndpoint' failed:
Chrome continues for many lines regarding the 'encrypt' undefined issue. I have no idea what that is about but it might be very relevant. The last line above implies that some reason for the failure might be given on the next line, but it is empty.
Neither browser logs the expected exception text beginning with: "websocket connection exception:".
Tomcat log files are all clean except for some curious entries in localhost__access_log such as:
209.90.225.218 - - [11/Jul/2021:00:43:33 +0000] "HEAD /robots.txt HTTP/1.0" 404 -
And others mentioning /invoker/readonly, /login, /jenkins/login, /nifi/.
The fact that both programs do return results from the Tomcat server tells me that permissions on ports etc are all sufficient. I've also dug into netstat results and the like, reviewed firewall settings, read many many articles and requests for help. (Probably irrelevant because Tomcat does return expected HTTP/1.1 data.) No luck.
I need this program to work. I would pay a cash reward for a solution to this by 07-16-2021, though I don't know how to discretely negotiate that. :-(
Problem resolved, though I don't understand the cause. Recall: the web application ran fine on development PC deployed to Tomcat version 10.0.2, for various JDKs, websocket libraries (including one found in the Tomcat 10.0.7 that had been installed on the VM). The app failed on the Ubuntu VM. A friend installed Tomcat 10.0.8 in the VM. Presto! websockets work.

html5 / js websocket: setting event handlers *after* connecting?

A lot of HTML5 websocket example code does something like this:
websocket = new WebSocket('ws://example.com');
websocket.onopen = MyOpenHandler;
websocket.onerror = MyErrorHandler;
Of course with the intention of MyOpenHandler being called upon connecting, or MyErrorHandler if the connection fails.
Exactly when does the actual connection takes place and is the above event handling approach guaranteed to work, even if the connection happens or fails immediately?
What I mean is, wouldn't an approach like this make more sense:
websocket = new WebSocket;
websocket.onopen = MyOpenEventHandler;
websocket.onerror = MyErrorHandler;
websocket.connect('ws://example.com');
I.e. connect after the event handlers have been set, to be 100% sure they are being called when appropriate.
Or am I just being paranoia here, and is the reference implementation (the topmost example) actually correct?
Addendum
I did some additional testing with the following code:
var websocket = new WebSocket("ws://localhost:8000"); // this connection will fail
alert("Created the websocket, now let's set the event handler");
websocket.onerror = function(e) { alert("Could not connect") }
This fails, the "Could not connect" alert does NOT appear. However if I remove that former alert (the one on line 2), it does.
This kinda worries me. Apparently it's possible the connection already failed before I got the chance to set the onerror event handler, thus the handler never gets called. How can I be 100% certain that the connection is guaranteed to take place after I set the appropriate handlers?
https://www.w3.org/TR/2011/WD-websockets-20110419/#the-websocket-interface
I believe that number 6 below answers your question.
When the WebSocket() constructor is invoked, the UA must run these steps:
Parse a WebSocket URL's components from the url argument, to obtain host, port, resource name, and secure. If this fails, throw a SYNTAX_ERR exception and abort these steps.
If port is a port to which the user agent is configured to block access, then throw a SECURITY_ERR exception. (User agents typically block access to well-known ports like SMTP.)
Access to ports 80 and 443 should not be blocked, including the unlikely cases when secure is false but port is 443 or secure is true but port is 80.
If protocols is absent, let protocols be an empty array.
Otherwise, if protocols is present and a string, let protocols instead be an array consisting of just that string.
If any of the values in protocols occur more than once or contain characters with Unicode code points less than U+0021 or greater than U+007E (i.e. the space character or any characters that are not printable ASCII characters), then throw a SYNTAX_ERR exception and abort these steps.
Let origin be the ASCII serialization of the origin of the script that invoked the WebSocket() constructor, converted to ASCII lowercase.
Return a new WebSocket object, and continue these steps in the background (without blocking scripts).
Establish a WebSocket connection to a host host, on port port (if one was specified), from origin, with the flag secure, with resource name as the resource name, with protocols as the (possibly empty) list of protocols, and with the defer cookies flag set.
UPDATE
https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol
When the WebSocket connection is established, the user agent must queue a task to run these steps:
Change the readyState attribute's value to OPEN (1).
Change the extensions attribute's value to the extensions in use, if is not the null value. [WSP]
Change the protocol attribute's value to the subprotocol in use, if is not the null value. [WSP]
Fire an event named open at the WebSocket object.
NOTE
Since the algorithm above is queued as a task, there is no race condition between the WebSocket connection being established and the script setting up an event listener for the open event.

Targetting HTTP Error Messages

I'm trying to send an JSON-encoded data string to a remote machine using AJAX.
Whenever I try to send the data string to the remote machine, one of two error messages will occur:
XMLHttpRequest cannot load http://10.1.0.139:8000/.
No 'Access-Control-Allow-Origin' header is present on
the requested resource. Origin 'http://localhost' is
therefore not allowed access.
This message occurs when the remote machine is powered on and accepting connections. However, although I am getting this error, my code is working exactly as I want it to - as in, the remote machine receives the correct piece of data.
POST http://10.1.0.139:8000/ net::ERR_CONNECTION_REFUSED
And this message occurs when the remote machine is either powered off or does not have it's own server running that accepts incoming requests and connections.
The problem is, I want to be able to differentiate between these two error messages, and I do not know how. I can't use AJAX callbacks such as error() or fail(), because there will always be an error - and it will say that there has been a failed request despite a HTTP status of 200 suggesting that everything is okay (when the first error message shows).
Is there a way that I can do something similar to a Pseudo command of 'IF I FAIL TO CONNECT TO REMOTE MACHINE, DO...'
EDIT
Something I've noticed just now is that my remote machine does not display incoming connections from Internet Explorer - instead it displays this:
XMLHttpRequest: Network Error 0x2efd,
Could not complete the operation due to error 00002efd.
Use the XMLHttpRequest timeout
var xhr = new window.XMLHttpRequest();
var data = 'x=1';
xhr.open('POST', 'http://10.1.0.139:8000/');
xhr.timeout = 5000;
xhr.addEventListener('timeout', function(e) {
// handle dead server
console.log('timeout');
console.error(e);
});
xhr.addEventListener('error', function(e) {
// handle error - CORS probably in this case
console.log('error');
console.error(e);
});
xhr.addEventListener('load', function(e) {
// handle success
console.log('load');
console.info(e);
});
xhr.send(data);
This triggers error in the case of a CORS error, and timeout in the case of no server

Handling unsuccessful websocket upgrade requests in Javascript Client

I want to have a javascript client process get the HTTP status code that a server is returning when the client makes a websocket upgrade request and that request is unsuccessful.
I have my server returning HTTP 400 to indicate that a websocket upgrade is unsuccessful.
I am using Google Chrome and when i open the developer console I can see the following message:
WebSocket connection to 'wss://' failed: Error during WebSocket handshake: Unexpected response code: 400
However, the onerror handler does not contain this message, it receives a 1006 error but does not indicate that the closure occured as a result of getting HTTP 400.
How does a javascript developer handle handshake errors? I would like to provide the client with an informative message when they get a handshake error.
I have put the websocket error below, it does not seem to contain anything that I can use to indicate that this error is a result of a websocket handshake error.
Websocket Error: {"path":{"length":0},"cancelBubble":false,"returnValue":true,"srcElement":{"binaryType":"blob","protocol":"","extensions":"","bufferedAmount":0,"readyState":3,"url":"wss://<my address>","URL":"wss://<my address>"},"defaultPrevented":false,"timeStamp":1417828938039,"cancelable":false,"bubbles":false,"eventPhase":2,"currentTarget":{"binaryType":"blob","protocol":"","extensions":"","bufferedAmount":0,"readyState":3,"url":"wss://<my address>","URL":"wss://<my address>"},"target":{"binaryType":"blob","protocol":"","extensions":"","bufferedAmount":0,"readyState":3,"url":"wss://<my address>","URL":"wss://<my address>"},"type":"error"}
I am afraid there is no way from Javascript to know the HTTP status code of the negotiation.
There are defined closing codes, and 1006 only means that the connection is closed abruptly, but the protocol even allows to close the connection without providing a reason. That, together with the readyState API, are the only tools you have to diagnosed the reason of the problem.

chrome getting new Error during WebSocket handshake

have node.js websockets running through haproxy, and has been running successfully for several months.
now now giving error
Error during WebSocket handshake: 'Connection' header value is not 'Upgrade'
same code / setup is still working on development computer
any ideas / suggestions more than appreciated!
firefox works ok! chrome errors from main server, but works correctly local
There is something terribly concerning here with this error message. The "Connection" header value should not be "Upgrade" but should contain "Upgrade". "Connection" is an HTTP header field which is hop-by-hop and may contain multiple tokens, including Upgrade, but also a number of other ones. This is in RFC6455 page 17 :
" 5. The request MUST contain an |Upgrade| header field whose value MUST include the "websocket" keyword."
So I think that something is wrong in the server software, or at least in the error message. You should definitely take a network capture to be sure.

Categories

Resources