Class: EventMachine::WebSocket::HandlerFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/em-websocket/handler_factory.rb

Constant Summary collapse

PATH =
/^(\w+) (\/[^\s]*) HTTP\/1\.1$/
HEADER =
/^([^:]+):\s*(.+)$/

Class Method Summary collapse

Class Method Details

.build(connection, data, secure = false, debug = false) ⇒ Object

Raises:



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
# File 'lib/em-websocket/handler_factory.rb', line 7

def self.build(connection, data, secure = false, debug = false)
  (header, remains) = data.split("\r\n\r\n", 2)
  unless remains
    # The whole header has not been received yet.
    return nil
  end

  request = {}

  lines = header.split("\r\n")

  # extract request path
  first_line = lines.shift.match(PATH)
  raise HandshakeError, "Invalid HTTP header" unless first_line
  request['method'] = first_line[1].strip
  request['path'] = first_line[2].strip

  unless request["method"] == "GET"
    raise HandshakeError, "Must be GET request"
  end

  # extract query string values
  request['query'] = Addressable::URI.parse(request['path']).query_values ||= {}
  # extract remaining headers
  lines.each do |line|
    h = HEADER.match(line)
    request[h[1].strip.downcase] = h[2].strip if h
  end

  build_with_request(connection, request, remains, secure, debug)
end

.build_with_request(connection, request, remains, secure = false, debug = false) ⇒ Object



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
# File 'lib/em-websocket/handler_factory.rb', line 39

def self.build_with_request(connection, request, remains, secure = false, debug = false)
  # Determine version heuristically
  version = if request['sec-websocket-version']
    # Used from drafts 04 onwards
    request['sec-websocket-version'].to_i
  elsif request['sec-websocket-draft']
    # Used in drafts 01 - 03
    request['sec-websocket-draft'].to_i
  elsif request['sec-websocket-key1']
    76
  else
    75
  end

  # Additional handling of bytes after the header if required
  case version
  when 75
    if !remains.empty?
      raise HandshakeError, "Extra bytes after header"
    end
  when 76, 1..3
    if remains.length < 8
      # The whole third-key has not been received yet.
      return nil
    elsif remains.length > 8
      raise HandshakeError, "Extra bytes after third key"
    end
    request['third-key'] = remains
  end

  # Validate that Connection and Upgrade headers
  unless request['connection'] && request['connection'] =~ /Upgrade/ && request['upgrade'] && request['upgrade'].downcase == 'websocket'
    raise HandshakeError, "Connection and Upgrade headers required"
  end

  # transform headers
  protocol = (secure ? "wss" : "ws")
  request['host'] = Addressable::URI.parse("#{protocol}://"+request['host'])

  case version
  when 75
    Handler75.new(connection, request, debug)
  when 76
    Handler76.new(connection, request, debug)
  when 1..3
    # We'll use handler03 - I believe they're all compatible
    Handler03.new(connection, request, debug)
  when 5
    Handler05.new(connection, request, debug)
  when 6
    Handler06.new(connection, request, debug)
  when 7
    Handler07.new(connection, request, debug)
  when 8
    Handler08.new(connection, request, debug)
  else
    # According to spec should abort the connection
    raise WebSocketError, "Protocol version #{version} not supported"
  end
end