class LibWebSocket::Request

Construct or parse a WebSocket request.

Constants

NOISE_CHARS

Attributes

cookies[RW]
resource_name[RW]

Public Instance Methods

connection() click to toggle source

A shortcut for self.field(‘Connection’)

# File lib/libwebsocket/request.rb, line 70
def connection
  self.field('Connection')
end
key1() click to toggle source

Draft 76 Sec-WebSocket-Key1 reader

# File lib/libwebsocket/request.rb, line 91
def key1
  self.key('key1')
end
key1=(val) click to toggle source

Draft 76 Sec-WebSocket-Key1 writter

# File lib/libwebsocket/request.rb, line 95
def key1=(val)
  self.key('key1',val)
end
key2() click to toggle source

Draft 76 Sec-WebSocket-Key2 reader

# File lib/libwebsocket/request.rb, line 99
def key2
  self.key('key2')
end
key2=(val) click to toggle source

Draft 76 Sec-WebSocket-Key2 writter

# File lib/libwebsocket/request.rb, line 103
def key2=(val)
  self.key('key2',val)
end
number1() click to toggle source

Draft 76 number 1 reader

# File lib/libwebsocket/request.rb, line 75
def number1
  self.number('number1','key1')
end
number1=(val) click to toggle source

Draft 76 number 1 writter

# File lib/libwebsocket/request.rb, line 79
def number1=(val)
  self.number('number1','key1',val)
end
number2() click to toggle source

Draft 76 number 2 reader

# File lib/libwebsocket/request.rb, line 83
def number2
  self.number('number2','key2')
end
number2=(val) click to toggle source

Draft 76 number 2 writter

# File lib/libwebsocket/request.rb, line 87
def number2=(val)
  self.number('number2','key2',val)
end
parse(opts) click to toggle source

Parse a WebSocket request. @param [String] opts parse string @param [Hash] opts parse rack env hash @see #parse_rack_env @example Parser

req = LibWebSocket::Request.new
req.parse("GET /demo HTTP/1.1\x0d\x0a")
req.parse("Upgrade: WebSocket\x0d\x0a")
req.parse("Connection: Upgrade\x0d\x0a")
req.parse("Host: example.com\x0d\x0a")
req.parse("Origin: http://example.com\x0d\x0a")
req.parse("Sec-WebSocket-Key1: 18x 6]8vM;54 *(5:  {   U1]8  z [  8\x0d\x0a")
req.parse("Sec-WebSocket-Key2: 1_ tx7X d  <  nw  334J702) 7]o}` 0\x0d\x0a")
req.parse("\x0d\x0aTm[K T2u")
# File lib/libwebsocket/request.rb, line 21
def parse(opts)
  case opts
  when String then super
  when Hash then parse_rack_env(opts)
  end
end
parse_rack_env(env) click to toggle source

Parse a WebSocket request. @param [Hash] env parse rack env hash @example Parser

req = LibWebSocket::Request.new
req.parse(env)
# File lib/libwebsocket/request.rb, line 33
def parse_rack_env(env)
  method = env['REQUEST_METHOD']
  unless method == 'GET'
    self.error = 'Wrong request method'
    return false
  end

  self.resource_name = env['REQUEST_URI']

  env.keys.select { |v| v =~ %r\AHTTP\_/ }.each do |key|
    self.field(key.gsub(%r\AHTTP\_/, "").gsub('_','-'), env[key])
  end

  body = env['rack.input']
  # Is compatible with rack.input spec?
  unless body.respond_to?(:rewind) and body.respond_to?(:read)
    self.error = "Invalid rack input"
    return false
  end

  body.rewind
  @buffer = body.read

  rv = self.parse_body
  return unless rv

  # Need more data
  return rv unless rv != true

  return self.done
end
to_s() click to toggle source

Construct a WebSocket request.

# Constructor
my $req = Protocol::WebSocket::Request.new(
    host          => 'example.com',
    resource_name => '/demo'
);
$req.to_s # GET /demo HTTP/1.1
          # Upgrade: WebSocket
          # Connection: Upgrade
          # Host: example.com
          # Origin: http://example.com
          # Sec-WebSocket-Key1: 32 0  3lD& 24+<    i u4  8! -6/4
          # Sec-WebSocket-Key2: 2q 4  2  54 09064
          #
          # x#####
# File lib/libwebsocket/request.rb, line 122
def to_s
  string = ''

  raise 'resource_name is required' unless self.resource_name
  string += "GET " + self.resource_name + " HTTP/1.1\x0d\x0a"

  string += "Upgrade: WebSocket\x0d\x0a"
  string += "Connection: Upgrade\x0d\x0a"

  raise 'Host is required' unless self.host
  string += "Host: " + self.host + "\x0d\x0a"

  origin = self.origin || 'http://' + self.host
  string += "Origin: " + origin + "\x0d\x0a"

  if self.version > 75
    self.generate_keys

    string += 'Sec-WebSocket-Protocol: ' + self.subprotocol + "\x0d\x0a" if self.subprotocol

    string += 'Sec-WebSocket-Key1: ' + self.key1 + "\x0d\x0a"
    string += 'Sec-WebSocket-Key2: ' + self.key2 + "\x0d\x0a"

    string += 'Content-Length: ' + self.challenge.length.to_s + "\x0d\x0a"
  else
    string += 'WebSocket-Protocol: ' + self.subprotocol + "\x0d\x0a" if self.subprotocol
  end

  # TODO cookies

  string += "\x0d\x0a"

  string += self.challenge if self.version > 75

  return string
end
upgrade() click to toggle source

A shortcut for self.field(‘Upgrade’)

# File lib/libwebsocket/request.rb, line 66
def upgrade
  self.field('Upgrade')
end

Protected Instance Methods

finalize() click to toggle source
# File lib/libwebsocket/request.rb, line 260
def finalize
  return unless self.upgrade    && self.upgrade    == 'WebSocket'
  return unless self.connection && self.connection == 'Upgrade'

  origin = self.field('Origin')
  return unless origin
  self.origin = origin

  host = self.field('Host')
  return unless host
  self.host = host

  subprotocol = self.field('Sec-WebSocket-Protocol') || self.field('WebSocket-Protocol')
  self.subprotocol = subprotocol if subprotocol

  cookie = self.build_cookie
  if cookies = cookie.parse(self.fields['cookie'])
     self.cookies = cookies
  end

  return self
end
generate_challenge() click to toggle source
# File lib/libwebsocket/request.rb, line 251
def generate_challenge
  challenge = ''
  8.times do
    challenge += rand(256).chr
  end

  return challenge
end
generate_key() click to toggle source
# File lib/libwebsocket/request.rb, line 234
def generate_key
  spaces = 1 + rand(12)
  max = 4_294_967_295 / spaces
  number = rand(max + 1)
  key = (number * spaces).to_s
  (1 + rand(12)).times do
    char = NOISE_CHARS[rand(NOISE_CHARS.size)]
    pos = rand(key.size + 1)
    key[pos...pos] = char
  end
  spaces.times do
    pos = 1 + rand(key.size - 1)
    key[pos...pos] = " "
  end
  return [number, key]
end
generate_keys() click to toggle source
# File lib/libwebsocket/request.rb, line 214
def generate_keys
  unless self.key1
    number, key = self.generate_key
    self.number1 = number
    self.key1 = key
  end

  unless self.key2
    number, key = self.generate_key
    self.number2 = number
    self.key2 = key
  end

  self.challenge ||= self.generate_challenge

  return self
end
key(name, value = nil) click to toggle source
# File lib/libwebsocket/request.rb, line 200
def key(name, value = nil)
  unless value
    if value = self.instance_variable_get("@#{name}")
      self.field("Sec-WebSocket-" + name.capitalize, value)
    end

    return self.field("Sec-WebSocket-" + name.capitalize)
  end

  return self.field("Sec-WebSocket-" + name.capitalize, value)

  return self
end
parse_body() click to toggle source
# File lib/libwebsocket/request.rb, line 179
def parse_body
  if self.key1 && self.key2
    return true if @buffer.length < 8

    challenge = @buffer.slice!(0..7)
    self.challenge = challenge
  else
    self.version = 75
  end

  if @buffer.length > 0
    self.error = 'Leftovers'
    return
  end

  return self if self.finalize

  self.error = 'Not a valid request'
  return
end
parse_first_line(line) click to toggle source
# File lib/libwebsocket/request.rb, line 161
def parse_first_line(line)
  req, resource_name, http = line.split(' ')

  unless req && resource_name && http
    self.error = 'Wrong request line'
    return
  end

  unless req == 'GET' && http == 'HTTP/1.1'
    self.error = 'Wrong method or http version'
    return
  end

  self.resource_name = resource_name

  return self
end