Permalink
Browse files

Merge branch 'configurable_size_limit'

  • Loading branch information...
2 parents 57b10b7 + 3e7f7d7 commit 87cd9e9262f6ab178acb5b742452a11d3048d44a @mloughran mloughran committed Feb 9, 2012
@@ -5,6 +5,8 @@ module WebSocket
class Connection < EventMachine::Connection
include Debugger
+ attr_writer :max_frame_size
+
# define WebSocket callbacks
def onopen(&blk); @onopen = blk; end
def onclose(&blk); @onclose = blk; end
@@ -193,6 +195,18 @@ def state
@handler ? @handler.state : :handshake
end
+ # Returns the maximum frame size which this connection is configured to
+ # accept. This can be set globally or on a per connection basis, and
+ # defaults to a value of 10MB if not set.
+ #
+ # The behaviour when a too large frame is received varies by protocol,
+ # but in the newest protocols the connection will be closed with the
+ # correct close code (1009) immediately after receiving the frame header
+ #
+ def max_frame_size
+ @max_frame_size || WebSocket.max_frame_size
+ end
+
private
# As definited in draft 06 7.2.2, some failures require that the server
@@ -3,11 +3,6 @@
module EventMachine
module WebSocket
module Framing03
-
- # Set the max frame lenth to very high value (10MB) until there is a
- # limit specified in the spec to protect against malicious attacks
- MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
-
def initialize_framing
@data = ''
@application_data_buffer = '' # Used for MORE frames
@@ -57,8 +52,7 @@ def process_data(newdata)
length
end
- # Addition to the spec to protect against malicious requests
- if payload_length > MAXIMUM_FRAME_LENGTH
+ if payload_length > @connection.max_frame_size
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
end
@@ -3,11 +3,6 @@
module EventMachine
module WebSocket
module Framing05
-
- # Set the max frame lenth to very high value (10MB) until there is a
- # limit specified in the spec to protect against malicious attacks
- MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
-
def initialize_framing
@data = MaskedString.new
@application_data_buffer = '' # Used for MORE frames
@@ -60,8 +55,7 @@ def process_data(newdata)
length
end
- # Addition to the spec to protect against malicious requests
- if payload_length > MAXIMUM_FRAME_LENGTH
+ if payload_length > @connection.max_frame_size
raise WSMessageTooBigError, "Frame length too long (#{payload_length} bytes)"
end
@@ -59,6 +59,10 @@ def process_data(newdata)
frame_length = pointer + payload_length
frame_length += 4 if mask
+ if frame_length > @connection.max_frame_size
+ raise WSMessageTooBigError, "Frame length too long (#{frame_length} bytes)"
+ end
+
# Check buffer size
if @data.getbyte(frame_length - 1) == nil
debug [:buffer_incomplete, @data]
@@ -3,11 +3,6 @@
module EventMachine
module WebSocket
module Framing76
-
- # Set the max frame lenth to very high value (10MB) until there is a
- # limit specified in the spec to protect against malicious attacks
- MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
-
def initialize_framing
@data = ''
end
@@ -40,8 +35,7 @@ def process_data(newdata)
break unless (b & 0x80) == 0x80
end
- # Addition to the spec to protect against malicious requests
- if length > MAXIMUM_FRAME_LENGTH
+ if length > @connection.max_frame_size
raise WSMessageTooBigError, "Frame length too long (#{length} bytes)"
end
@@ -73,7 +67,7 @@ def process_data(newdata)
end
# Addition to the spec to protect against malicious requests
- if @data.size > MAXIMUM_FRAME_LENGTH
+ if @data.size > @connection.max_frame_size
raise WSMessageTooBigError, "Frame length too long (#{@data.size} bytes)"
end
@@ -38,5 +38,10 @@ def self.stop
puts "Terminating WebSocket Server"
EventMachine.stop
end
+
+ class << self
+ attr_accessor :max_frame_size
+ end
+ @max_frame_size = 10 * 1024 * 1024 # 10MB
end
end
View
@@ -107,6 +107,7 @@ def initialize
@ws.errback { @onerror.call if @onerror }
@ws.callback { @onopen.call if @onopen }
@ws.stream { |msg| @onmessage.call(msg) if @onmessage }
+ @ws.disconnect { @onclose.call if @onclose }
end
def send(message)
@@ -1,6 +1,6 @@
require 'helper'
-# These tests are not specifi to any particular draft of the specification
+# These tests are not specific to any particular draft of the specification
#
describe "WebSocket server" do
include EM::SpecHelper
@@ -1,5 +1,7 @@
# encoding: UTF-8
+# These tests are run against all draft versions
+#
shared_examples_for "a websocket server" do
it "should call onerror if an application error raised in onopen" do
em {
@@ -62,6 +64,41 @@
}
end
+ it "should close the connection when a too long frame is sent" do
+ em {
+ start_server { |server|
+ server.max_frame_size = 20
+
+ server.onerror { |e|
+ # 3: Error should be reported to server
+ e.class.should == EventMachine::WebSocket::WSMessageTooBigError
+ e.message.should =~ /Frame length too long/
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ EM.next_tick {
+ client.send("This message is longer than 20 characters")
+ }
+
+ }
+
+ client.onmessage { |msg|
+ # 4: This is actually the close message. Really need to use a real
+ # WebSocket client in these tests...
+ done
+ }
+
+ client.onclose {
+ # 4: Drafts 75 & 76 don't send a close message, they just close the
+ # connection
+ done
+ }
+ }
+ }
+ end
+
# Only run these tests on ruby 1.9
if "a".respond_to?(:force_encoding)
it "should raise error if you try to send non utf8 text data to ws" do
@@ -4,6 +4,13 @@
class FramingContainer
include EM::WebSocket::Framing03
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
def <<(data)
@data << data
process_data(data)
@@ -122,6 +129,13 @@ def debug(*args); end
class FramingContainer04
include EM::WebSocket::Framing04
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
def <<(data)
@data << data
process_data(data)
@@ -184,6 +198,13 @@ def debug(*args); end
class FramingContainer07
include EM::WebSocket::Framing07
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
def <<(data)
@data << data
process_data(data)

0 comments on commit 87cd9e9

Please sign in to comment.