emscripten
emscripten copied to clipboard
Can't connect to a websocket from Chrome.
Version of emscripten/emsdk: emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.34 (57b21b8fdcbe3ebb523178b79465254668eab408) clang version 17.0.0 (https://github.com/llvm/llvm-project a031f72187ce495b9faa4ccf99b1e901a3872f4b) Target: wasm32-unknown-emscripten Thread model: posix
My emscripten app connects to a websocket in a C++ server. This server is based on boost beast, I've got their simple example:
void do_session(tcp::socket& socket)
{
try
{
// Construct the stream by moving in the socket
websocket::stream<tcp::socket> ws{std::move(socket)};
ws.set_option(websocket::stream_base::timeout::suggested(beast::role_type::server));
// Set a decorator to change the Server of the handshake
ws.set_option(websocket::stream_base::decorator(
[](websocket::response_type& res)
{
res.set(http::field::server, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-server-sync");
}));
// Accept the websocket handshake
ws.accept();
//ws.accept(buffer.data());
for (;;)
{
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message
ws.read(buffer);
}
}
catch (beast::system_error const& se)
{
// This indicates that the session was closed
if (se.code() != websocket::error::closed)
std::cerr << "Error: " << se.code().message() << std::endl;
}
catch (std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
}
int main(int argc, char *argv[])
{
net::io_context ioc{1};
tcp::resolver resolver(ioc);
//tcp::acceptor acceptor{ioc, resolver.resolve("0.0.0.0", "8010")};
tcp::acceptor acceptor{ioc, {net::ip::make_address("0.0.0.0"), 8010}};
while (!service_context.exit)
{
tcp::socket socket{ioc};
acceptor.accept(socket);
logger->Info("Connection accepted");
std::thread{std::bind(&do_session, std::move(socket))}.detach();
}
}
In my emscripten app I use boost::asio sockets. Although, I far as I unserstand, it doesn't matter. This is the params of the client app:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_SDL=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_SDL_TTF=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_SDL_IMAGE=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_FREETYPE=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --preload-file ./fonts")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ALLOW_MEMORY_GROWTH")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_DISABLE_EXCEPTION_CATCHING")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WEBSOCKET_SUBPROTOCOL='text'")
So, it works nice in Firefox (connects well). Also, it connects using a test extension in Chrome. But it doesn't work when I run the client in Chrome. In Debug I see:
WebSocket connection to 'ws://127.0.0.1:8010/' failed:
Stack trace points on createPeer(),
ws = new WebSocketConstructor(url, opts);
yutovo_web.worker.js:192 worker.js onmessage() captured an uncaught exception: boost::wrapexcept<boost::system::system_error>: write: Socket not connected [system:53]
Server exception: "End of file". Any suggestions?
I've got a simple python server to test:
from simple_websocket_server import WebSocketServer, WebSocket
class SimpleEcho(WebSocket):
def handle(self):
# echo message back to client
self.send_message(self.data)
def connected(self):
print(self.address, 'connected')
def handle_close(self):
print(self.address, 'closed')
server = WebSocketServer('', 8010, SimpleEcho)
server.serve_forever()
with the same result...
What I see in Wireshark: In Firefox, where all is ok:
GET / HTTP/1.1
Host: 127.0.0.1:8010
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0
Accept: */*
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br
Sec-WebSocket-Version: 13
Origin: http://localhost:6931
Sec-WebSocket-Protocol: text
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: X3M/D9V4gnEJ/kgn7FndUA==
Connection: keep-alive, Upgrade
Sec-Fetch-Dest: websocket
Sec-Fetch-Mode: websocket
Sec-Fetch-Site: cross-site
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: 8KmtW7aV6HAZkl8K4TlrvYAi5Sw=
..=].-i8{Y..Test
In Chrome, where the connection fails:
GET / HTTP/1.1
Host: 127.0.0.1:8010
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Upgrade: websocket
Origin: http://localhost:6931
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Sec-WebSocket-Key: ds3grl+Ked2SanDzRl8F8A==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: text
HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: oyK9uvxYMBBySj50gB3JzGedn8A=
The server wants to upgrade, but the client closes the connection...
Hi,
I encountered the same issue, things working well on Firefox, but Chromium-based browsers are not opening the WebSocket.
Did you find a solution?
I did it with web socket in JS. I call JS wrappers from C++, do send/receive, and return result into C++.
Thank you, unfortunately that's not a solution we can apply so we'll continue to investigate.
Any solution on this? I have the same issue, and it happens only when i'm using asio based WS server (websocketpp or beast). With another WS servers chrome works fine.
Is there workaround for this?
I think a secure WebSocket is needed, technically an NGINX configured to expose the WebSocket with a certificate it should work.
What do you mean needed? For sure i'm using wss connection from chrome. And SSL handshake on the server was accepted. So the issue isn't SSL related.
Then disregard my comment, the issue I had was because of not using secure WebSocket
I had what is possibly a similar problem, in that Firefox would connect to a secure web socket, but Chrome/Edge wouldn't. On Windows, the log also had:
WebSocket connection to 'wss://xyz/' failed:
Which wasn't much help, as the error is missing. However, running Chromium on Linux gave an error:
WebSocket connection to 'wss://xyz/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
I needed to modify the server (written using Qt), with a call to:
QWebSocketServer::setSupportedSubprotocols({"binary"})
Thanks it really helped me, i was passing info in the Subprotocols field at the initialization of the WebSocket. I removed that and used this solution :
https://stackoverflow.com/questions/4361173/http-headers-in-websockets-client-api
it work now on both Firefox and Chrome