vines 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +19 -0
- data/README +34 -0
- data/Rakefile +55 -0
- data/bin/vines +95 -0
- data/conf/certs/README +32 -0
- data/conf/certs/ca-bundle.crt +3987 -0
- data/conf/config.rb +114 -0
- data/lib/vines.rb +155 -0
- data/lib/vines/command/bcrypt.rb +12 -0
- data/lib/vines/command/cert.rb +49 -0
- data/lib/vines/command/init.rb +58 -0
- data/lib/vines/command/ldap.rb +35 -0
- data/lib/vines/command/restart.rb +12 -0
- data/lib/vines/command/schema.rb +24 -0
- data/lib/vines/command/start.rb +28 -0
- data/lib/vines/command/stop.rb +18 -0
- data/lib/vines/config.rb +191 -0
- data/lib/vines/contact.rb +99 -0
- data/lib/vines/daemon.rb +78 -0
- data/lib/vines/error.rb +150 -0
- data/lib/vines/jid.rb +56 -0
- data/lib/vines/kit.rb +23 -0
- data/lib/vines/router.rb +125 -0
- data/lib/vines/stanza.rb +55 -0
- data/lib/vines/stanza/iq.rb +50 -0
- data/lib/vines/stanza/iq/auth.rb +18 -0
- data/lib/vines/stanza/iq/disco_info.rb +25 -0
- data/lib/vines/stanza/iq/disco_items.rb +23 -0
- data/lib/vines/stanza/iq/error.rb +16 -0
- data/lib/vines/stanza/iq/ping.rb +16 -0
- data/lib/vines/stanza/iq/query.rb +10 -0
- data/lib/vines/stanza/iq/result.rb +16 -0
- data/lib/vines/stanza/iq/roster.rb +153 -0
- data/lib/vines/stanza/iq/session.rb +22 -0
- data/lib/vines/stanza/iq/vcard.rb +58 -0
- data/lib/vines/stanza/message.rb +41 -0
- data/lib/vines/stanza/presence.rb +119 -0
- data/lib/vines/stanza/presence/error.rb +23 -0
- data/lib/vines/stanza/presence/probe.rb +38 -0
- data/lib/vines/stanza/presence/subscribe.rb +66 -0
- data/lib/vines/stanza/presence/subscribed.rb +64 -0
- data/lib/vines/stanza/presence/unavailable.rb +15 -0
- data/lib/vines/stanza/presence/unsubscribe.rb +57 -0
- data/lib/vines/stanza/presence/unsubscribed.rb +50 -0
- data/lib/vines/storage.rb +216 -0
- data/lib/vines/storage/couchdb.rb +119 -0
- data/lib/vines/storage/ldap.rb +59 -0
- data/lib/vines/storage/local.rb +66 -0
- data/lib/vines/storage/redis.rb +108 -0
- data/lib/vines/storage/sql.rb +174 -0
- data/lib/vines/store.rb +51 -0
- data/lib/vines/stream.rb +198 -0
- data/lib/vines/stream/client.rb +131 -0
- data/lib/vines/stream/client/auth.rb +94 -0
- data/lib/vines/stream/client/auth_restart.rb +33 -0
- data/lib/vines/stream/client/bind.rb +58 -0
- data/lib/vines/stream/client/bind_restart.rb +25 -0
- data/lib/vines/stream/client/closed.rb +13 -0
- data/lib/vines/stream/client/ready.rb +15 -0
- data/lib/vines/stream/client/start.rb +27 -0
- data/lib/vines/stream/client/tls.rb +37 -0
- data/lib/vines/stream/component.rb +53 -0
- data/lib/vines/stream/component/handshake.rb +25 -0
- data/lib/vines/stream/component/ready.rb +24 -0
- data/lib/vines/stream/component/start.rb +19 -0
- data/lib/vines/stream/http.rb +111 -0
- data/lib/vines/stream/http/http_request.rb +22 -0
- data/lib/vines/stream/http/http_state.rb +139 -0
- data/lib/vines/stream/http/http_states.rb +53 -0
- data/lib/vines/stream/parser.rb +78 -0
- data/lib/vines/stream/server.rb +126 -0
- data/lib/vines/stream/server/auth.rb +13 -0
- data/lib/vines/stream/server/auth_restart.rb +19 -0
- data/lib/vines/stream/server/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth.rb +31 -0
- data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/auth_result.rb +28 -0
- data/lib/vines/stream/server/outbound/final_features.rb +27 -0
- data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
- data/lib/vines/stream/server/outbound/start.rb +20 -0
- data/lib/vines/stream/server/outbound/tls.rb +30 -0
- data/lib/vines/stream/server/outbound/tls_result.rb +31 -0
- data/lib/vines/stream/server/ready.rb +20 -0
- data/lib/vines/stream/server/start.rb +13 -0
- data/lib/vines/stream/server/tls.rb +13 -0
- data/lib/vines/stream/state.rb +55 -0
- data/lib/vines/token_bucket.rb +46 -0
- data/lib/vines/user.rb +124 -0
- data/lib/vines/version.rb +5 -0
- data/lib/vines/xmpp_server.rb +25 -0
- data/test/config_test.rb +396 -0
- data/test/error_test.rb +59 -0
- data/test/ext/nokogiri.rb +14 -0
- data/test/jid_test.rb +71 -0
- data/test/kit_test.rb +21 -0
- data/test/router_test.rb +60 -0
- data/test/stanza/iq/roster_test.rb +198 -0
- data/test/stanza/iq/session_test.rb +30 -0
- data/test/stanza/iq/vcard_test.rb +159 -0
- data/test/stanza/message_test.rb +124 -0
- data/test/stanza/presence/subscribe_test.rb +75 -0
- data/test/storage/couchdb_test.rb +102 -0
- data/test/storage/ldap_test.rb +207 -0
- data/test/storage/local_test.rb +54 -0
- data/test/storage/redis_test.rb +75 -0
- data/test/storage/sql_test.rb +55 -0
- data/test/storage/storage_tests.rb +134 -0
- data/test/storage_test.rb +90 -0
- data/test/stream/client/auth_test.rb +127 -0
- data/test/stream/client/ready_test.rb +47 -0
- data/test/stream/component/handshake_test.rb +46 -0
- data/test/stream/component/ready_test.rb +105 -0
- data/test/stream/component/start_test.rb +41 -0
- data/test/stream/parser_test.rb +121 -0
- data/test/stream/server/outbound/auth_test.rb +77 -0
- data/test/stream/server/ready_test.rb +100 -0
- data/test/token_bucket_test.rb +24 -0
- data/test/user_test.rb +64 -0
- metadata +318 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Client
|
|
6
|
+
class AuthRestart < State
|
|
7
|
+
def initialize(stream, success=Auth)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def node(node)
|
|
12
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
|
13
|
+
stream.start(node)
|
|
14
|
+
doc = Document.new
|
|
15
|
+
features = doc.create_element('stream:features') do |el|
|
|
16
|
+
el << doc.create_element('mechanisms') do |parent|
|
|
17
|
+
parent.default_namespace = NAMESPACES[:sasl]
|
|
18
|
+
mechanisms.each {|name| parent << doc.create_element('mechanism', name) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
stream.write(features)
|
|
22
|
+
advance
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def mechanisms
|
|
28
|
+
['EXTERNAL', 'PLAIN']
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Client
|
|
6
|
+
class Bind < State
|
|
7
|
+
NS = NAMESPACES[:bind]
|
|
8
|
+
MAX_ATTEMPTS = 5
|
|
9
|
+
|
|
10
|
+
def initialize(stream, success=Ready)
|
|
11
|
+
super
|
|
12
|
+
@attempts = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def node(node)
|
|
16
|
+
@attempts += 1
|
|
17
|
+
raise StreamErrors::NotAuthorized unless bind?(node)
|
|
18
|
+
raise StreamErrors::PolicyViolation.new('max bind attempts reached') if @attempts > MAX_ATTEMPTS
|
|
19
|
+
raise StanzaErrors::ResourceConstraint.new(node, 'wait') if resource_limit_reached?
|
|
20
|
+
stream.user.jid.resource = resource(node)
|
|
21
|
+
doc = Document.new
|
|
22
|
+
result = doc.create_element('iq', 'id' => node['id'], 'type' => 'result') do |el|
|
|
23
|
+
el << doc.create_element('bind') do |bind|
|
|
24
|
+
bind.default_namespace = NS
|
|
25
|
+
bind << doc.create_element('jid', stream.user.jid.to_s)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
stream.write(result)
|
|
29
|
+
stream.write('<stream:features/>')
|
|
30
|
+
advance
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def bind?(node)
|
|
36
|
+
node.name == 'iq' && node['type'] == 'set' && node.xpath('ns:bind', 'ns' => NS).any?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def resource(node)
|
|
40
|
+
el = node.xpath('ns:bind/ns:resource', 'ns' => NS).first
|
|
41
|
+
resource = el ? el.text.strip : ''
|
|
42
|
+
resource.empty? || resource_used?(resource) ? Kit.uuid : resource
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def resource_limit_reached?
|
|
46
|
+
used = stream.router.connected_resources(stream.user.jid.bare).size
|
|
47
|
+
used >= stream.max_resources_per_account
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resource_used?(resource)
|
|
51
|
+
stream.router.available_resources(stream.user.jid).any? do |c|
|
|
52
|
+
c.user.jid.resource == resource
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Client
|
|
6
|
+
class BindRestart < State
|
|
7
|
+
def initialize(stream, success=Bind)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def node(node)
|
|
12
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
|
13
|
+
stream.start(node)
|
|
14
|
+
doc = Document.new
|
|
15
|
+
features = doc.create_element('stream:features') do |el|
|
|
16
|
+
el << doc.create_element('bind', 'xmlns' => NAMESPACES[:bind])
|
|
17
|
+
el << doc.create_element('session', 'xmlns' => NAMESPACES[:session])
|
|
18
|
+
end
|
|
19
|
+
stream.write(features)
|
|
20
|
+
advance
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Client
|
|
6
|
+
class Start < State
|
|
7
|
+
def initialize(stream, success=TLS)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def node(node)
|
|
12
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
|
13
|
+
stream.start(node)
|
|
14
|
+
doc = Document.new
|
|
15
|
+
features = doc.create_element('stream:features') do |el|
|
|
16
|
+
el << doc.create_element('starttls') do |tls|
|
|
17
|
+
tls.default_namespace = NAMESPACES[:tls]
|
|
18
|
+
tls << doc.create_element('required')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
stream.write(features)
|
|
22
|
+
advance
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Client
|
|
6
|
+
class TLS < State
|
|
7
|
+
NS = NAMESPACES[:tls]
|
|
8
|
+
PROCEED = %Q{<proceed xmlns="#{NS}"/>}.freeze
|
|
9
|
+
FAILURE = %Q{<failure xmlns="#{NS}"/>}.freeze
|
|
10
|
+
STARTTLS = 'starttls'.freeze
|
|
11
|
+
|
|
12
|
+
def initialize(stream, success=AuthRestart)
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def node(node)
|
|
17
|
+
raise StreamErrors::NotAuthorized unless starttls?(node)
|
|
18
|
+
if stream.encrypt?
|
|
19
|
+
stream.write(PROCEED)
|
|
20
|
+
stream.encrypt
|
|
21
|
+
advance
|
|
22
|
+
else
|
|
23
|
+
stream.write(FAILURE)
|
|
24
|
+
stream.write('</stream:stream>')
|
|
25
|
+
stream.close_connection_after_writing
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def starttls?(node)
|
|
32
|
+
node.name == STARTTLS && namespace(node) == NS
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
|
|
6
|
+
# Implements the XMPP protocol for trusted, external component (XEP-0114)
|
|
7
|
+
# streams. This serves connected streams using the jabber:component:accept
|
|
8
|
+
# namespace.
|
|
9
|
+
class Component < Stream
|
|
10
|
+
attr_reader :config, :remote_domain
|
|
11
|
+
|
|
12
|
+
def initialize(config)
|
|
13
|
+
@config = config
|
|
14
|
+
@remote_domain = nil
|
|
15
|
+
@stream_id = Kit.uuid
|
|
16
|
+
@state = Start.new(self)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def max_stanza_size
|
|
20
|
+
@config[:component].max_stanza_size
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ready?
|
|
24
|
+
@state.class == Component::Ready
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def start(node)
|
|
28
|
+
@remote_domain = node['to']
|
|
29
|
+
send_stream_header
|
|
30
|
+
raise StreamErrors::HostUnknown unless @config[:component].password(@remote_domain)
|
|
31
|
+
raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns'] == NAMESPACES[:component]
|
|
32
|
+
raise StreamErrors::InvalidNamespace unless node.namespaces['xmlns:stream'] == NAMESPACES[:stream]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def secret
|
|
36
|
+
password = @config[:component].password(@remote_domain)
|
|
37
|
+
Digest::SHA1.hexdigest(@stream_id + password)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def send_stream_header
|
|
43
|
+
attrs = {
|
|
44
|
+
'xmlns' => NAMESPACES[:component],
|
|
45
|
+
'xmlns:stream' => NAMESPACES[:stream],
|
|
46
|
+
'id' => @stream_id,
|
|
47
|
+
'from' => @remote_domain
|
|
48
|
+
}
|
|
49
|
+
write "<stream:stream %s>" % attrs.to_a.map{|k,v| "#{k}='#{v}'"}.join(' ')
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Component
|
|
6
|
+
class Handshake < State
|
|
7
|
+
def initialize(stream, success=Ready)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def node(node)
|
|
12
|
+
raise StreamErrors::NotAuthorized unless handshake?(node)
|
|
13
|
+
stream.write('<handshake/>')
|
|
14
|
+
advance
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def handshake?(node)
|
|
20
|
+
node.name == 'handshake' && node.text == stream.secret
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Component
|
|
6
|
+
class Ready < State
|
|
7
|
+
def node(node)
|
|
8
|
+
stanza = to_stanza(node)
|
|
9
|
+
raise StreamErrors::UnsupportedStanzaType unless stanza
|
|
10
|
+
to = (node['to'] || '').strip
|
|
11
|
+
from = JID.new(node['from'] || '')
|
|
12
|
+
raise StreamErrors::ImproperAddressing if to.empty? || from.domain != stream.remote_domain
|
|
13
|
+
if stanza.local?
|
|
14
|
+
stream.router.connected_resources(to).each do |recipient|
|
|
15
|
+
recipient.write(node)
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
stanza.route
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Component
|
|
6
|
+
class Start < State
|
|
7
|
+
def initialize(stream, success=Handshake)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def node(node)
|
|
12
|
+
raise StreamErrors::NotAuthorized unless stream?(node)
|
|
13
|
+
stream.start(node)
|
|
14
|
+
advance
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Vines
|
|
4
|
+
class Stream
|
|
5
|
+
class Http < Client
|
|
6
|
+
include Thin
|
|
7
|
+
include Vines::Log
|
|
8
|
+
|
|
9
|
+
attr_accessor :last_broadcast_presence, :last_activity
|
|
10
|
+
|
|
11
|
+
def initialize(config)
|
|
12
|
+
@config = config
|
|
13
|
+
@domain = nil
|
|
14
|
+
@requested_roster = false
|
|
15
|
+
@available = false
|
|
16
|
+
@unbound = false
|
|
17
|
+
@last_broadcast_presence = nil
|
|
18
|
+
@request = Thin::Request.new
|
|
19
|
+
@@http_states ||= HttpStates.new
|
|
20
|
+
@state = Auth.new(self)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def user
|
|
24
|
+
@http_state.user
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def user=(user)
|
|
28
|
+
@http_state.user = user
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def receive_data(data)
|
|
32
|
+
#TODO: make sure we add max stanza size enforcement
|
|
33
|
+
if @request.parse(data)
|
|
34
|
+
process_http_request(@request)
|
|
35
|
+
@request = Thin::Request.new
|
|
36
|
+
end
|
|
37
|
+
rescue InvalidRequest => e
|
|
38
|
+
error(StreamErrors::NotWellFormed.new)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def write(data)
|
|
42
|
+
@http_state.write(data)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def setup_new_client(rid, domain)
|
|
46
|
+
sid = Kit.uuid
|
|
47
|
+
log.info("Setting up a new client SID: #{sid} for RID: #{rid}.")
|
|
48
|
+
@http_state = HttpState.new(self, sid, rid, domain)
|
|
49
|
+
@@http_states[sid] = @http_state
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def unbind
|
|
53
|
+
#router.delete(@http_state)
|
|
54
|
+
log.info("HTTP Stream disconnected:\tfrom=#{@remote_addr}\tto=#{@local_addr}")
|
|
55
|
+
log.info("Streams connected: #{router.size}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def process_http_request(request)
|
|
59
|
+
if request.body.string.empty?
|
|
60
|
+
#Respond to proxy servers' status pings
|
|
61
|
+
log.info("A status request has been received.")
|
|
62
|
+
send_data("Online")
|
|
63
|
+
close_connection_after_writing
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
body = Nokogiri::XML(request.body.string).root
|
|
67
|
+
body.namespace = nil
|
|
68
|
+
#TODO: Confirm this is a valid body stanza.
|
|
69
|
+
# If it isn't a body, return proxy ping result
|
|
70
|
+
|
|
71
|
+
if body['sid']
|
|
72
|
+
@http_state = @@http_states[body['sid']]
|
|
73
|
+
unless @http_state
|
|
74
|
+
log.info("Client was not found #{body['sid']}")
|
|
75
|
+
send_bosh_error
|
|
76
|
+
return
|
|
77
|
+
end
|
|
78
|
+
@domain = @http_state.domain
|
|
79
|
+
@user = @http_state.user
|
|
80
|
+
@http_state.request(body['rid'])
|
|
81
|
+
if body['restart']
|
|
82
|
+
@http_state.handle_restart
|
|
83
|
+
router << @http_state
|
|
84
|
+
@state = Bind.new(self)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
body.elements.each do |node|
|
|
88
|
+
@nodes.push(Nokogiri::XML(node.to_s.sub(' xmlns="jabber:client"', '')).root)
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
self.setup_new_client(body['rid'], body['to'])
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def send_bosh_error
|
|
96
|
+
body = "<body type='terminate' condition='remote-connection-failed' xmlns='http://jabber.org/protocol/httpbind'/>"
|
|
97
|
+
header = [
|
|
98
|
+
"HTTP/1.1 404 OK",
|
|
99
|
+
"Content-Type: text/xml; charset=utf-8",
|
|
100
|
+
"Content-Length: #{body.bytesize}"
|
|
101
|
+
].join("\r\n")
|
|
102
|
+
|
|
103
|
+
send_data([header, body].join("\r\n\r\n"))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def domain
|
|
107
|
+
@http_state.domain
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|