Skip to content

Commit

Permalink
Refactor error code classes and support 1009 code
Browse files Browse the repository at this point in the history
* Renamed DataError to WSProtocolError to be consistent with the specification terminology, and made it clear that this always represents a closing scenario
* Added comments to other errors to clarify their use
* Added WSMessageTooBigError with associated 1009 error code
  • Loading branch information
mloughran committed Jan 31, 2012
1 parent 8772645 commit 57b10b7
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 20 deletions.
4 changes: 2 additions & 2 deletions lib/em-websocket/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ def receive_data(data)
trigger_on_error(e)
# Errors during the handshake require the connection to be aborted
abort
rescue WebSocketError => e
rescue WSProtocolError => e
debug [:error, e]
trigger_on_error(e)
close_websocket_private(1002) # 1002 indicates a protocol error
close_websocket_private(e.code)
rescue => e
debug [:error, e]
# These are application errors - raise unless onerror defined
Expand Down
6 changes: 3 additions & 3 deletions lib/em-websocket/framing03.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def process_data(newdata)

# Addition to the spec to protect against malicious requests
if payload_length > MAXIMUM_FRAME_LENGTH
raise DataError, "Frame length too long (#{payload_length} bytes)"
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
end

# Check buffer size
Expand All @@ -78,7 +78,7 @@ def process_data(newdata)
frame_type = opcode_to_type(opcode)

if frame_type == :continuation && !@frame_type
raise WebSocketError, 'Continuation frame not expected'
raise WSProtocolError, 'Continuation frame not expected'
end

if more
Expand Down Expand Up @@ -156,7 +156,7 @@ def type_to_opcode(frame_type)
end

def opcode_to_type(opcode)
FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode")
end

def data_frame?(type)
Expand Down
6 changes: 3 additions & 3 deletions lib/em-websocket/framing05.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def process_data(newdata)

# Addition to the spec to protect against malicious requests
if payload_length > MAXIMUM_FRAME_LENGTH
raise DataError, "Frame length too long (#{payload_length} bytes)"
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
end

# Check buffer size
Expand All @@ -83,7 +83,7 @@ def process_data(newdata)
frame_type = opcode_to_type(opcode)

if frame_type == :continuation && !@frame_type
raise WebSocketError, 'Continuation frame not expected'
raise WSProtocolError, 'Continuation frame not expected'
end

if !fin
Expand Down Expand Up @@ -157,7 +157,7 @@ def type_to_opcode(frame_type)
end

def opcode_to_type(opcode)
FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode")
end

def data_frame?(type)
Expand Down
4 changes: 2 additions & 2 deletions lib/em-websocket/framing07.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def process_data(newdata)
frame_type = opcode_to_type(opcode)

if frame_type == :continuation && !@frame_type
raise WebSocketError, 'Continuation frame not expected'
raise WSProtocolError, 'Continuation frame not expected'
end

if !fin
Expand Down Expand Up @@ -158,7 +158,7 @@ def type_to_opcode(frame_type)
end

def opcode_to_type(opcode)
FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
FRAME_TYPES_INVERSE[opcode] || raise(WSProtocolError, "Unknown opcode")
end

def data_frame?(type)
Expand Down
6 changes: 3 additions & 3 deletions lib/em-websocket/framing76.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def process_data(newdata)

# Addition to the spec to protect against malicious requests
if length > MAXIMUM_FRAME_LENGTH
raise DataError, "Frame length too long (#{length} bytes)"
raise WSMessageTooBigError, "Frame length too long (#{length} bytes)"
end

if @data.getbyte(pointer+length-1) == nil
Expand All @@ -69,12 +69,12 @@ def process_data(newdata)

if @data.getbyte(0) != 0x00
# Close the connection since this buffer can never match
raise DataError, "Invalid frame received"
raise WSProtocolError, "Invalid frame received"
end

# Addition to the spec to protect against malicious requests
if @data.size > MAXIMUM_FRAME_LENGTH
raise DataError, "Frame length too long (#{@data.size} bytes)"
raise WSMessageTooBigError, "Frame length too long (#{@data.size} bytes)"
end

# Optimization to avoid calling slice! unnecessarily
Expand Down
2 changes: 1 addition & 1 deletion lib/em-websocket/handler_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def self.build_with_request(connection, request, remains, secure = false, debug
Handler13.new(connection, request, debug)
else
# According to spec should abort the connection
raise WebSocketError, "Protocol version #{version} not supported"
raise HandshakeError, "Protocol version #{version} not supported"
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/em-websocket/message_processor_06.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def message(message_type, extension_data, application_data)
nil
when 1
# Illegal close frame
raise DataError, "Close frames with a body must contain a 2 byte status code"
raise WSProtocolError, "Close frames with a body must contain a 2 byte status code"
else
application_data.slice!(0, 2).unpack('n').first
end
Expand Down
18 changes: 17 additions & 1 deletion lib/em-websocket/websocket.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
module EventMachine
module WebSocket
# All errors raised by em-websocket should descend from this class
#
class WebSocketError < RuntimeError; end

# Used for errors that occur during WebSocket handshake
#
class HandshakeError < WebSocketError; end
class DataError < WebSocketError; end

# Used for errors which should cause the connection to close.
# See RFC6455 §7.4.1 for a full description of meanings
#
class WSProtocolError < WebSocketError
def code; 1002; end
end

# 1009: Message too big to process
class WSMessageTooBigError < WSProtocolError
def code; 1009; end
end

def self.start(options, &blk)
EM.epoll
Expand Down
4 changes: 2 additions & 2 deletions spec/integration/draft76_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def start_client
em {
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
server.onerror { |error|
error.should be_an_instance_of EM::WebSocket::DataError
error.should be_an_instance_of EM::WebSocket::WSMessageTooBigError
error.message.should == "Frame length too long (1180591620717411303296 bytes)"
done
}
Expand All @@ -164,7 +164,7 @@ def start_client
em {
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
server.onerror { |error|
error.should be_an_instance_of EM::WebSocket::DataError
error.should be_an_instance_of EM::WebSocket::WSProtocolError
error.message.should == "Invalid frame received"
done
}
Expand Down
4 changes: 2 additions & 2 deletions spec/unit/framing_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ def debug(*args); end
end

describe "other tests" do
it "should raise a DataError if an invalid frame type is requested" do
it "should raise a WSProtocolError if an invalid frame type is requested" do
lambda {
# Opcode 3 is not supported by this draft
@f << "\x83\x05Hello"
}.should raise_error(EventMachine::WebSocket::DataError, "Unknown opcode")
}.should raise_error(EventMachine::WebSocket::WSProtocolError, "Unknown opcode")
end

it "should accept a fragmented unmasked text message in 3 frames" do
Expand Down

0 comments on commit 57b10b7

Please sign in to comment.