riddl 0.99.105
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/AUTHORS +1 -0
- data/COPYING +165 -0
- data/INSTALL +24 -0
- data/README.rdoc +2 -0
- data/Rakefile +17 -0
- data/TODO +17 -0
- data/contrib/riddl.jpg +0 -0
- data/contrib/riddl.png +0 -0
- data/contrib/riddl.svg +138 -0
- data/lib/riddl/client.rb +423 -0
- data/lib/riddl/commonlogger.rb +16 -0
- data/lib/riddl/constants.rb +5 -0
- data/lib/riddl/error.rb +8 -0
- data/lib/riddl/handlers.rb +14 -0
- data/lib/riddl/handlers/oauth.rb +19 -0
- data/lib/riddl/handlers/plain-type.rb +21 -0
- data/lib/riddl/handlers/relaxng.rb +16 -0
- data/lib/riddl/handlers/xmlschema.rb +16 -0
- data/lib/riddl/header.rb +9 -0
- data/lib/riddl/implementation.rb +57 -0
- data/lib/riddl/ns/common-patterns/addon-security/request.xml +25 -0
- data/lib/riddl/ns/common-patterns/addon-security/response.xml +25 -0
- data/lib/riddl/ns/common-patterns/downloadify/1.0/downloadify.xml +18 -0
- data/lib/riddl/ns/common-patterns/notifications-consumer/1.0/consumer.xml +100 -0
- data/lib/riddl/ns/common-patterns/notifications-producer/1.0/producer.xml +204 -0
- data/lib/riddl/ns/common-patterns/properties/1.0/properties.schema.schema +140 -0
- data/lib/riddl/ns/common-patterns/properties/1.0/properties.schema.xsl +89 -0
- data/lib/riddl/ns/common-patterns/properties/1.0/properties.xml +150 -0
- data/lib/riddl/ns/common/datatypes-1_0.rng +79 -0
- data/lib/riddl/ns/common/relaxng-modular.rng +330 -0
- data/lib/riddl/ns/common/relaxng.rng +10 -0
- data/lib/riddl/ns/declaration/1.0/declaration.rng +114 -0
- data/lib/riddl/ns/description/1.0/description.rng +302 -0
- data/lib/riddl/option.rb +9 -0
- data/lib/riddl/parameter.rb +54 -0
- data/lib/riddl/protocols/http/generator.rb +121 -0
- data/lib/riddl/protocols/http/parser.rb +199 -0
- data/lib/riddl/protocols/websocket.rb +103 -0
- data/lib/riddl/protocols/xmpp/generator.rb +176 -0
- data/lib/riddl/protocols/xmpp/parser.rb +118 -0
- data/lib/riddl/roles.rb +15 -0
- data/lib/riddl/roles/http%3A%2F%2Foauth.net%2F1.0%2Faccess_token.rb +30 -0
- data/lib/riddl/roles/http%3A%2F%2Foauth.net%2F1.0%2Fon_behalf.rb +22 -0
- data/lib/riddl/roles/http%3A%2F%2Foauth.net%2F1.0%2Frequest_token.rb +30 -0
- data/lib/riddl/roles/http%3A%2F%2Foauth.net%2F1.0/base.rb +67 -0
- data/lib/riddl/server.rb +519 -0
- data/lib/riddl/utils/description.rb +29 -0
- data/lib/riddl/utils/downloadify.rb +14 -0
- data/lib/riddl/utils/erbserve.rb +23 -0
- data/lib/riddl/utils/fileserve.rb +31 -0
- data/lib/riddl/utils/notifications_producer.rb +310 -0
- data/lib/riddl/utils/properties.rb +474 -0
- data/lib/riddl/utils/xsloverlay.rb +21 -0
- data/lib/riddl/wrapper.rb +280 -0
- data/lib/riddl/wrapper/declaration.rb +103 -0
- data/lib/riddl/wrapper/declaration/facade.rb +94 -0
- data/lib/riddl/wrapper/declaration/interface.rb +34 -0
- data/lib/riddl/wrapper/declaration/tile.rb +107 -0
- data/lib/riddl/wrapper/description.rb +69 -0
- data/lib/riddl/wrapper/description/access.rb +108 -0
- data/lib/riddl/wrapper/description/message_and_transformation.rb +131 -0
- data/lib/riddl/wrapper/description/resource.rb +271 -0
- data/lib/riddl/wrapper/layerchecker.rb +33 -0
- data/lib/riddl/wrapper/messageparser.rb +221 -0
- data/lib/riddl/wrapper/resourcechecker.rb +98 -0
- data/ns/common-patterns/addon-security/request.xml +25 -0
- data/ns/common-patterns/addon-security/response.xml +25 -0
- data/ns/common-patterns/downloadify/1.0/downloadify.xml +18 -0
- data/ns/common-patterns/notifications-consumer/1.0/consumer.xml +100 -0
- data/ns/common-patterns/notifications-producer/1.0/producer.xml +204 -0
- data/ns/common-patterns/properties/1.0/properties.schema.schema +140 -0
- data/ns/common-patterns/properties/1.0/properties.schema.xsl +89 -0
- data/ns/common-patterns/properties/1.0/properties.xml +150 -0
- data/ns/common/datatypes-1_0.rng +79 -0
- data/ns/common/relaxng-modular.rng +330 -0
- data/ns/common/relaxng.rng +10 -0
- data/ns/declaration/1.0/declaration.rng +114 -0
- data/ns/description/1.0/description.rng +302 -0
- data/riddl.gemspec +33 -0
- data/test/smartrunner.rb +48 -0
- data/test/tc_declaration-distributed.rb +79 -0
- data/test/tc_declaration-hybrid.rb +71 -0
- data/test/tc_declaration-local.rb +47 -0
- data/test/tc_helloworld.rb +17 -0
- data/test/tc_producer.rb +54 -0
- data/test/tc_properties.rb +72 -0
- data/tools/flash-policy-server.rb +12 -0
- data/tools/riddlcheck +36 -0
- data/tools/riddlcheck-1_0 +36 -0
- data/tools/riddlprocess +51 -0
- data/tools/riddlprocess-1_0 +51 -0
- metadata +291 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../constants')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../parameter')
|
3
|
+
|
4
|
+
module Riddl
|
5
|
+
module Protocols
|
6
|
+
module XMPP
|
7
|
+
class Parser
|
8
|
+
FORM_CONTENT_TYPES = [
|
9
|
+
#{{{
|
10
|
+
nil,
|
11
|
+
'application/x-www-form-urlencoded'
|
12
|
+
#}}}
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
STD_ATTRIBUTES = [
|
16
|
+
#{{{
|
17
|
+
'content-type',
|
18
|
+
'content-disposition',
|
19
|
+
'content-id',
|
20
|
+
'content-transfer-type',
|
21
|
+
'RIDDL-TYPE',
|
22
|
+
#}}}
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
def self::unescape(s)
|
26
|
+
#{{{
|
27
|
+
return s if s.nil?
|
28
|
+
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
29
|
+
[$1.delete('%')].pack('H*')
|
30
|
+
}
|
31
|
+
#}}}
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_part(input,head,ctype,content_disposition,content_id,riddl_type)
|
35
|
+
#{{{
|
36
|
+
head = Hash[
|
37
|
+
head.map do |h|
|
38
|
+
STD_ATTRIBUTES.include?(h.qname.name) ? nil : [h.qname.name, value]
|
39
|
+
end.compact
|
40
|
+
]
|
41
|
+
ctype = nil if riddl_type == 'simple'
|
42
|
+
filename = content_disposition[/ filename="?([^\";]*)"?/ni, 1]
|
43
|
+
name = content_disposition[/ name="?([^\";]*)"?/ni, 1] || content_id
|
44
|
+
|
45
|
+
if ctype || filename
|
46
|
+
body = Parameter::Tempfile.new("RiddlMultipart")
|
47
|
+
body.binmode if body.respond_to?(:binmode)
|
48
|
+
else
|
49
|
+
body = ''
|
50
|
+
end
|
51
|
+
|
52
|
+
body << input
|
53
|
+
|
54
|
+
add_to_params(name,body,filename,ctype,head)
|
55
|
+
#}}}
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_to_params(name,body,filename,ctype,head)
|
59
|
+
#{{{
|
60
|
+
if filename == ""
|
61
|
+
# filename is blank which means no file has been selected
|
62
|
+
elsif filename && ctype
|
63
|
+
body.rewind
|
64
|
+
|
65
|
+
# Take the basename of the upload's original filename.
|
66
|
+
# This handles the full Windows paths given by Internet Explorer
|
67
|
+
# (and perhaps other broken user agents) without affecting
|
68
|
+
# those which give the lone filename.
|
69
|
+
filename =~ /^(?:.*[:\\\/])?(.*)/m
|
70
|
+
filename = $1
|
71
|
+
|
72
|
+
@params << Parameter::Complex.new(name, ctype, body, filename, head)
|
73
|
+
elsif !filename && ctype
|
74
|
+
body.rewind
|
75
|
+
|
76
|
+
# Generic multipart cases, not coming from a form
|
77
|
+
@params << Parameter::Complex.new(name, ctype, body, nil, head)
|
78
|
+
else
|
79
|
+
@params << Parameter::Simple.new(name, body, :body)
|
80
|
+
end
|
81
|
+
#}}}
|
82
|
+
end
|
83
|
+
private :add_to_params
|
84
|
+
|
85
|
+
def parse_nested_query(qs, type)
|
86
|
+
#{{{
|
87
|
+
(qs || '').split(/[#{D}] */n).each do |p|
|
88
|
+
k, v = self.class::unescape(p).split('=', 2)
|
89
|
+
@params << Parameter::Simple.new(k,v,type)
|
90
|
+
end
|
91
|
+
#}}}
|
92
|
+
end
|
93
|
+
private :parse_nested_query
|
94
|
+
|
95
|
+
def initialize(query_string,input)
|
96
|
+
#{{{
|
97
|
+
@params = Riddl::Parameter::Array.new
|
98
|
+
|
99
|
+
parse_nested_query(query_string,:query)
|
100
|
+
|
101
|
+
input.find('/message/xr:part').each do |p|
|
102
|
+
content_type = p.attributes['content-type'] || ''
|
103
|
+
media_type = content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
|
104
|
+
if FORM_CONTENT_TYPES.include?(media_type)
|
105
|
+
# sub is a fix for Safari Ajax postings that always append \0
|
106
|
+
parse_nested_query(p.text.sub(/\0\z/, ''),:body)
|
107
|
+
else
|
108
|
+
parse_part(p.text,p.attributes,content_type,p.attributes['content_disposition']||'',p.attributes['content-id']||'',p.attributes['RIDDL-TYPE']||'')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
#}}}
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :params
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/riddl/roles.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Riddl
|
2
|
+
module Roles
|
3
|
+
@@roles = {}
|
4
|
+
def self::add(name,what)
|
5
|
+
@@roles[name] = what
|
6
|
+
end
|
7
|
+
def self::roles
|
8
|
+
@@roles
|
9
|
+
end
|
10
|
+
class Implementation
|
11
|
+
def self::before(method,parameters,headers,options); end
|
12
|
+
def self::after(method,code,response,headers,options); end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/http%3A%2F%2Foauth.net%2F1.0/base')
|
2
|
+
|
3
|
+
module Riddl
|
4
|
+
module Roles
|
5
|
+
module OAuth
|
6
|
+
|
7
|
+
module AccessToken
|
8
|
+
WANTED = [:consumer_key, :consumer_secret, :token, :token_secret, :verifier]
|
9
|
+
|
10
|
+
def self::after(fullpath,method,code,response,headers,options)
|
11
|
+
if code == 200
|
12
|
+
Riddl::Roles::OAuth::Response.new(response[0].value.read)
|
13
|
+
else
|
14
|
+
response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self::before(fullpath,method,parameters,headers,options)
|
19
|
+
unless WANTED.all?{ |e| options.has_key?(e) }
|
20
|
+
raise ArgumentError, "Riddl::Options have to include: #{WANTED.join(', ')}"
|
21
|
+
end
|
22
|
+
Riddl::Roles::OAuth::sign(fullpath,method,parameters,headers,options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Riddl::Roles::add("http://oauth.net/1.0/access_token",Riddl::Roles::OAuth::AccessToken)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/http%3A%2F%2Foauth.net%2F1.0/base')
|
2
|
+
|
3
|
+
module Riddl
|
4
|
+
module Roles
|
5
|
+
module OAuth
|
6
|
+
|
7
|
+
module OnBehalf
|
8
|
+
WANTED = [:consumer_key, :consumer_secret, :token, :token_secret]
|
9
|
+
|
10
|
+
def self::before(fullpath,method,parameters,headers,options)
|
11
|
+
unless WANTED.all?{ |e| options.has_key?(e) }
|
12
|
+
raise ArgumentError, "Riddl::Options have to include: #{WANTED.join(', ')}"
|
13
|
+
end
|
14
|
+
Riddl::Roles::OAuth::sign(fullpath,method,parameters,headers,options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Riddl::Roles::add("http://oauth.net/1.0/on_behalf",Riddl::Roles::OAuth::OnBehalf)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/http%3A%2F%2Foauth.net%2F1.0/base')
|
2
|
+
|
3
|
+
module Riddl
|
4
|
+
module Roles
|
5
|
+
module OAuth
|
6
|
+
|
7
|
+
module RequestToken
|
8
|
+
WANTED = [:consumer_key, :consumer_secret]
|
9
|
+
|
10
|
+
def self::after(fullpath,method,code,response,headers,options)
|
11
|
+
if code == 200
|
12
|
+
Riddl::Roles::OAuth::Response.new(response[0].value.read)
|
13
|
+
else
|
14
|
+
response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self::before(fullpath,method,parameters,headers,options)
|
19
|
+
unless WANTED.all?{ |e| options.has_key?(e) }
|
20
|
+
raise ArgumentError, "Riddl::Options have to include: #{WANTED.join(', ')}"
|
21
|
+
end
|
22
|
+
Riddl::Roles::OAuth::sign(fullpath,method,parameters,headers,options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Riddl::Roles::add("http://oauth.net/1.0/request_token",Riddl::Roles::OAuth::RequestToken)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../protocols/http/generator')
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Riddl
|
6
|
+
module Roles
|
7
|
+
module OAuth
|
8
|
+
DIGEST = OpenSSL::Digest::Digest.new('sha1')
|
9
|
+
VERSION_MAJOR = 1
|
10
|
+
VERSION_MINOR = 0
|
11
|
+
|
12
|
+
class Response
|
13
|
+
def method_missing(name)
|
14
|
+
@provided[name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def items
|
18
|
+
@provided.keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(qs)
|
22
|
+
@provided = {}
|
23
|
+
(qs || '').split(/[&] */n).each do |p|
|
24
|
+
k, v = Protocols::HTTP::Parser::unescape(p).split('=', 2)
|
25
|
+
@provided[k.to_sym] = v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self::sign(fullpath,method,parameters,headers,options)
|
31
|
+
signature_string = method.upcase + "&" + Protocols::HTTP::Generator::escape(fullpath) + "&"
|
32
|
+
|
33
|
+
sparams = []
|
34
|
+
if parameters.class == Array
|
35
|
+
parameters.each do |p|
|
36
|
+
if p.class == Riddl::Parameter::Simple
|
37
|
+
sparams << [Protocols::HTTP::Generator::escape(p.name),Protocols::HTTP::Generator::escape(p.value)]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
oparams = []
|
43
|
+
oparams << ["oauth_consumer_key",Protocols::HTTP::Generator::escape(options[:consumer_key])]
|
44
|
+
oparams << ["oauth_signature_method","HMAC-SHA1"]
|
45
|
+
oparams << ["oauth_timestamp",Time.new.to_i.to_s]
|
46
|
+
oparams << ["oauth_version","1.0"]
|
47
|
+
oparams << ["oauth_nonce",Protocols::HTTP::Generator::escape(OpenSSL::Digest::SHA1.hexdigest(rand(10000).to_s)[0...32])]
|
48
|
+
oparams << ["oauth_token",Protocols::HTTP::Generator::escape(options[:token])] if options[:token]
|
49
|
+
oparams << ["oauth_verifier",Protocols::HTTP::Generator::escape(options[:verifier])] if options[:verifier]
|
50
|
+
|
51
|
+
params = (sparams + oparams).sort{|a,b|a[0]<=>b[0]}.map{ |e| e[0] + '=' + e[1] }.join('&')
|
52
|
+
signature_string += Protocols::HTTP::Generator::escape(params)
|
53
|
+
|
54
|
+
signature = OpenSSL::HMAC.digest(DIGEST,"#{Protocols::HTTP::Generator::escape(options[:consumer_secret])}&#{Protocols::HTTP::Generator::escape(options[:token_secret])}",signature_string)
|
55
|
+
signature = [signature].pack("m").gsub(/\n/, '')
|
56
|
+
|
57
|
+
oparams << ["oauth_signature", Protocols::HTTP::Generator::escape(signature)]
|
58
|
+
|
59
|
+
oparams.unshift(["realm", Protocols::HTTP::Generator::escape(options[:realm])]) if options[:realm]
|
60
|
+
|
61
|
+
headers['Authorization'] = 'OAuth ' + oparams.map{|e|e[0]+'='+"\"#{e[1]}\""}.join(', ')
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/lib/riddl/server.rb
ADDED
@@ -0,0 +1,519 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/constants')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/implementation')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/protocols/http/parser')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/protocols/http/generator')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/protocols/xmpp/parser')
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + '/protocols/xmpp/generator')
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/protocols/websocket')
|
8
|
+
require File.expand_path(File.dirname(__FILE__) + '/header')
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '/parameter')
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + '/error')
|
11
|
+
require File.expand_path(File.dirname(__FILE__) + '/wrapper')
|
12
|
+
require File.expand_path(File.dirname(__FILE__) + '/utils/description')
|
13
|
+
|
14
|
+
require 'optparse'
|
15
|
+
require 'stringio'
|
16
|
+
require 'rack/content_length'
|
17
|
+
require 'rack/chunked'
|
18
|
+
require 'securerandom'
|
19
|
+
require 'yaml'
|
20
|
+
require 'blather/client/client'
|
21
|
+
|
22
|
+
module Riddl
|
23
|
+
|
24
|
+
class Server
|
25
|
+
|
26
|
+
class Execution #{{{
|
27
|
+
attr_reader :response,:headers
|
28
|
+
def initialize(response,headers)
|
29
|
+
@response = (response.is_a?(Array) ? response : [response])
|
30
|
+
@headers = (headers.is_a?(Array) ? headers : [headers])
|
31
|
+
@response.delete_if do |r|
|
32
|
+
r.class != Riddl::Parameter::Simple && r.class != Riddl::Parameter::Complex
|
33
|
+
end
|
34
|
+
@headers.delete_if do |h|
|
35
|
+
h.class != Riddl::Header
|
36
|
+
end
|
37
|
+
@headers.compact!
|
38
|
+
@response.compact!
|
39
|
+
@headers = Hash[ @headers.map{ |h| [h.name, h.value] } ]
|
40
|
+
end
|
41
|
+
end #}}}
|
42
|
+
|
43
|
+
OPTS = {
|
44
|
+
:host => 'localhost',
|
45
|
+
:port => 9292,
|
46
|
+
:secure => false,
|
47
|
+
:mode => :debug,
|
48
|
+
:basepath => File.expand_path(File.dirname($0)),
|
49
|
+
:pidfile => File.basename($0,'.rb') + '.pid',
|
50
|
+
:conffile => File.basename($0,'.rb') + '.conf'
|
51
|
+
}
|
52
|
+
|
53
|
+
def loop! #{{{
|
54
|
+
########################################################################################################################
|
55
|
+
# parse arguments
|
56
|
+
########################################################################################################################
|
57
|
+
verbose = false
|
58
|
+
operation = "start"
|
59
|
+
ARGV.options { |opt|
|
60
|
+
opt.summary_indent = ' ' * 4
|
61
|
+
opt.banner = "Usage:\n#{opt.summary_indent}ruby server.rb [options] start|startclean|stop|restart|info\n"
|
62
|
+
opt.on("Options:")
|
63
|
+
opt.on("--verbose", "-v", "Do not daemonize. Write ouput to console.") { verbose = true }
|
64
|
+
opt.on("--help", "-h", "This text.") { puts opt; exit }
|
65
|
+
opt.separator(opt.summary_indent + "start|stop|restart|info".ljust(opt.summary_width+1) + "Do operation start, stop, restart or get information.")
|
66
|
+
opt.separator(opt.summary_indent + "startclean".ljust(opt.summary_width+1) + "Delete all instances before starting.")
|
67
|
+
opt.parse!
|
68
|
+
}
|
69
|
+
unless %w{start startclean stop restart info}.include?(ARGV[0])
|
70
|
+
puts ARGV.options
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
operation = ARGV[0]
|
74
|
+
|
75
|
+
########################################################################################################################
|
76
|
+
# status and info
|
77
|
+
########################################################################################################################
|
78
|
+
pid = File.read(@riddl_opts[:basepath] + '/' + @riddl_opts[:pidfile]).to_i rescue pid = 666
|
79
|
+
status = Proc.new do
|
80
|
+
begin
|
81
|
+
Process.getpgid pid
|
82
|
+
true
|
83
|
+
rescue Errno::ESRCH
|
84
|
+
false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
if operation == "info" && status.call == false
|
88
|
+
puts "Server (#{@riddl_opts[:url]}) not running"
|
89
|
+
exit
|
90
|
+
end
|
91
|
+
if operation == "info" && status.call == true
|
92
|
+
puts "Server (#{@riddl_opts[:url]}) running as #{pid}"
|
93
|
+
begin
|
94
|
+
stats = `ps -o "vsz,rss,lstart,time" -p #{pid}`.split("\n")[1].strip.split(/ +/)
|
95
|
+
puts "Virtual: #{"%0.2f" % (stats[0].to_f/1024)} MiB"
|
96
|
+
puts "Resident: #{"%0.2f" % (stats[1].to_f/1024)} MiB"
|
97
|
+
puts "Started: #{stats[2..-2].join(' ')}"
|
98
|
+
puts "CPU Time: #{stats.last}"
|
99
|
+
rescue
|
100
|
+
end
|
101
|
+
exit
|
102
|
+
end
|
103
|
+
if %w{start startclean}.include?(operation) && status.call == true
|
104
|
+
puts "Server (#{@riddl_opts[:url]}) already started"
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
|
108
|
+
########################################################################################################################
|
109
|
+
# stop/restart server
|
110
|
+
########################################################################################################################
|
111
|
+
if %w{stop restart}.include?(operation)
|
112
|
+
if status.call == false
|
113
|
+
puts "Server (#{@riddl_opts[:url]}) maybe not started?"
|
114
|
+
else
|
115
|
+
puts "Server (#{@riddl_opts[:url]}) stopped"
|
116
|
+
puts "Waiting while server goes down ..."
|
117
|
+
while status.call
|
118
|
+
Process.kill "SIGTERM", pid
|
119
|
+
sleep 0.3
|
120
|
+
end
|
121
|
+
end
|
122
|
+
exit unless operation == "restart"
|
123
|
+
end
|
124
|
+
|
125
|
+
########################################################################################################################
|
126
|
+
# start server
|
127
|
+
########################################################################################################################
|
128
|
+
if operation == 'startclean'
|
129
|
+
Dir.glob(File.expand_path(@riddl_opts[:basepath] + '/instances/*')).each do |d|
|
130
|
+
FileUtils.rm_r(d) if File.basename(d) =~ /^\d+$/
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
app = Rack::Builder.new self
|
135
|
+
unless @riddl_logger.nil?
|
136
|
+
app.use Rack::CommonLogger, @riddl_logger
|
137
|
+
end
|
138
|
+
|
139
|
+
server = if verbose
|
140
|
+
Rack::Server.new(
|
141
|
+
:app => app,
|
142
|
+
:Port => @riddl_opts[:port],
|
143
|
+
:environment => (@riddl_opts[:mode] == :debug ? 'development' : 'deployment'),
|
144
|
+
:server => 'thin',
|
145
|
+
:pid => File.expand_path(@riddl_opts[:basepath] + '/' + @riddl_opts[:pidfile])
|
146
|
+
)
|
147
|
+
else
|
148
|
+
server = Rack::Server.new(
|
149
|
+
:app => app,
|
150
|
+
:Port => @riddl_opts[:port],
|
151
|
+
:environment => 'none',
|
152
|
+
:server => 'thin',
|
153
|
+
:pid => File.expand_path(@riddl_opts[:basepath] + '/' + @riddl_opts[:pidfile]),
|
154
|
+
:daemonize => true
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
# remove LINT in any case as it breaks websockets
|
159
|
+
server.middleware.each do |k,v|
|
160
|
+
v.delete [Rack::Lint]
|
161
|
+
end
|
162
|
+
|
163
|
+
EM.run do
|
164
|
+
puts "Server (#{@riddl_opts[:url]}) started as #{Process.pid}"
|
165
|
+
puts "XMPP support (#{@riddl_xmpp_jid}) active" if @riddl_xmpp_jid && @riddl_xmpp_pass
|
166
|
+
server.start
|
167
|
+
if @riddl_xmpp_jid && @riddl_xmpp_pass
|
168
|
+
xmpp = Blather::Client.setup @riddl_xmpp_jid, @riddl_xmpp_pass
|
169
|
+
xmpp.register_handler(:message, :type => :normal) do |m|
|
170
|
+
began_at = Time.now
|
171
|
+
instance = dup
|
172
|
+
instance.__xmpp_call(xmpp,m)
|
173
|
+
now = Time.now
|
174
|
+
instance.riddl_log.write Rack::CommonLogger::FORMAT % [
|
175
|
+
@riddl_xmpp_jid || "-",
|
176
|
+
m.from || "-",
|
177
|
+
now.strftime("%d/%b/%Y %H:%M:%S"),
|
178
|
+
instance.riddl_method.upcase,
|
179
|
+
instance.riddl_pinfo,
|
180
|
+
'',
|
181
|
+
'XMPP',
|
182
|
+
instance.riddl_status,
|
183
|
+
'?',
|
184
|
+
now - began_at ]
|
185
|
+
|
186
|
+
end
|
187
|
+
xmpp.connect
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end #}}}
|
191
|
+
|
192
|
+
attr_reader :riddl_log, :riddl_method, :riddl_pinfo, :riddl_status
|
193
|
+
|
194
|
+
def initialize(riddl,opts={},&blk)# {{{
|
195
|
+
@riddl_opts = {}
|
196
|
+
OPTS.each do |k,v|
|
197
|
+
@riddl_opts[k] = opts.has_key?(k) ? opts[k] : v
|
198
|
+
end
|
199
|
+
|
200
|
+
if File.exists?(@riddl_opts[:basepath] + '/' + @riddl_opts[:conffile])
|
201
|
+
@riddl_opts.merge!(YAML::load_file(@riddl_opts[:basepath] + '/' + @riddl_opts[:conffile]))
|
202
|
+
end
|
203
|
+
@riddl_opts[:url] = (@riddl_opts[:secure] ? 'https://' : 'http://') + @riddl_opts[:host] + ':' + @riddl_opts[:port].to_s
|
204
|
+
|
205
|
+
@riddl_logger = nil
|
206
|
+
@riddl_process_out = true
|
207
|
+
@riddl_cross_site_xhr = false
|
208
|
+
@accessible_description = false
|
209
|
+
@riddl_description_string = ''
|
210
|
+
@riddl_paths = []
|
211
|
+
|
212
|
+
@riddl_interfaces = {}
|
213
|
+
instance_eval(&blk) if block_given?
|
214
|
+
|
215
|
+
@riddl = Riddl::Wrapper.new(riddl,@accessible_description)
|
216
|
+
if @riddl.description?
|
217
|
+
raise SpecificationError, 'RIDDL description does not conform to specification' unless @riddl.validate!
|
218
|
+
@riddl_description_string = @riddl.description.xml
|
219
|
+
elsif @riddl.declaration?
|
220
|
+
raise SpecificationError, 'RIDDL declaration does not conform to specification' unless @riddl.validate!
|
221
|
+
@riddl_description_string = @riddl.declaration.description_xml
|
222
|
+
else
|
223
|
+
raise SpecificationError, 'Not a RIDDL file'
|
224
|
+
end
|
225
|
+
|
226
|
+
@riddl.load_necessary_handlers!
|
227
|
+
@riddl_paths = @riddl.paths
|
228
|
+
end# }}}
|
229
|
+
|
230
|
+
def call(env)# {{{
|
231
|
+
dup.__http_call(env)
|
232
|
+
end# }}}
|
233
|
+
|
234
|
+
def __call #{{{
|
235
|
+
@riddl_message = @riddl.io_messages(@riddl_matching_path[0],@riddl_method,@riddl_parameters,@riddl_headers)
|
236
|
+
if @riddl_message.nil?
|
237
|
+
if @riddl_info[:env].has_key?('HTTP_ORIGIN') && @riddl_cross_site_xhr
|
238
|
+
@riddl_res['Access-Control-Allow-Origin'] = '*'
|
239
|
+
@riddl_res['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
240
|
+
@riddl_res['Access-Control-Allow-Headers'] = @riddl_info[:env]['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] if @riddl_info[:env]['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']
|
241
|
+
@riddl_res['Access-Control-Max-Age'] = '0'
|
242
|
+
@riddl_res['Content-Length'] = '0'
|
243
|
+
@riddl_status = 200
|
244
|
+
else
|
245
|
+
@riddl_log.write "501: the #{@riddl_method} parameters are not matching anything in the description.\n"
|
246
|
+
@riddl_status = 501 # not implemented?!
|
247
|
+
end
|
248
|
+
else
|
249
|
+
if get 'riddl-description-request'
|
250
|
+
run Riddl::Utils::Description::XML, @riddl_description_string
|
251
|
+
else
|
252
|
+
if @riddl.description?
|
253
|
+
instance_exec(@riddl_info, &@riddl_interfaces[nil])
|
254
|
+
elsif @riddl.declaration?
|
255
|
+
ifs = @riddl_message.route? ? @riddl_message.route : [@riddl_message]
|
256
|
+
ifs.each do |m|
|
257
|
+
@riddl_path = '/'
|
258
|
+
if m.interface.base.nil?
|
259
|
+
if @riddl_interfaces.key? m.interface.name
|
260
|
+
@riddl_info[:r] = m.interface.real_path(@riddl_pinfo).sub(/\//,'').split('/')
|
261
|
+
@riddl_info[:h]['RIDDL_DECLARATION_PATH'] = @riddl_pinfo
|
262
|
+
@riddl_info[:h]['RIDDL_DECLARATION_RESOURCE'] = m.interface.top
|
263
|
+
@riddl_info[:s] = m.interface.sub.sub(/\//,'').split('/')
|
264
|
+
@riddl_info.merge!(:match => matching_path)
|
265
|
+
instance_exec(@riddl_info, &@riddl_interfaces[m.interface.name])
|
266
|
+
else
|
267
|
+
@riddl_log.write "501: not implemented (for remote: add @location in declaration; for local: add to Riddl::Server).\n"
|
268
|
+
@riddl_status = 501 # not implemented?!
|
269
|
+
break
|
270
|
+
end
|
271
|
+
else
|
272
|
+
run Riddl::Utils::Description::Call, @riddl_exe, @riddl_pinfo, m.interface.top, m.interface.base, m.interface.des.to_doc, m.interface.real_path(@riddl_pinfo)
|
273
|
+
end
|
274
|
+
break unless @riddl_status == 200
|
275
|
+
@riddl_info.merge!(:h => @riddl_exe.headers, :p => @riddl_exe.response)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
if @riddl_info[:env].has_key?('HTTP_ORIGIN') && @riddl_cross_site_xhr
|
280
|
+
@riddl_res['Access-Control-Allow-Origin'] = '*'
|
281
|
+
@riddl_res['Access-Control-Max-Age'] = '0'
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end #}}}
|
285
|
+
|
286
|
+
def __xmpp_call(env,raw) #{{{
|
287
|
+
Dir.chdir(@riddl_opts[:basepath]) if @riddl_opts[:basepath]
|
288
|
+
@riddl_log = @riddl_logger || STDOUT
|
289
|
+
|
290
|
+
@riddl_env = XML::Smart::Dom::Element.new(raw).parent
|
291
|
+
@riddl_env.register_namespace 'xr', Riddl::Protocols::XMPP::XR_NS
|
292
|
+
@riddl_res = env
|
293
|
+
@riddl_status = 404
|
294
|
+
|
295
|
+
@riddl_pinfo = ('/' + @riddl_env.root.attributes['to'].sub(/^[^\/]+/,'')).gsub(/\/+/,'/')
|
296
|
+
@riddl_pinfo.gsub!(/\?(.*)/).each do
|
297
|
+
@riddl_query_string = $1; ''
|
298
|
+
end
|
299
|
+
@riddl_matching_path = @riddl_paths.find{ |e| e[1] =~ @riddl_pinfo }
|
300
|
+
|
301
|
+
if @riddl_matching_path
|
302
|
+
@riddl_method = @riddl_env.find('string(/message/xr:operation)').downcase
|
303
|
+
|
304
|
+
@riddl_headers = {}
|
305
|
+
@riddl_env.find('/message/xr:header').each do |e|
|
306
|
+
@riddl_headers[e.attributes['name']] = e.text
|
307
|
+
end
|
308
|
+
@riddl_parameters = Protocols::XMPP::Parser.new(
|
309
|
+
@riddl_query_string,
|
310
|
+
@riddl_env
|
311
|
+
).params
|
312
|
+
|
313
|
+
@riddl_path = '/'
|
314
|
+
@riddl_info = {
|
315
|
+
:h => @riddl_headers,
|
316
|
+
:p => @riddl_parameters,
|
317
|
+
:r => @riddl_pinfo.sub(/\//,'').split('/').map{|e|Protocols::HTTP::Parser::unescape(e)},
|
318
|
+
:s => @riddl_matching_path[0].sub(/\//,'').split('/').map{|e|Protocols::HTTP::Parser::unescape(e)},
|
319
|
+
:m => @riddl_method,
|
320
|
+
:env => Hash[@riddl_env.root.attributes.map{|a| [a.qname.name, a.value] }].merge({ 'riddl.transport' => 'xmpp' }),
|
321
|
+
:match => []
|
322
|
+
}
|
323
|
+
|
324
|
+
__call
|
325
|
+
else
|
326
|
+
@riddl_log.write "404: this resource for sure does not exist.\n"
|
327
|
+
@riddl_status = 404 # client requests wrong path
|
328
|
+
end
|
329
|
+
stanza = if @riddl_exe && @riddl_status == 200
|
330
|
+
Protocols::XMPP::Generator.new(@riddl_status,@riddl_exe.response,@riddl_exe.headers).generate
|
331
|
+
else
|
332
|
+
Protocols::XMPP::Error.new(@riddl_status).generate
|
333
|
+
end
|
334
|
+
stanza.from = raw.to
|
335
|
+
stanza.to = raw.from
|
336
|
+
stanza.id = raw.id
|
337
|
+
@riddl_res.write stanza
|
338
|
+
end #}}}
|
339
|
+
|
340
|
+
def __http_call(env) #{{{
|
341
|
+
Dir.chdir(@riddl_opts[:basepath]) if @riddl_opts[:basepath]
|
342
|
+
|
343
|
+
@riddl_env = env
|
344
|
+
@riddl_env['rack.logger'] = @riddl_logger if @riddl_logger
|
345
|
+
@riddl_log = @riddl_logger || @riddl_env['rack.errors']
|
346
|
+
@riddl_res = Rack::Response.new
|
347
|
+
@riddl_status = 404
|
348
|
+
|
349
|
+
@riddl_pinfo = @riddl_env["PATH_INFO"].gsub(/\/+/,'/')
|
350
|
+
@riddl_matching_path = @riddl_paths.find{ |e| e[1] =~ @riddl_pinfo }
|
351
|
+
|
352
|
+
if @riddl_matching_path
|
353
|
+
@riddl_query_string = @riddl_env['QUERY_STRING']
|
354
|
+
@riddl_raw = @riddl_env['rack.input']
|
355
|
+
|
356
|
+
@riddl_headers = {}
|
357
|
+
@riddl_env.each do |h,v|
|
358
|
+
@riddl_headers[$1] = v if h =~ /^HTTP_(.*)$/
|
359
|
+
end
|
360
|
+
@riddl_parameters = Protocols::HTTP::Parser.new(
|
361
|
+
@riddl_query_string,
|
362
|
+
@riddl_raw,
|
363
|
+
@riddl_env['CONTENT_TYPE'],
|
364
|
+
@riddl_env['CONTENT_LENGTH'],
|
365
|
+
@riddl_env['HTTP_CONTENT_DISPOSITION'],
|
366
|
+
@riddl_env['HTTP_CONTENT_ID'],
|
367
|
+
@riddl_env['HTTP_RIDDL_TYPE']
|
368
|
+
).params
|
369
|
+
|
370
|
+
@riddl_method = @riddl_env['REQUEST_METHOD'].downcase
|
371
|
+
@riddl_path = '/'
|
372
|
+
@riddl_info = {
|
373
|
+
:h => @riddl_headers,
|
374
|
+
:p => @riddl_parameters,
|
375
|
+
:r => @riddl_pinfo.sub(/\//,'').split('/').map{|e|Protocols::HTTP::Parser::unescape(e)},
|
376
|
+
:s => @riddl_matching_path[0].sub(/\//,'').split('/').map{|e|Protocols::HTTP::Parser::unescape(e)},
|
377
|
+
:m => @riddl_method,
|
378
|
+
:env => @riddl_env.reject{|k,v| k =~ /^rack\./}.merge({'riddl.transport' => 'xmpp'}),
|
379
|
+
:match => []
|
380
|
+
}
|
381
|
+
|
382
|
+
if @riddl_info[:env]["HTTP_CONNECTION"] =~ /Upgrade/ && @riddl_info[:env]["HTTP_UPGRADE"] =~ /\AWebSocket\z/i
|
383
|
+
# TODO raise error when declaration and route or (not route and non-local interface)
|
384
|
+
# raise SpecificationError, 'RIDDL description does not conform to specification' unless @riddl.validate!
|
385
|
+
@riddl_info[:m] = @riddl_method = 'websocket'
|
386
|
+
if @riddl.description?
|
387
|
+
instance_exec(@riddl_info, &@riddl_interfaces[nil])
|
388
|
+
elsif @riddl.declaration?
|
389
|
+
@riddl_message = @riddl.io_messages(@riddl_matching_path[0],'websocket',@riddl_parameters,@riddl_headers)
|
390
|
+
# one ws connection, no overlay
|
391
|
+
unless @riddl_message.nil?
|
392
|
+
if @riddl_interfaces.key? @riddl_message.interface.name
|
393
|
+
@riddl_info[:r] = @riddl_message.interface.real_path(@riddl_pinfo).sub(/\//,'').split('/')
|
394
|
+
@riddl_info[:h]['RIDDL_DECLARATION_PATH'] = @riddl_pinfo
|
395
|
+
@riddl_info[:h]['RIDDL_DECLARATION_RESOURCE'] = @riddl_message.interface.top
|
396
|
+
@riddl_info[:s] = @riddl_message.interface.sub.sub(/\//,'').split('/')
|
397
|
+
@riddl_info.merge!(:match => matching_path)
|
398
|
+
instance_exec(@riddl_info, &@riddl_interfaces[@riddl_message.interface.name])
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
return [-1, {}, []]
|
403
|
+
else
|
404
|
+
__call
|
405
|
+
end
|
406
|
+
else
|
407
|
+
@riddl_log.write "404: this resource for sure does not exist.\n"
|
408
|
+
@riddl_status = 404 # client requests wrong path
|
409
|
+
end
|
410
|
+
if @riddl_exe
|
411
|
+
if @riddl_status == 200
|
412
|
+
@riddl_res.write Protocols::HTTP::Generator.new(@riddl_exe.response,@riddl_res).generate.read
|
413
|
+
end
|
414
|
+
@riddl_exe.headers.each do |n,h|
|
415
|
+
@riddl_res[n] = h
|
416
|
+
end
|
417
|
+
end
|
418
|
+
@riddl_res.status = @riddl_status
|
419
|
+
@riddl_res.finish
|
420
|
+
end #}}}
|
421
|
+
|
422
|
+
def process_out(pout)# {{{
|
423
|
+
@riddl_process_out = pout
|
424
|
+
end# }}}
|
425
|
+
def xmpp(jid,pass)# {{{
|
426
|
+
@riddl_xmpp_jid = jid
|
427
|
+
@riddl_xmpp_pass = pass
|
428
|
+
end# }}}
|
429
|
+
def cross_site_xhr(csxhr)# {{{
|
430
|
+
@riddl_cross_site_xhr = csxhr
|
431
|
+
end# }}}
|
432
|
+
def logger(lgr)# {{{
|
433
|
+
@riddl_logger = lgr
|
434
|
+
end# }}}
|
435
|
+
def accessible_description(ad)# {{{
|
436
|
+
@accessible_description = ad
|
437
|
+
end# }}}
|
438
|
+
def interface(name,&block) #{{{
|
439
|
+
@riddl_interfaces[name] = block
|
440
|
+
end #}}}
|
441
|
+
|
442
|
+
def on(resource, &block)# {{{
|
443
|
+
if @riddl_paths.empty? # default interface, when a description and "on" syntax in server
|
444
|
+
@riddl_interfaces[nil] = block
|
445
|
+
return
|
446
|
+
end
|
447
|
+
|
448
|
+
@riddl_path << (@riddl_path == '/' ? resource : '/' + resource)
|
449
|
+
|
450
|
+
|
451
|
+
### only descend when there is a possibility that it holds the right path
|
452
|
+
rp = @riddl_path.sub(/\//,'').split('/')
|
453
|
+
|
454
|
+
block.call(@riddl_info.merge!(:match => matching_path)) if @riddl_info[:s][rp.length-1] == rp.last
|
455
|
+
@riddl_path = File.dirname(@riddl_path).gsub(/\/+/,'/')
|
456
|
+
end# }}}
|
457
|
+
|
458
|
+
def use(blk,*args)# {{{
|
459
|
+
instance_eval(&blk)
|
460
|
+
end# }}}
|
461
|
+
|
462
|
+
def run(what,*args)# {{{
|
463
|
+
return if @riddl_path == ''
|
464
|
+
if what.class == Class && what.superclass == Riddl::WebSocketImplementation
|
465
|
+
data = WebSocketParserData.new
|
466
|
+
data.request_path = @riddl_pinfo
|
467
|
+
data.request_url = @riddl_pinfo + '?' + @riddl_query_string
|
468
|
+
data.query_string = @riddl_query_string
|
469
|
+
data.http_method = @riddl_env['REQUEST_METHOD']
|
470
|
+
data.body = @riddl_env['rack.input'].read
|
471
|
+
data.headers = Hash[
|
472
|
+
@riddl_headers.map { |key, value| [key.downcase.gsub('_','-'), value] }
|
473
|
+
]
|
474
|
+
w = what.new(@riddl_info.merge!(:a => args, :version => @riddl_env['HTTP_SEC_WEBSOCKET_VERSION'], :match => matching_path))
|
475
|
+
w.io = Riddl::WebSocket.new(w, @riddl_env['thin.connection'])
|
476
|
+
w.io.dispatch(data)
|
477
|
+
end
|
478
|
+
if what.class == Class && what.superclass == Riddl::Implementation
|
479
|
+
w = what.new(@riddl_info.merge!(:a => args, :match => matching_path))
|
480
|
+
@riddl_exe = Riddl::Server::Execution.new(w.response,w.headers)
|
481
|
+
@riddl_status = w.status
|
482
|
+
if @riddl_process_out && @riddl_status == 200
|
483
|
+
unless @riddl.check_message(@riddl_exe.response,@riddl_exe.headers,@riddl_message.out)
|
484
|
+
@riddl_log.write "500: the return for the #{@riddl_method} is not matching anything in the description.\n"
|
485
|
+
@riddl_status = 500
|
486
|
+
return
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end# }}}
|
491
|
+
|
492
|
+
def method(what)# {{{
|
493
|
+
if !@riddl_message.nil? && what.class == Hash && what.length == 1
|
494
|
+
met, min = what.first
|
495
|
+
@riddl_path == @riddl_matching_path[0] && min == @riddl_message.in.name && @riddl_method == met.to_s.downcase
|
496
|
+
else
|
497
|
+
false
|
498
|
+
end
|
499
|
+
end # }}}
|
500
|
+
def post(min='*'); return false if @riddl_message.nil?; @riddl_path == '/' + @riddl_info[:s].join('/') && min == @riddl_message.in.name && @riddl_method == 'post' end
|
501
|
+
def get(min='*'); return false if @riddl_message.nil?; @riddl_path == '/' + @riddl_info[:s].join('/') && min == @riddl_message.in.name && @riddl_method == 'get' end
|
502
|
+
def delete(min='*'); return false if @riddl_message.nil?; @riddl_path == '/' + @riddl_info[:s].join('/') && min == @riddl_message.in.name && @riddl_method == 'delete' end
|
503
|
+
def put(min='*'); return false if @riddl_message.nil?; @riddl_path == '/' + @riddl_info[:s].join('/') && min == @riddl_message.in.name && @riddl_method == 'put' end
|
504
|
+
def websocket; return false if @riddl_message.nil?; @riddl_path == '/' + @riddl_info[:s].join('/') && @riddl_method == 'websocket' end
|
505
|
+
def resource(rname=nil); return rname.nil? ? '{}' : rname end
|
506
|
+
|
507
|
+
def matching_path #{{{
|
508
|
+
@riddl_path.sub(/\//,'').split('/')
|
509
|
+
end #}}}
|
510
|
+
|
511
|
+
def declaration_path #{{{
|
512
|
+
@riddl_info[:h]['RIDDL_DECLARATION_PATH']
|
513
|
+
end #}}}
|
514
|
+
def declaration_resource #{{{
|
515
|
+
@riddl_info[:h]['RIDDL_DECLARATION_RESOURCE']
|
516
|
+
end #}}}
|
517
|
+
|
518
|
+
end
|
519
|
+
end
|