Class: Vines::Stream::Http

Inherits:
Client show all
Defined in:
lib/vines/stream/http.rb,
lib/vines/stream/http/auth.rb,
lib/vines/stream/http/bind.rb,
lib/vines/stream/http/ready.rb,
lib/vines/stream/http/start.rb,
lib/vines/stream/http/request.rb,
lib/vines/stream/http/session.rb,
lib/vines/stream/http/sessions.rb,
lib/vines/stream/http/bind_restart.rb

Defined Under Namespace

Classes: Auth, Bind, BindRestart, Ready, Request, Session, Sessions, Start

Constant Summary

Constants inherited from Client

Client::MECHANISMS

Constants inherited from Vines::Stream

ERROR, PAD

Instance Attribute Summary collapse

Attributes inherited from Vines::Stream

#config, #domain, #user

Instance Method Summary collapse

Methods inherited from Client

#authentication_mechanisms, #method_missing, #ssl_handshake_completed, #unbind

Methods inherited from Vines::Stream

#advance, #available_resources, #cert_domain_matches?, #close_connection, #connected_resources, #encrypt, #encrypt?, #error, #interested_resources, #post_init, #receive_data, #reset, #router, #ssl_verify_peer, #storage, #unbind, #update_user_streams, #vhost

Methods included from Log

#log

Constructor Details

#initialize(config) ⇒ Http

Returns a new instance of Http.



8
9
10
11
# File 'lib/vines/stream/http.rb', line 8

def initialize(config)
  super
  @session = Http::Session.new(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Vines::Stream::Client

Instance Attribute Details

#sessionObject

Returns the value of attribute session.



6
7
8
# File 'lib/vines/stream/http.rb', line 6

def session
  @session
end

Instance Method Details

#create_parserObject

Override Stream#create_parser to provide an HTTP parser rather than a Nokogiri XML parser.

Returns nothing.



17
18
19
20
21
22
23
24
25
26
# File 'lib/vines/stream/http.rb', line 17

def create_parser
  @parser = ::Http::Parser.new.tap do |parser|
    body = ''
    parser.on_body = proc {|data| body << data }
    parser.on_message_complete = proc do
      process_request(Request.new(self, @parser, body))
      body = ''
    end
  end
end

#parse_body(body) ⇒ Object

Parse the one or more stanzas from a single body element. BOSH clients buffer stanzas sent in quick succession, and send them as a bundle, to save on the request/response cycle.

TODO This parses the XML again just to strip namespaces. Figure out Nokogiri namespace handling instead.

body - The XML::Node containing the BOSH ‘body` element.

Returns an Array of XML::Node stanzas.



92
93
94
95
96
97
# File 'lib/vines/stream/http.rb', line 92

def parse_body(body)
  body.namespace = nil
  body.elements.map do |node|
    Nokogiri::XML(node.to_s.sub(' xmlns="jabber:client"', '')).root
  end
end

#process_request(request) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/vines/stream/http.rb', line 48

def process_request(request)
  if request.path == self.bind && request.options?
    request.reply_to_options
  elsif request.path == self.bind
    body = Nokogiri::XML(request.body).root
    if session = Sessions[body['sid']]
      @session = session
    else
      @session = Http::Session.new(self)
    end
    @session.request(request)
    @nodes.push(body)
  else
    request.reply_with_file(self.root)
  end
end

#start(node) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/vines/stream/http.rb', line 99

def start(node)
  domain, type, hold, wait, rid = %w[to content hold wait rid].map {|a| (node[a] || '').strip }
  version = node.attribute_with_ns('version', NAMESPACES[:bosh]).value rescue nil

  @session.inactivity = 20
  @session.domain = domain
  @session.content_type = type unless type.empty?
  @session.hold = hold.to_i unless hold.empty?
  @session.wait = wait.to_i unless wait.empty?

  raise StreamErrors::UndefinedCondition.new('rid required') if rid.empty?
  raise StreamErrors::UnsupportedVersion unless version == '1.0'
  raise StreamErrors::ImproperAddressing unless valid_address?(domain)
  raise StreamErrors::HostUnknown unless config.vhost?(domain)
  raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:http_bind]

  Sessions[@session.id] = @session
  send_stream_header
end

#stream_writeObject

Alias the Stream#write method before overriding it so we can call it later from a Session instance.



67
# File 'lib/vines/stream/http.rb', line 67

alias :stream_write :write

#terminateObject



119
120
121
122
123
124
125
126
# File 'lib/vines/stream/http.rb', line 119

def terminate
  doc = Nokogiri::XML::Document.new
  node = doc.create_element('body',
    'type'  => 'terminate',
    'xmlns' => NAMESPACES[:http_bind])
  @session.reply(node)
  close_stream
end

#valid_session?(sid) ⇒ Boolean

If the session ID is valid, switch this stream’s session to the new ID and return true. Some clients, like Google Chrome, reuse one stream for multiple sessions.

sid - The String session ID.

Returns true if the server previously distributed this SID to a client.

Returns:

  • (Boolean)


35
36
37
38
39
40
# File 'lib/vines/stream/http.rb', line 35

def valid_session?(sid)
  if session = Sessions[sid]
    @session = session
  end
  !!session
end

#write(data) ⇒ Object

Override Stream#write to queue stanzas rather than immediately writing to the stream. Stanza responses must be paired with a queued request.

If a request is not waiting, the written stanzas will buffer until they can be sent in the next response.

data - The XML String or XML::Node to write to the HTTP socket.

Returns nothing.



78
79
80
# File 'lib/vines/stream/http.rb', line 78

def write(data)
  @session.write(data)
end