Skip to content

Commit

Permalink
Merge branch 'draft5and6'
Browse files Browse the repository at this point in the history
  • Loading branch information
mloughran committed May 6, 2011
2 parents 74f0530 + eac922a commit bbb3135
Show file tree
Hide file tree
Showing 35 changed files with 1,104 additions and 349 deletions.
2 changes: 1 addition & 1 deletion em-websocket.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ Gem::Specification.new do |s|
s.add_dependency("eventmachine", ">= 0.12.9")
s.add_dependency("addressable", '>= 2.1.1')
s.add_development_dependency('em-http-request', '~> 0.2.6')
s.add_development_dependency('rspec', "~> 2.0.0")
s.add_development_dependency('rspec', "~> 2.5.0")
s.add_development_dependency('rake')
end
9 changes: 6 additions & 3 deletions lib/em-websocket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

%w[
debugger websocket connection
handshake75 handshake76
framing76 framing03
handler_factory handler handler75 handler76 handler03
handshake75 handshake76 handshake04
framing76 framing03 framing04 framing05
close75 close03 close05 close06
masking04
message_processor_03 message_processor_06
handler_factory handler handler75 handler76 handler03 handler05 handler06
].each do |file|
require "em-websocket/#{file}"
end
Expand Down
11 changes: 11 additions & 0 deletions lib/em-websocket/close03.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module EventMachine
module WebSocket
module Close03
def close_websocket(code, body)
# TODO: Ideally send body data and check that it matches in ack
send_frame(:close, '')
@state = :closing
end
end
end
end
11 changes: 11 additions & 0 deletions lib/em-websocket/close05.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module EventMachine
module WebSocket
module Close05
def close_websocket(code, body)
# TODO: Ideally send body data and check that it matches in ack
send_frame(:close, "\x53")
@state = :closing
end
end
end
end
16 changes: 16 additions & 0 deletions lib/em-websocket/close06.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module EventMachine
module WebSocket
module Close06
def close_websocket(code, body)
if code
close_data = [code].pack('n')
close_data << body if body
send_frame(:close, close_data)
else
send_frame(:close, '')
end
@state = :closing
end
end
end
end
10 changes: 10 additions & 0 deletions lib/em-websocket/close75.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module EventMachine
module WebSocket
module Close75
def close_websocket(code, body)
@state = :closed
@connection.close_connection_after_writing
end
end
end
end
85 changes: 53 additions & 32 deletions lib/em-websocket/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ def initialize(options)
# Use this method to close the websocket connection cleanly
# This sends a close frame and waits for acknowlegement before closing
# the connection
def close_websocket
if @handler
@handler.close_websocket
else
# The handshake hasn't completed - should be safe to terminate
close_connection
def close_websocket(code = nil, body = nil)
if code && !(4000..4999).include?(code)
raise "Application code may only use codes in the range 4000-4999"
end

# If code not defined then set to 1000 (normal closure)
code ||= 1000

close_websocket_private(code, body)
end

def post_init
Expand All @@ -55,12 +57,32 @@ def receive_data(data)
else
dispatch(data)
end
rescue HandshakeError => e
debug [:error, e]
@onerror.call(e) if @onerror
# Errors during the handshake require the connection to be aborted
abort
rescue WebSocketError => e
debug [:error, e]
@onerror.call(e) if @onerror
close_websocket_private(1002) # 1002 indicates a protocol error
rescue => e
debug [:error, e]
# These are application errors - raise unless onerror defined
@onerror ? @onerror.call(e) : raise(e)
# There is no code defined for application errors, so use 3000
# (which is reserved for frameworks)
close_websocket_private(3000)
end

def unbind
debug [:unbind, :connection]

@handler.unbind if @handler
rescue => e
debug [:error, e]
# These are application errors - raise unless onerror defined
@onerror ? @onerror.call(e) : raise(e)
end

def dispatch(data)
Expand All @@ -69,30 +91,18 @@ def dispatch(data)
return false
else
debug [:inbound_headers, data]
begin
@data << data
@handler = HandlerFactory.build(self, @data, @secure, @debug)
unless @handler
# The whole header has not been received yet.
return false
end
@data = nil
@handler.run
return true
rescue => e
debug [:error, e]
process_bad_request(e)
@data << data
@handler = HandlerFactory.build(self, @data, @secure, @debug)
unless @handler
# The whole header has not been received yet.
return false
end
@data = nil
@handler.run
return true
end
end

def process_bad_request(reason)
@onerror.call(reason) if @onerror
send_data "HTTP/1.1 400 Bad request\r\n\r\n"
close_connection_after_writing
end

def send_flash_cross_domain_file
file = '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'
debug [:cross_domain, file]
Expand All @@ -105,27 +115,38 @@ def send_flash_cross_domain_file
end

def send(data)
debug [:send, data]

if @handler
@handler.send_text_frame(data)
else
raise WebSocketError, "Cannot send data before onopen callback"
end
end

def close_with_error(message)
@onerror.call(message) if @onerror
close_connection_after_writing
end

def request
@handler ? @handler.request : {}
end

def state
@handler ? @handler.state : :handshake
end

private

# As definited in draft 06 7.2.2, some failures require that the server
# abort the websocket connection rather than close cleanly
def abort
close_connection
end

def close_websocket_private(code, body = nil)
if @handler
debug [:closing, code]
@handler.close_websocket(code, body)
else
# The handshake hasn't completed - should be safe to terminate
abort
end
end
end
end
end
39 changes: 9 additions & 30 deletions lib/em-websocket/framing03.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module EventMachine
module WebSocket
module Framing03

def initialize_framing
@data = ''
@application_data_buffer = '' # Used for MORE frames
Expand All @@ -15,7 +15,7 @@ def process_data(newdata)
while !error && @data.size > 1
pointer = 0

more = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
more = ((@data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin
# Ignoring rsv1-3 for now
opcode = @data.getbyte(0) & 0b00001111
pointer += 1
Expand All @@ -28,7 +28,7 @@ def process_data(newdata)
when 127 # Length defined by 8 bytes
# Check buffer size
if @data.getbyte(pointer+8-1) == nil
debug [:buffer_incomplete, @data.inspect]
debug [:buffer_incomplete, @data]
error = true
next
end
Expand All @@ -41,7 +41,7 @@ def process_data(newdata)
when 126 # Length defined by 2 bytes
# Check buffer size
if @data.getbyte(pointer+2-1) == nil
debug [:buffer_incomplete, @data.inspect]
debug [:buffer_incomplete, @data]
error = true
next
end
Expand All @@ -55,7 +55,7 @@ def process_data(newdata)

# Check buffer size
if @data.getbyte(pointer+payload_length-1) == nil
debug [:buffer_incomplete, @data.inspect]
debug [:buffer_incomplete, @data]
error = true
next
end
Expand Down Expand Up @@ -91,6 +91,8 @@ def process_data(newdata)
end

def send_frame(frame_type, application_data)
debug [:sending_frame, frame_type, application_data]

if @state == :closing && data_frame?(frame_type)
raise WebSocketError, "Cannot send data frame since connection is closing"
end
Expand Down Expand Up @@ -124,31 +126,8 @@ def send_text_frame(data)

private

def message(message_type, extension_data, application_data)
case message_type
when :close
if @state == :closing
# TODO: Check that message body matches sent data
# We can close connection immediately since there is no more data
# is allowed to be sent or received on this connection
@connection.close_connection
@state = :closed
else
# Acknowlege close
# The connection is considered closed
send_frame(:close, application_data)
@state = :closed
@connection.close_connection_after_writing
end
when :ping
# Pong back the same data
send_frame(:pong, application_data)
when :pong
# TODO: Do something. Complete a deferrable established by a ping?
when :text, :binary
@connection.trigger_on_message(application_data)
end
end
# This allows flipping the more bit to fin for draft 04
def fin; false; end

FRAME_TYPES = {
:continuation => 0,
Expand Down
15 changes: 15 additions & 0 deletions lib/em-websocket/framing04.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# encoding: BINARY

module EventMachine
module WebSocket
# The only difference between draft 03 framing and draft 04 framing is
# that the MORE bit has been changed to a FIN bit
module Framing04
include Framing03

private

def fin; true; end
end
end
end
Loading

0 comments on commit bbb3135

Please sign in to comment.