/
websocket_handler.cr
57 lines (46 loc) · 1.46 KB
/
websocket_handler.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
require "base64"
require "../../web_socket"
{% if flag?(:without_openssl) %}
require "digest/sha1"
{% else %}
require "openssl/sha1"
{% end %}
class HTTP::WebSocketHandler
include HTTP::Handler
def initialize(&@proc : WebSocket, Server::Context ->)
end
def call(context)
if websocket_upgrade_request? context.request
response = context.response
version = context.request.headers["Sec-WebSocket-Version"]?
unless version == WebSocket::Protocol::VERSION
response.status_code = 426
response.headers["Sec-WebSocket-Version"] = WebSocket::Protocol::VERSION
return
end
key = context.request.headers["Sec-WebSocket-Key"]?
unless key
response.status_code = 400
return
end
accept_code = WebSocket::Protocol.key_challenge(key)
response.status_code = 101
response.headers["Upgrade"] = "websocket"
response.headers["Connection"] = "Upgrade"
response.headers["Sec-WebSocket-Accept"] = accept_code
response.upgrade do |io|
ws_session = WebSocket.new(io)
@proc.call(ws_session, context)
ws_session.run
io.close
end
else
call_next(context)
end
end
private def websocket_upgrade_request?(request)
return false unless upgrade = request.headers["Upgrade"]?
return false unless upgrade.compare("websocket", case_insensitive: true) == 0
request.headers.includes_word?("Connection", "Upgrade")
end
end