/
draft75.rb
102 lines (85 loc) · 2.42 KB
/
draft75.rb
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
module WebSocket
class Driver
class Draft75 < Driver
def initialize(socket, options = {})
super
@stage = 0
@closing = false
@headers['Upgrade'] = 'WebSocket'
@headers['Connection'] = 'Upgrade'
@headers['WebSocket-Origin'] = @socket.env['HTTP_ORIGIN']
@headers['WebSocket-Location'] = @socket.url
end
def version
'hixie-75'
end
def close(reason = nil, code = nil)
return false if @ready_state == 3
@ready_state = 3
emit(:close, CloseEvent.new(nil, nil))
true
end
def parse(chunk)
return if @ready_state > 1
@reader.put(chunk)
@reader.each_byte do |octet|
case @stage
when -1 then
@body << octet
send_handshake_body
when 0 then
parse_leading_byte(octet)
when 1 then
@length = (octet & 0x7F) + 128 * @length
if @closing and @length.zero?
return close
elsif (octet & 0x80) != 0x80
if @length.zero?
@stage = 0
else
@skipped = 0
@stage = 2
end
end
when 2 then
if octet == 0xFF
@stage = 0
emit(:message, MessageEvent.new(Driver.encode(@buffer, UNICODE)))
else
if @length
@skipped += 1
@stage = 0 if @skipped == @length
else
@buffer << octet
return close if @buffer.size > @max_length
end
end
end
end
end
def frame(buffer, type = nil, error_type = nil)
return queue([buffer, type, error_type]) if @ready_state == 0
frame = [0x00, buffer, 0xFF].pack('CA*C')
@socket.write(frame)
true
end
private
def handshake_response
start = 'HTTP/1.1 101 Web Socket Protocol Handshake'
headers = [start, @headers.to_s, '']
headers.join("\r\n")
end
def parse_leading_byte(octet)
if (octet & 0x80) == 0x80
@length = 0
@stage = 1
else
@length = nil
@skipped = nil
@buffer = []
@stage = 2
end
end
end
end
end