ruby-yadis 0.3.2 → 0.3.3

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/examples/openid.rb CHANGED
@@ -6,17 +6,22 @@ require 'yadis'
6
6
  # Visit http://curl.haxx.se/docs/caextract.html and uncomment:
7
7
  # YADIS.ca_path = '/path/to/cacert.pem'
8
8
 
9
- yadis = YADIS.discover('http://brian.myopenid.com/')
10
- if yadis.nil? or yadis.openid_servers.length == 0
11
- p 'No XRDS found'
9
+ url = 'http://brianellin.com/'
10
+ puts "Looking for servers for #{url}\n"
11
+
12
+ yadis = YADIS.discover(url)
13
+ openid_filter = Proc.new do |service|
14
+ service.service_types.member?('http://openid.net/signon/1.0') ? service : nil
15
+ end
16
+
17
+ if yadis.nil?
18
+ puts 'No XRDS found.'
12
19
  else
13
- servers = yadis.openid_servers
14
- if servers.length == 0
15
- p 'No OpenID servers found'
20
+ services = yadis.filter_services(openid_filter)
21
+ if services.length > 0
22
+ services.each {|s| puts "OpenID server found: #{s.uri}"}
16
23
  else
17
- servers.each do |s|
18
- p "OpenID server found: #{s.type}, #{s.uri}"
19
- end
24
+ puts 'No OpenID servers found.'
20
25
  end
21
26
  end
22
27
 
@@ -0,0 +1,79 @@
1
+ require "uri"
2
+
3
+ begin
4
+ require "net/https"
5
+ rescue LoadError
6
+ HAS_OPENSSL_ = false
7
+ require 'net/http'
8
+ else
9
+ HAS_OPENSSL_ = true
10
+ end
11
+
12
+ class NetHTTPFetcher
13
+
14
+ attr_accessor :ca_path
15
+
16
+ def initialize(read_timeout=20, open_timeout=20)
17
+ @read_timeout = read_timeout
18
+ @open_timeout = open_timeout
19
+ @ca_path = nil
20
+ end
21
+
22
+ def get(url, params = nil)
23
+ resp, final_url = do_get(url, params)
24
+ if resp.nil?
25
+ nil
26
+ else
27
+ [final_url, resp]
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ # return a Net::HTTP object ready for use
34
+ def get_http_obj(uri)
35
+ http = Net::HTTP.new(uri.host, uri.port)
36
+ http.read_timeout = @read_timeout
37
+ http.open_timeout = @open_timeout
38
+
39
+ if uri.scheme == 'https'
40
+ if HAS_OPENSSL_
41
+ http.use_ssl = true
42
+ if @ca_path
43
+ http.ca_file = @ca_path
44
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
45
+ else
46
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
47
+ STDERR.puts("Warning: fetching over https without verifying server certificate")
48
+ end
49
+ else
50
+ STDERR.puts('Warning: trying to fetch HTTPS URL without OpenSSL support')
51
+ end
52
+ end
53
+
54
+ return http
55
+ end
56
+
57
+ # do a GET following redirects limit deep
58
+ def do_get(url, params, limit=5)
59
+ if limit == 0
60
+ return nil
61
+ end
62
+ begin
63
+ uri = URI.parse(url)
64
+ http = get_http_obj(uri)
65
+ resp = http.request_get(uri.request_uri, params)
66
+ rescue
67
+ nil
68
+ else
69
+ case resp
70
+ when Net::HTTPSuccess then [resp, URI.parse(url).to_s]
71
+ when Net::HTTPRedirection then do_get(resp["location"], params, limit-1)
72
+ else
73
+ STDERR.puts("ERROR, what to do with #{resp}")
74
+ nil
75
+ end
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,138 @@
1
+ require 'yadis/yadis'
2
+
3
+ class YadisServiceManager
4
+
5
+ attr_reader :starting_url, :yadis_url, :services, :session_key, :current
6
+
7
+ def initialize(starting_url, yadis_url, services)
8
+ @starting_url = starting_url
9
+ @yadis_url = yadis_url
10
+ @services = services
11
+ @current = nil
12
+ end
13
+
14
+ def next
15
+ @current = @services.shift
16
+ end
17
+
18
+ def for_url?(url)
19
+ url == @starting_url or url == @yadis_url
20
+ end
21
+
22
+ def started?
23
+ not @current.nil?
24
+ end
25
+
26
+ def length
27
+ @services.length
28
+ end
29
+
30
+ end
31
+
32
+ class Discovery
33
+
34
+ @@default_suffix = nil
35
+ @@prefix = '_yadis_services_'
36
+
37
+ def initialize(session, url, session_key_siffix=nil)
38
+ @session = session
39
+ @url = url
40
+ @session_key = @@prefix + (session_key_suffix or @@default_suffix)
41
+ end
42
+
43
+ def next_service(discover_block)
44
+ manager = self.get_manager
45
+ if manager and manager.length <= 0
46
+ self.destroy_manager
47
+ manager = nil
48
+ end
49
+
50
+ unless manager
51
+ begin
52
+ yadis_url, services = self.discover
53
+ rescue YADISParseError, YADISHTTPError
54
+ manager = nil
55
+ else
56
+ manager = self.create_manager(services, yadis_url)
57
+ end
58
+ end
59
+
60
+ if manager
61
+ service = manager.next
62
+ self.store_manager(manager)
63
+ else
64
+ service = nil
65
+ end
66
+
67
+ return service
68
+ end
69
+
70
+ def finish
71
+ manager = self.get_manager
72
+ return nil unless manager
73
+
74
+ service = manager.current
75
+ self.destroy_manager
76
+ return service
77
+ end
78
+
79
+ def get_manager
80
+ manager = @session[@session_key]
81
+
82
+ # make sure we've got the right manager here
83
+ if manager and manager.for_url?(@url)
84
+ return manager
85
+ end
86
+
87
+ return nil
88
+ end
89
+
90
+ def create_manager(services, yadis_url=nil)
91
+ if self.get_manager
92
+ raise ArgumentError, "There is already a manager for #{@url}"
93
+ end
94
+
95
+ if services.length > 0
96
+ manager = YadisServiceManager.new(@url, yadis_url, services)
97
+ self.store_manager(manager)
98
+ else
99
+ manager = nil
100
+ end
101
+
102
+ return manager
103
+ end
104
+
105
+ def destroy_manager
106
+ if self.get_manager
107
+ begin
108
+ @session.delete(@session_key)
109
+ rescue
110
+ # sometimes Hash like session objects don't have a delete
111
+ # method. We handle that case by assigning nil to the session[key]
112
+ @session[@session_key] = nil
113
+ end
114
+ end
115
+ end
116
+
117
+ def store_manager(manager)
118
+ @session[@session_key] = manager
119
+ end
120
+
121
+ # The filter argument is a Proc that will be used to call
122
+ # YADIS.filter_services. See the documentation for YADIS.filter_services
123
+ # for more information about writing filters.
124
+ def discover(filter=nil)
125
+ y = YADIS.new(@url)
126
+
127
+ # a default filter which sends through everything. you should
128
+ # probably consider writing a custom filter and passing it in.
129
+ unless filter
130
+ filter = lambda {|s| s}
131
+ end
132
+
133
+ return [y.url, y.filter_services(filter)]
134
+ end
135
+
136
+ end
137
+
138
+
data/lib/yadis/service.rb CHANGED
@@ -1,13 +1,14 @@
1
1
  # Class representing an XRD Service element.
2
2
  class ServiceEndpoint
3
3
 
4
- attr_accessor :service_types, :uri, :yadis_uri, :element, :yadis
4
+ attr_accessor :service_types, :uri, :yadis_uri, :element, :yadis, :canonical_id
5
5
 
6
6
  def initialize
7
7
  @service_types = []
8
8
  @uri = nil
9
9
  @yadis_uri = nil
10
10
  @element = nil
11
+ @canonical_id = nil
11
12
  end
12
13
 
13
14
  def match_type_uris(type_uris)
@@ -0,0 +1,24 @@
1
+ require 'rexml/document'
2
+
3
+ # Class representing an XRD Service element.
4
+ class ServiceEndpoint
5
+
6
+ attr_accessor :service_types, :uri, :yadis_uri, :element, :yadis
7
+
8
+ def initialize
9
+ @service_types = []
10
+ @uri = nil
11
+ @yadis_uri = nil
12
+ @element = nil
13
+ @yadis_uri = nil
14
+ end
15
+
16
+ def match_type_uris(type_uris)
17
+ type_uris.find_all {|t| @service_types.member?(t)}
18
+ end
19
+
20
+ def ==(other)
21
+ return self.instance_variables == other.instance_variables
22
+ end
23
+
24
+ end
data/lib/yadis/xrds.rb CHANGED
@@ -66,6 +66,14 @@ class XRDS
66
66
  REXML::XPath.each(xrd, 'xrdns:Service', @@namespaces) do |s|
67
67
  _create_services(s)
68
68
  end
69
+
70
+ REXML::XPath.each(xrd, 'xrdns:CanonicalID', @@namespaces) do |c|
71
+ canonical_id = c.text.strip
72
+ if canonical_id.length > 0
73
+ self.services.each {|s| s.canonical_id = canonical_id}
74
+ end
75
+ end
76
+
69
77
  end
70
78
 
71
79
 
@@ -0,0 +1,128 @@
1
+ require 'rexml/document'
2
+ require 'yadis/service'
3
+
4
+ # Class that handles XRDS parsing and XRD Service element extraction.
5
+
6
+ module XRDSUtil
7
+
8
+ @@default_namespace = 'xri://$xrd*($v*2.0)'
9
+ @@xrds_namespace = {'xrds' => 'xri://$xrds'}
10
+
11
+ def last_xrd(root_element)
12
+ REXML::XPath.match(root_element, '/xrds:XRDS/XRD',
13
+ @@xrds_namespace)[-1]
14
+ end
15
+
16
+ end
17
+
18
+ class XRDS
19
+
20
+ include XRDSUtil
21
+ attr_reader :xml
22
+
23
+ # Method for producing a valid XRDS object. Accepts an XML
24
+ # String. Returns an XRDS object on success, or nil on failure.
25
+ # Same as calling XRDS.new, but does not rails ArgumentErrors.
26
+ def XRDS.parse(xml)
27
+ begin
28
+ return new(xml)
29
+ rescue
30
+ return nil
31
+ end
32
+ end
33
+
34
+ # Create a new XRDS object. Raises ArgumentError if xml_text is
35
+ # malformed or invalid XRDS.
36
+ def initialize(xml_text)
37
+ parse_xml(xml_text)
38
+ end
39
+
40
+ def parse_xml(xml_text)
41
+ begin
42
+ xml = @xml = REXML::Document.new(xml_text)
43
+ rescue
44
+ raise ArgumentError, "Can't parse XRDS"
45
+ end
46
+
47
+ if xml.root.nil?
48
+ raise ArgumentError, "No document root"
49
+ end
50
+
51
+ xmlns = xml.root.attributes['xmlns']
52
+ if xmlns != @@default_namespace
53
+ raise ArgumentError, "Unknown XRID version #{xmlns.to_s}"
54
+ end
55
+
56
+ xrd = self.last_xrd(xml.root)
57
+ raise ArgumentError, "No XRD Elements found" if xrd.nil?
58
+
59
+ @services = {} # keyed by [service_priority, uri_priority]
60
+ xrd.elements.each('Service') {|s| _create_services(s)}
61
+ end
62
+
63
+
64
+ # Returns an Array of ServiceEndpoint objects, sorted by priority. Highest
65
+ # priority is at element 0.
66
+ def services
67
+ s = []
68
+
69
+ @services.keys.sort.each do |key|
70
+ services_list = @services[key].dup
71
+
72
+ # randomize services with the same priority
73
+ while services_list.length > 0
74
+ s << services_list.delete_at((rand * services_list.length).to_i)
75
+ end
76
+
77
+ end
78
+
79
+ return s
80
+ end
81
+
82
+ private
83
+
84
+ # create services objects
85
+ def _create_services(service_element)
86
+ service = ServiceEndpoint.new
87
+ service.element = service_element
88
+ service.uri = nil
89
+ service.service_types = []
90
+
91
+ service_element.elements.each('Type') do |t|
92
+ service.service_types << t.text.strip
93
+ end
94
+
95
+ sp = service_element.attributes['priority']
96
+ service_priority = sp ? sp.to_i : -1
97
+
98
+ if service.element.elements['URI']
99
+ service.element.elements.each('URI') do |uri|
100
+ _service = service.dup
101
+ _service.uri = uri.text.strip
102
+
103
+ up = uri.attributes['priority']
104
+ uri_priority = up ? up.to_i : -1
105
+ priority = [service_priority, uri_priority]
106
+
107
+ _add_service(priority, _service)
108
+ end
109
+
110
+ else
111
+ priority = [service_priority, -1]
112
+ _add_service(priority, service)
113
+
114
+ end
115
+
116
+ end
117
+
118
+ def _add_service(priority, service)
119
+ unless @services.has_key?(priority)
120
+ @services[priority] = []
121
+ end
122
+
123
+ # services with the same priority are appended to the list
124
+ @services[priority] << service
125
+ end
126
+
127
+ end
128
+
data/lib/yadis/xri.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'yadis/xrds'
2
+ require 'yadis/fetcher'
3
+
4
+ # The '(' is for cross-reference authorities, and hopefully has a matching ')'
5
+ # somewhere.
6
+ XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("]
7
+
8
+ module XRI
9
+
10
+ def XRI.identifier_scheme(identifier)
11
+ if identifier.match('^xri://') or XRI_AUTHORITIES.member?(identifier[0].chr)
12
+ return :xri
13
+ else
14
+ return :uri
15
+ end
16
+ end
17
+
18
+ # Transform an XRI reference to an IRI reference.
19
+ # Note this is not not idempotent, so do not apply this to an identifier more
20
+ # than once.
21
+ # XRI Syntax section 2.3.1
22
+ def XRI.to_iri_normal(xri)
23
+ iri = xri.dup
24
+ iri.insert(0, 'xri://') if not iri.match('^xri://')
25
+ return escape_for_iri(iri)
26
+ end
27
+
28
+ # Note this is not not idempotent, so do not apply this more than once.
29
+ # XRI Syntax section 2.3.2
30
+ def XRI.escape_for_iri(xri)
31
+ esc = xri.dup
32
+ # encode all %
33
+ esc.gsub!(/%/, '%25')
34
+ esc.gsub!(/\((.*?)\)/) { |xref_match|
35
+ xref_match.gsub(/[\/\?\#]/) { |char_match|
36
+ CGI::escape(char_match)
37
+ }
38
+ }
39
+ return esc
40
+ end
41
+
42
+ # Transform an XRI reference to a URI reference.
43
+ # Note this is not not idempotent, so do not apply this to an identifier more
44
+ # than once.
45
+ # XRI Syntax section 2.3.1
46
+ def XRI.to_uri_normal(xri)
47
+ return iri_to_uri(to_iri_normal(xri))
48
+ end
49
+
50
+ # RFC 3987 section 3.1
51
+ def XRI.iri_to_uri(iri)
52
+ uri = iri.dup
53
+ # for char in ucschar or iprivate
54
+ # convert each char to %HH%HH%HH (as many %HH as octets)
55
+ return uri
56
+ end
57
+
58
+ def provider_is_authoritative(provider_id, canonical_id)
59
+ lastbang = canonical_id.rindex('!')
60
+ return false unless lastbang
61
+ parent = canonical_id[0...lastbang]
62
+ return parent == provider_id
63
+ end
64
+
65
+ def root_authority(xri)
66
+ xri = xri[6..-1] if xri.index('xri://') == 0
67
+ authority = xri.split('/', 2)[0]
68
+ if authority[0].chr == '('
69
+ root = authority[0...authority.index(')')+1]
70
+ elsif XRI_AUTHORITIES.member?(authority[0].chr)
71
+ root = authority[0].chr
72
+ else
73
+ root = authority.split(/[!*]/)[0]
74
+ end
75
+
76
+ make_xri(root)
77
+ end
78
+
79
+
80
+ def make_xri(xri)
81
+ if xri.index('xri://') != 0
82
+ xri = 'xri://' + xri
83
+ end
84
+ return xri
85
+ end
86
+
87
+ end
@@ -0,0 +1,94 @@
1
+ require "cgi"
2
+ require "yadis/xri"
3
+ require "yadis/xrds"
4
+ require "yadis/fetcher"
5
+
6
+ module XRI
7
+
8
+ class XRIHTTPError < StandardError; end
9
+
10
+ class ProxyResolver
11
+
12
+ DEFAULT_PROXY = 'http://proxy.xri.net/'
13
+
14
+ def initialize(proxy_url=nil)
15
+ if proxy_url
16
+ @proxy_url = proxy_url
17
+ else
18
+ @proxy_url = DEFAULT_PROXY
19
+ end
20
+
21
+ @proxy_url += '/' unless @proxy_url.match('/$')
22
+ end
23
+
24
+ def query_url(xri, service_type=nil)
25
+ # URI normal form has a leading xri://, but we need to strip
26
+ # that off again for the QXRI. This is under discussion for
27
+ # XRI Resolution WD 11.
28
+ #
29
+ qxri = XRI.to_uri_normal(xri)[6..-1]
30
+ hxri = @proxy_url + qxri
31
+ args = {'_xrd_r' => 'application/xrds+xml'}
32
+ if service_type
33
+ args['_xrd_t'] = service_type
34
+ else
35
+ # don't perform service endpoint selection
36
+ args['_xrd_r'] += ';sep=false'
37
+ end
38
+
39
+ return XRI.append_args(hxri, args)
40
+ end
41
+
42
+ def query(xri, service_types)
43
+ # these can be query args or http headers, needn't be both.
44
+ # headers = {'Accept' => 'application/xrds+xml;sep=true'}
45
+ fetcher = NetHTTPFetcher.new
46
+ services = service_types.collect { |service_type|
47
+ url = self.query_url(xri, service_type)
48
+ response = fetcher.get(url)
49
+ raise XRIHTTPError, "Could not fetch #{xri}" if response.nil?
50
+ xrds = XRDS.new(response[1].body)
51
+ return xrds.services unless xrds.nil?
52
+ }
53
+ # TODO:
54
+ # * If we do get hits for multiple service_types, we're almost
55
+ # certainly going to have duplicated service entries and
56
+ # broken priority ordering.
57
+ services = services.inject([]) { |flatter, some_services|
58
+ flatter.concat(some_services) unless some_services.nil?
59
+ }
60
+ end
61
+ end
62
+
63
+ def XRI.urlencode(args)
64
+ a = []
65
+ args.each do |key, val|
66
+ a << (CGI::escape(key) + "=" + CGI::escape(val))
67
+ end
68
+ a.join("&")
69
+ end
70
+
71
+ def XRI.append_args(url, args)
72
+ return url if args.length == 0
73
+
74
+ # rstrip question marks
75
+ rstripped = url.dup
76
+ while rstripped[-1].chr == '?'
77
+ rstripped = rstripped[0...rstripped.length-1]
78
+ end
79
+
80
+ if rstripped.index('?')
81
+ sep = '&'
82
+ else
83
+ sep = '?'
84
+ end
85
+
86
+ return url + sep + XRI.urlencode(args)
87
+ end
88
+
89
+ end
90
+
91
+ # Example:
92
+ # r = XRI::ProxyResolver.new('http://proxy.xri.net/')
93
+ # j = r.query('=keturn', ['xri://+i-service*(+forwarding)*($v*1.0)'])
94
+ # Stderr.puts("the answer is #{j}")
@@ -0,0 +1,104 @@
1
+ require 'yadis/xrds'
2
+ require 'yadis/fetcher'
3
+ require 'yadis/parsehtml'
4
+
5
+ class YADISParseError < StandardError; end
6
+ class YADISHTTPError < StandardError; end
7
+
8
+ class YADIS
9
+
10
+ @@ca_path = nil
11
+ attr_accessor :uri, :xrds_uri, :xrds
12
+
13
+ # Discover services for a given URI. Please note that no normalization
14
+ # will be done to the passed in URI, it should be a textually
15
+ # valid URI string before calling discover.
16
+ #
17
+ # Returns nil if no XRDS was found, or a YADIS object on success. This
18
+ # method is essentially the same as YADIS.new, but does not raise any
19
+ # exceptions.
20
+ def YADIS.discover(uri)
21
+ return nil unless uri
22
+ begin
23
+ return YADIS.new(uri)
24
+ rescue
25
+ return nil
26
+ end
27
+ end
28
+
29
+ # Set the path to a certificate authority pem file, for verifying
30
+ # server certificates of HTTPS pages. If you are interested in verifying
31
+ # certs like the mozilla web browser, have a look at the files here:
32
+ #
33
+ # http://curl.haxx.se/docs/caextract.html
34
+ def YADIS.ca_path=(ca_path)
35
+ ca_path = ca_path.to_s
36
+ if File.exists?(ca_path)
37
+ @@ca_path = ca_path
38
+ else
39
+ raise ArgumentError, "#{ca_path} is not a valid file path"
40
+ end
41
+ end
42
+
43
+ # Discover services for a URI using the Yadis protocol. +uri+ should
44
+ # be a valid URI represented as a string. This method may raise
45
+ # YADISParseError in the case of an invalid or unparsable XRDS file,
46
+ # or YADISHTTPError is the URI cannot be fetched.
47
+ def initialize(uri)
48
+ http = NetHTTPFetcher.new
49
+ http.ca_path = @@ca_path if @@ca_path
50
+ headers = {'Accept' => 'application/xrds+xml'}
51
+
52
+ response = http.get(uri, headers)
53
+ raise YADISHTTPError, "Could not fetch #{uri}" if response.nil?
54
+
55
+ uri, resp_payload = response
56
+ xrds_uri = uri
57
+
58
+ header = resp_payload['x-xrds-location']
59
+ header = resp_payload['x-yadis-location'] if header.nil?
60
+
61
+ if header
62
+ xrds_uri = header
63
+ response = http.get(xrds_uri)
64
+ raise YADISHTTPError, "Could not fetch XRDS #{xrds_uri}" if response.nil?
65
+ resp_payload = response[1]
66
+ end
67
+
68
+ unless resp_payload['content-type'] == 'application/xrds+xml'
69
+ loc = html_yadis_location(resp_payload.body)
70
+ unless loc.nil?
71
+ xrds_uri, resp_payload = http.get(loc)
72
+ end
73
+ end
74
+
75
+ xrds = XRDS.parse(resp_payload.body)
76
+ raise YADISParseError, "Bad XRDS" if xrds.nil?
77
+
78
+ @uri = uri
79
+ @xrds_uri = xrds_uri
80
+ @xrds = xrds
81
+ end
82
+
83
+ # Returns an Array Service objects sorted by priority.
84
+ def services
85
+ @xrds.services.each {|s| s.yadis = self}
86
+ @xrds.services
87
+ end
88
+
89
+ # Returns a list of services, ordered by priority,
90
+ # that match the filter. filter is a Proc object that produces
91
+ # ServiceEnpoint objects, subclasses of ServiceEnpoint or nil.
92
+ # This method is useful for extracting several types of services while
93
+ # maintaining priority, for example you may write a filter Proc to extract
94
+ # OpenID and LID ServiceEnpoint objects.
95
+ def filter_services(filter)
96
+ # product a list of filtered ServiceEndpoint objects. filtered
97
+ # will contain a list of nil or ServiceEnpoint (subclasses) objects.
98
+ filtered = self.services.collect {|s| filter.call(s)}
99
+
100
+ # return all object in filtered that are not nil
101
+ return filtered.find_all {|s| s}
102
+ end
103
+
104
+ end
data/lib/yadis.rb CHANGED
@@ -4,3 +4,5 @@ require 'yadis/service'
4
4
  require 'yadis/parsehtml'
5
5
  require 'yadis/fetcher'
6
6
  require 'yadis/manager'
7
+ require 'yadis/xri'
8
+ require 'yadis/xrires'
data/lib/yadis.rb~ ADDED
@@ -0,0 +1 @@
1
+ require 'yadis/yadis'
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <XRDS ref="xri://=keturn">
3
+ <XRD xmlns:xrd="xri://$xrd*($v*2.0)">
4
+ <Query>*keturn</Query>
5
+ <Status code="100"/>
6
+ <Expires>2006-05-31T02:45:37.000Z</Expires>
7
+ <ProviderID>xri://=</ProviderID>
8
+ <LocalID priority="10">!2397.58EC.8F7D.D097</LocalID>
9
+ <CanonicalID priority="10">=!2397.58EC.8F7D.D097</CanonicalID>
10
+ <Service priority="10">
11
+ <Type/>
12
+ <Type>xri://+i-service*(+forwarding)*($v*1.0)</Type>
13
+ <ProviderID>xri://!!1003</ProviderID>
14
+ <URI priority="10">https://forwarding.godaddy.amsoftsystems.com</URI>
15
+ </Service>
16
+ <Service priority="10">
17
+ <Type>xri://+i-service*(+contact)*($v*1.0)</Type>
18
+ <ProviderID>xri://!!1003</ProviderID>
19
+ <Path>+contact</Path>
20
+ <MediaType/>
21
+ <MediaType>text/html</MediaType>
22
+ <URI priority="10">https://contact.godaddy.amsoftsystems.com</URI>
23
+ </Service>
24
+ <Service priority="10">
25
+ <Type>xri://+i-service*(+authn)*(+saml)*($v*1.0)</Type>
26
+ <ProviderID>xri://!!1003</ProviderID>
27
+ <Path>+login</Path>
28
+ <URI priority="10">https://isso.godaddy.amsoftsystems.com</URI>
29
+ </Service>
30
+ </XRD>
31
+ </XRDS>
32
+
data/test/test_xri.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'test/unit'
2
+ require 'yadis/xri'
3
+
4
+ class XriDiscoveryTestCase < Test::Unit::TestCase
5
+
6
+ def test_isXRI?
7
+ assert_equal(:xri, XRI.identifier_scheme('=john.smith'))
8
+ assert_equal(:xri, XRI.identifier_scheme('@smiths/john'))
9
+ assert_equal(:xri, XRI.identifier_scheme('xri://=john'))
10
+ assert_equal(:xri, XRI.identifier_scheme('@ootao*test1'))
11
+ assert_equal(:uri, XRI.identifier_scheme('smoker.myopenid.com'))
12
+ assert_equal(:uri, XRI.identifier_scheme('http://smoker.myopenid.com'))
13
+ assert_equal(:uri, XRI.identifier_scheme('https://smoker.myopenid.com'))
14
+ end
15
+ end
16
+
17
+ class XriEscapingTestCase < Test::Unit::TestCase
18
+ def test_escaping_percents
19
+ assert_equal('@example/abc%252Fd/ef',
20
+ XRI.escape_for_iri('@example/abc%2Fd/ef'))
21
+ end
22
+
23
+ def test_escaping_xref
24
+ # no escapes
25
+ assert_equal('@example/foo/(@bar)',
26
+ XRI.escape_for_iri('@example/foo/(@bar)'))
27
+ # escape slashes
28
+ assert_equal('@example/foo/(@bar%2Fbaz)',
29
+ XRI.escape_for_iri('@example/foo/(@bar/baz)'))
30
+ # escape query ? and fragment #
31
+ assert_equal('@example/foo/(@baz%3Fp=q%23r)?i=j#k',
32
+ XRI.escape_for_iri('@example/foo/(@baz?p=q#r)?i=j#k'))
33
+ end
34
+ end
35
+
36
+ class XriTransformationTestCase < Test::Unit::TestCase
37
+ def test_to_iri_normal
38
+ assert_equal('xri://@example', XRI.to_iri_normal('@example'))
39
+ end
40
+ # iri_to_url:
41
+ # various ucschar to hex
42
+ end
43
+
44
+ H = 'http://xri.example.com/'
45
+ # ST = 'http://openid.net/signon/1.2'
46
+ ST = 'xri://+i-service*(+forwarding)*($v*1.0)'
47
+ class ProxyQueryTestCase < Test::Unit::TestCase
48
+ def setup
49
+ @proxy = XRI::ProxyResolver.new(H)
50
+ end
51
+
52
+ def test_proxy_url
53
+ args_esc = "_xrd_r=application%2Fxrds%2Bxml&_xrd_t=#{CGI::escape(ST)}"
54
+ self.assert_equal(H + '=foo?' + args_esc, @proxy.query_url('=foo', ST))
55
+ self.assert_equal(H + '=foo/bar?baz&' + args_esc,
56
+ @proxy.query_url('=foo/bar?baz', ST))
57
+ self.assert_equal(H + '=foo/bar?baz=quux&' + args_esc,
58
+ @proxy.query_url('=foo/bar?baz=quux', ST))
59
+ self.assert_equal(H + '=foo/bar?mi=fa&so=la&' + args_esc,
60
+ @proxy.query_url('=foo/bar?mi=fa&so=la', ST))
61
+ # TODO:
62
+ # self.assert_equal(H + '=foo/bar??' + args_esc,
63
+ # @proxy.query_url('=foo/bar?', ST))
64
+ # self.assert_equal(H + '=foo/bar????' + args_esc,
65
+ # @proxy.query_url('=foo/bar???', ST))
66
+ end
67
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: ruby-yadis
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.2
7
- date: 2006-06-26 00:00:00 -07:00
6
+ version: 0.3.3
7
+ date: 2006-08-20 00:00:00 -07:00
8
8
  summary: A library for performing Yadis service discovery
9
9
  require_paths:
10
10
  - lib
@@ -31,29 +31,39 @@ files:
31
31
  - examples/openid.rb
32
32
  - lib/yadis.rb
33
33
  - lib/yadis
34
+ - lib/yadis.rb~
34
35
  - lib/yadis/parsehtml.rb
35
36
  - lib/yadis/xrds.rb
36
37
  - lib/yadis/yadis.rb
37
38
  - lib/yadis/fetcher.rb
38
39
  - lib/yadis/htmltokenizer.rb
39
40
  - lib/yadis/manager.rb
41
+ - lib/yadis/yadis.rb~
40
42
  - lib/yadis/service.rb
43
+ - lib/yadis/manager.rb~
44
+ - lib/yadis/service.rb~
45
+ - lib/yadis/xrds.rb~
46
+ - lib/yadis/fetcher.rb~
47
+ - lib/yadis/xri.rb
48
+ - lib/yadis/xrires.rb
41
49
  - test/test_parse.rb
42
50
  - test/data
43
51
  - test/test_discovery.rb
44
52
  - test/test_yadis.rb
45
53
  - test/test_xrds.rb
46
54
  - test/runtests.rb
55
+ - test/test_xri.rb
47
56
  - test/data/manifest.txt
48
57
  - test/data/brian.xrds
49
- - test/data/brian_priority.xrds
50
- - test/data/brian.multi.xrds
51
58
  - test/data/index.html
59
+ - test/data/brian.multi.xrds
60
+ - test/data/brian_priority.xrds
52
61
  - test/data/brian.multi_uri.xrds
53
- - test/data/index_yadis.html
54
62
  - test/data/index_xrds.html
63
+ - test/data/index_yadis.html
55
64
  - test/data/proxy-june1.xrds
56
65
  - test/data/weirdver.xrds
66
+ - test/data/keturn.xrds
57
67
  - test/data/brianellin.mylid.xrds
58
68
  - README
59
69
  - INSTALL