class Vines::Stream::Http
Attributes
Public Class Methods
Vines::Stream::Client::new
# File lib/vines/stream/http.rb, line 8 def initialize(config) super @session = Http::Session.new(self) end
Public Instance Methods
Override +Stream#create_parser+ to provide an HTTP parser rather than a Nokogiri XML parser.
# File lib/vines/stream/http.rb, line 15 def create_parser @parser = ::Http::Parser.new.tap do |p| body = '' p.on_body = proc {|data| body << data } p.on_message_complete = proc { process_request(Request.new(self, @parser, body)) body = '' } end end
Return an array of Node objects inside the body element. TODO This parses the XML again just to strip namespaces. Figure out Nokogiri namespace handling instead.
# File lib/vines/stream/http.rb, line 72 def parse_body(body) body.namespace = nil body.elements.map do |node| Nokogiri::XML(node.to_s.sub(' xmlns="jabber:client"', '')).root end end
# File lib/vines/stream/http.rb, line 42 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
# File lib/vines/stream/http.rb, line 79 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
Alias the Stream#write
method before overriding it so we can call it later from a Session
instance.
# File lib/vines/stream/http.rb, line 99 def terminate doc = Nokogiri::XML::Document.new node = doc.create_element('body', 'type' => 'terminate', 'xmlns' => NAMESPACES[:http_bind]) @session.reply(node) close_stream end
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.
# File lib/vines/stream/http.rb, line 29 def valid_session?(sid) if session = Sessions[sid] @session = session end !!session end
Override Stream#write
to queue stanzas rather than immediately writing to the stream. Stanza
responses must be paired with a queued request.
# File lib/vines/stream/http.rb, line 65 def write(data) @session.write(data) end
Private Instance Methods
Override +Stream#close_stream+ to simply close the connection without writing a closing stream tag.
# File lib/vines/stream/http.rb, line 151 def close_stream close_connection_after_writing @session.close end
Override +Stream#send_stream_error+ to wrap the error XML in a BOSH terminate body tag.
# File lib/vines/stream/http.rb, line 138 def send_stream_error(e) doc = Nokogiri::XML::Document.new node = doc.create_element('body', 'condition' => 'remote-stream-error', 'type' => 'terminate', 'xmlns' => NAMESPACES[:http_bind], 'xmlns:stream' => NAMESPACES[:stream]) node.inner_html = e.to_xml @session.reply(node) end
# File lib/vines/stream/http.rb, line 110 def send_stream_header doc = Nokogiri::XML::Document.new node = doc.create_element('body', 'charsets' => 'UTF-8', 'from' => @session.domain, 'hold' => @session.hold, 'inactivity' => @session.inactivity, 'polling' => '5', 'requests' => '2', 'sid' => @session.id, 'ver' => '1.6', 'wait' => @session.wait, 'xmpp:version' => '1.0', 'xmlns' => NAMESPACES[:http_bind], 'xmlns:xmpp' => NAMESPACES[:bosh], 'xmlns:stream' => NAMESPACES[:stream]) node << doc.create_element('stream:features') do |el| el << doc.create_element('mechanisms') do |mechanisms| mechanisms.default_namespace = NAMESPACES[:sasl] mechanisms << doc.create_element('mechanism', 'PLAIN') end end @session.reply(node) end