Async::WebSocket gemの素振り その5 - @ledsun blog で::Async::WebSocket::Response.forが気になりました。
::Async::WebSocket::Response.forのソースコードです。
def self.for(request, headers = nil, **options, &body) if request.version =~ /http\/1/i return UpgradeResponse.new(request, headers, **options, &body) elsif request.version =~ /http\/2/i return ConnectResponse.new(request, headers, **options, &body) end raise UnsupportedVersionError, "Unsupported HTTP version: #{request.version}!" end
実態は::Async::WebSocket::UpgradeResponseインスタンスを返すだけです。
現在の実験環境はHTTP1です。
::Async::WebSocket::UpgradeResponseまで展開してみます。
require 'async/http/body/hijack' require 'async/websocket/connection' require 'protocol/websocket/framer' require 'protocol/websocket/extensions' require "protocol/rack/request" require "protocol/rack/adapter" class App def self.response(request, &block) headers = ::Protocol::HTTP::Headers.new accept_nounce = request.headers[::Protocol::WebSocket::Headers::SEC_WEBSOCKET_KEY]&.first headers.add ::Protocol::WebSocket::Headers::SEC_WEBSOCKET_ACCEPT, ::Protocol::WebSocket::Headers::Nounce.accept_digest(accept_nounce) body = Async::HTTP::Body::Hijack.wrap(request, &block) ::Protocol::HTTP::Response.new(request.version, 101, headers, body, ::Protocol::WebSocket::Headers::PROTOCOL) end def self.call(env) req = ::Protocol::Rack::Request[env] res = self.response(req) do |stream| framer = ::Protocol::WebSocket::Framer.new(stream) conn = ::Async::WebSocket::Connection.call framer, nil, ::Protocol::WebSocket::Extensions::Server.default # Echo back! while message = conn.read conn.write message end res end Protocol::Rack::Adapter.make_response(env, res) end end run App
リクエストのSec-WebSocket-Keyヘッダーの値のダイジェストをレスポンスのSec-WebSocket-Acceptヘッダーで返します。
RubyでWebSocketサーバー - @ledsun blogでやったことを思い出しました。
WebSocketメッセージを処理するブロックはAsync::HTTP::Body::Hijack.wrapで動くようです。