19

I'm having trouble opening a websocket in Chrome. It seems that there is some CORS policy in chrome for websockets.

If I am on www.example.com and attempt to open the websocket at api.example.com it'll say pending on the console network tab, and will fire the onerror with a message WebSocket connection to 'wss://api.example.com' failed: Connection closed before receiving a handshake response. If I look at the server I do not see a request for a web socket connection being made, so there is no options request to respond to, or Ability to set an Access-Control-Allow-Origin header. However if I first make a request to api.example.com which on the browser will redirect me back to www.example.com it'll work fine.

Are you required to use the same origin for websocket requests in chrome?

Note: this issue is only with chrome.

fab
  • 317
  • 4
  • 20
Josh Wilson
  • 3,585
  • 7
  • 32
  • 53
  • Based on the dates here it like this has been an issue for a long time, but we've reproduced it in some cases in Chrome today and the Chromium team claims it was a recent regression. Follow the bug report here: https://crbug.com/993907 – Nick G Aug 30 '19 at 17:27

6 Answers6

25

There is no browser enforced CORS with WebSocket. Here are 2 things that can go wrong (assuming you use both HTTPS and WSS):

  • the server enforces an Origin. The Origin HTTP header is set by the browser to the origin of the HTML page containing the JavaScript that is opening the WebSocket connection. A server MAY check that header and deny. But since you say other browsers are working (which?), this is unlikely
  • since you are using wss, the server certificate MUST be completely valid, and acceptable to the browser without any user interaction. Is this the case?
oberstet
  • 21,353
  • 10
  • 64
  • 97
  • I have a hard time believing that the issue with Chrome isn't something with CORS. I have it working by first sending an options request to my server. The websocket connection works as expected iff the options request goes through successfully. – Josh Wilson Mar 26 '14 at 00:35
  • 8
    As said, CORS does not apply to WebSocket. – oberstet Mar 26 '14 at 00:53
4

I came across this issue again. I still haven't figured out why, but making an OPTIONS (or any other) request to the subdomain first allows the connection to be opened.

This only seems to be a problem with wss connections, and has popped up across multiple domains and certificates.

YakovL
  • 7,557
  • 12
  • 62
  • 102
Josh Wilson
  • 3,585
  • 7
  • 32
  • 53
1

This sounds like it has to do with making cross-origin requests that are not "simple". HTTP requests that are not simple are "preflighted" by the browser (Chrome at least) with "OPTIONS" automatically. I'm guessing the browser is just enforcing this behavior.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

mhgbrown
  • 91
  • 6
  • 1
    How would it be possible to make a "non simple" Websocket connection? The WS constructor takes no options, which means you can't a) set custom headers, or b) use a verb other than GET. – Coderer Jul 08 '20 at 10:46
1

For me, this ended up being because Socket.IO uses HTTP to set up the connection. Their docs mention how to resolve this. For me, changing my server initialization as mentioned in the docs fixed it:

const io = new socketIo.Server(5555, {
    cors: {
        origin: "http://localhost:4200"  // Angular port
    }
});
Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
0

If you are not the one running the server or don't know the stack used, it will be hard to figure out.

One example of server software with websocket is gotty (it uses implementation github.com/gorilla/websocket).

For gotty server to allow any origin value, command & params to start it must be:

 > gotty -w  --ws-origin ".*" bash

--ws-origin value A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default [$GOTTY_WS_ORIGIN]

On a chrome console, you can now execute below without errors:

url = 'ws://<host>:<port>/ws';  
const w = new WebSocket(url) 

It seems the protocol do mention it:

The |Origin| header field [RFC6454] is used to protect against
unauthorized cross-origin use of a WebSocket server by scripts using
the WebSocket API in a web browser.

newbee
  • 101
  • 1
  • 4
-1

Try setting an Access-Control-Allow-Origin header on api.example.com that allows www.example.com.

webinista
  • 3,750
  • 1
  • 20
  • 21
  • 1
    This wont help since the request is never made. Updating the question to describe that. – Josh Wilson Mar 25 '14 at 20:50
  • I have a similar problem, my application is built using Angular 7. I am making an ajax call to a BPMS server which works fine in IE but I have a CORS error in Chrome. However when I copy the ajax url to the Chrome browser I have all the data. Can anyone help? – David Sagang Aug 18 '20 at 16:39