mirror of
https://github.com/faye/websocket-driver-ruby.git
synced 2025-11-01 13:59:38 +00:00
Don't catch errors from event listeners. Instead, make sure that in all parsing methods in Hybi, @stage is set before any user called is invoked so the parser is in the right state before code that might raise is called.
This commit is contained in:
@@ -121,17 +121,7 @@ module WebSocket
|
||||
|
||||
private
|
||||
|
||||
def emit(*args)
|
||||
super
|
||||
rescue Exception => error
|
||||
emit(:error, error)
|
||||
shutdown(1011, error.message)
|
||||
end
|
||||
|
||||
def shutdown(code, reason)
|
||||
@ready_state = 3
|
||||
@stage = 5
|
||||
emit(:close, CloseEvent.new(code, reason))
|
||||
end
|
||||
|
||||
def open
|
||||
|
||||
@@ -108,15 +108,15 @@ module WebSocket
|
||||
when 3 then
|
||||
buffer = @reader.read(4)
|
||||
if buffer
|
||||
@frame.masking_key = buffer
|
||||
@stage = 4
|
||||
@frame.masking_key = buffer
|
||||
end
|
||||
|
||||
when 4 then
|
||||
buffer = @reader.read(@frame.length)
|
||||
if buffer
|
||||
emit_frame(buffer)
|
||||
@stage = 0
|
||||
emit_frame(buffer)
|
||||
end
|
||||
|
||||
else
|
||||
@@ -255,17 +255,19 @@ module WebSocket
|
||||
headers.join("\r\n")
|
||||
end
|
||||
|
||||
def shutdown(code, reason)
|
||||
def shutdown(code, reason, &error)
|
||||
frame(reason, :close, code) if @ready_state < 2
|
||||
@frame = @message = nil
|
||||
@ready_state = 3
|
||||
@stage = 5
|
||||
@extensions.close
|
||||
super
|
||||
error.call if error
|
||||
emit(:close, CloseEvent.new(code, reason))
|
||||
end
|
||||
|
||||
def fail(type, message)
|
||||
return if @ready_state > 1
|
||||
emit(:error, ProtocolError.new(message))
|
||||
shutdown(ERRORS[type], message)
|
||||
shutdown(ERRORS[type], message) { emit(:error, ProtocolError.new(message)) }
|
||||
end
|
||||
|
||||
def parse_opcode(data)
|
||||
@@ -279,6 +281,8 @@ module WebSocket
|
||||
@frame.rsv3 = rsvs[2]
|
||||
@frame.opcode = (data & OPCODE)
|
||||
|
||||
@stage = 1
|
||||
|
||||
unless @extensions.valid_frame_rsv?(@frame)
|
||||
return fail(:protocol_error,
|
||||
"One or more reserved bits are on: reserved1 = #{@frame.rsv1 ? 1 : 0}" +
|
||||
@@ -297,37 +301,34 @@ module WebSocket
|
||||
if @message and OPENING_OPCODES.include?(@frame.opcode)
|
||||
return fail(:protocol_error, 'Received new data frame but previous continuous frame is unfinished')
|
||||
end
|
||||
|
||||
@stage = 1
|
||||
end
|
||||
|
||||
def parse_length(data)
|
||||
@frame.masked = (data & MASK) == MASK
|
||||
if @require_masking and not @frame.masked
|
||||
return fail(:unacceptable, 'Received unmasked frame but masking is required')
|
||||
end
|
||||
|
||||
@frame.length = (data & LENGTH)
|
||||
@frame.masked = (data & MASK) == MASK
|
||||
|
||||
if @frame.length >= 0 and @frame.length <= 125
|
||||
return unless check_frame_length
|
||||
@stage = @frame.masked ? 3 : 4
|
||||
return unless check_frame_length
|
||||
else
|
||||
@frame.length_bytes = (@frame.length == 126) ? 2 : 8
|
||||
@stage = 2
|
||||
@frame.length_bytes = (@frame.length == 126) ? 2 : 8
|
||||
end
|
||||
|
||||
if @require_masking and not @frame.masked
|
||||
return fail(:unacceptable, 'Received unmasked frame but masking is required')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_extended_length(buffer)
|
||||
@frame.length = integer(buffer)
|
||||
@stage = @frame.masked ? 3 : 4
|
||||
|
||||
unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.length <= 125
|
||||
return fail(:protocol_error, "Received control frame having too long payload: #{@frame.length}")
|
||||
end
|
||||
|
||||
return unless check_frame_length
|
||||
|
||||
@stage = @frame.masked ? 3 : 4
|
||||
end
|
||||
|
||||
def check_frame_length
|
||||
|
||||
@@ -358,25 +358,6 @@ describe WebSocket::Driver::Hybi do
|
||||
driver.parse [0x89, 0x04, 0x4f, 0x48, 0x41, 0x49].pack("C*")
|
||||
expect(@bytes).to eq [0x8a, 0x04, 0x4f, 0x48, 0x41, 0x49]
|
||||
end
|
||||
|
||||
describe "if a message listener raises an error" do
|
||||
before do
|
||||
driver.on :message, -> e { raise StandardError, "event error" }
|
||||
driver.parse [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f].pack("C*")
|
||||
end
|
||||
|
||||
it "triggers the onerror event" do
|
||||
expect(@error.message).to eq("event error")
|
||||
end
|
||||
|
||||
it "triggers the onclose event" do
|
||||
expect(@close).to eq [1011, "event error"]
|
||||
end
|
||||
|
||||
it "changes the state to :closed" do
|
||||
expect(driver.state).to eq :closed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :frame do
|
||||
|
||||
Reference in New Issue
Block a user