-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
This example
require "http/web_socket"
ws_handler = HTTP::WebSocketHandler.new do |socket|
socket.on_message do |message|
puts "server got: #{message}"
socket.stream do |io|
io << message
io.flush
end
end
end
server = HTTP::Server.new([ws_handler])
spawn do
address = server.bind_tcp("0.0.0.0", 8080)
puts "Listening on http://#{address}"
server.listen
end
Fiber.yield
socket = HTTP::WebSocket.new("localhost", "/", 8080)
received = [] of String
socket.on_binary do |message|
puts "Received: #{String.new(message)}"
received << String.new(message)
end
socket.on_close do |code, msg|
puts "Socket closed: #{code}, #{msg}"
end
spawn do
socket.run
end
socket.send("Hello")
socket.send("World")
sleep 0.1.seconds
puts "All messages received: #{received}"will print
All messages received: ["Hello", "", "World", ""]
I get these extra empty messages.
I think it's because of HTTP::WebSocket::Protocol::StreamIO#flush. I'm calling #flush without any argument in the stream block, meaning that final=true. When the block is done #stream will call #flush again but this time with @opcode = Opcode::CONTINUATION (which was set by my flush call) and an empty buffer.
I can fix this by make sure to call flush(false), but that doesn't help I want to use a json builder:
socket.stream do |io|
JSON.build do |json|
json.string "hello world"
end # here io.flush is called
endOne big problem though is that a web browser will close the connection when it receives these empty frames, probably because of the opcode?
Maybe this means that HTTP::WebSocket is too naive and should validate incoming frames better and close the connection too?
I'm running
Crystal 1.18.2 (2025-10-21)
LLVM: 21.1.8
Default target: aarch64-apple-darwin24.6.0