Package openid :: Package yadis :: Module xrires
[frames] | no frames]

Source Code for Module openid.yadis.xrires

  1  # -*- test-case-name: openid.test.test_xrires -*- 
  2  """XRI resolution. 
  3  """ 
  4   
  5  from urllib import urlencode 
  6  from openid import fetchers 
  7  from openid.yadis import etxrd 
  8  from openid.yadis.xri import toURINormal 
  9  from openid.yadis.services import iterServices 
 10   
 11  DEFAULT_PROXY = 'http://proxy.xri.net/' 
 12   
13 -class ProxyResolver(object):
14 """Python interface to a remote XRI proxy resolver. 15 """
16 - def __init__(self, proxy_url=DEFAULT_PROXY):
17 self.proxy_url = proxy_url
18 19
20 - def queryURL(self, xri, service_type=None):
21 """Build a URL to query the proxy resolver. 22 23 @param xri: An XRI to resolve. 24 @type xri: unicode 25 26 @param service_type: The service type to resolve, if you desire 27 service endpoint selection. A service type is a URI. 28 @type service_type: str 29 30 @returns: a URL 31 @returntype: str 32 """ 33 # Trim off the xri:// prefix. The proxy resolver didn't accept it 34 # when this code was written, but that may (or may not) change for 35 # XRI Resolution 2.0 Working Draft 11. 36 qxri = toURINormal(xri)[6:] 37 hxri = self.proxy_url + qxri 38 args = { 39 # XXX: If the proxy resolver will ensure that it doesn't return 40 # bogus CanonicalIDs (as per Steve's message of 15 Aug 2006 41 # 11:13:42), then we could ask for application/xrd+xml instead, 42 # which would give us a bit less to process. 43 '_xrd_r': 'application/xrds+xml', 44 } 45 if service_type: 46 args['_xrd_t'] = service_type 47 else: 48 # Don't perform service endpoint selection. 49 args['_xrd_r'] += ';sep=false' 50 query = _appendArgs(hxri, args) 51 return query
52 53
54 - def query(self, xri, service_types):
55 """Resolve some services for an XRI. 56 57 Note: I don't implement any service endpoint selection beyond what 58 the resolver I'm querying does, so the Services I return may well 59 include Services that were not of the types you asked for. 60 61 May raise fetchers.HTTPFetchingError or L{etxrd.XRDSError} if 62 the fetching or parsing don't go so well. 63 64 @param xri: An XRI to resolve. 65 @type xri: unicode 66 67 @param service_types: A list of services types to query for. Service 68 types are URIs. 69 @type service_types: list of str 70 71 @returns: tuple of (CanonicalID, Service elements) 72 @returntype: (unicode, list of C{ElementTree.Element}s) 73 """ 74 # FIXME: No test coverage! 75 services = [] 76 # Make a seperate request to the proxy resolver for each service 77 # type, as, if it is following Refs, it could return a different 78 # XRDS for each. 79 80 canonicalID = None 81 82 for service_type in service_types: 83 url = self.queryURL(xri, service_type) 84 response = fetchers.fetch(url) 85 if response.status not in (200, 206): 86 # XXX: sucks to fail silently. 87 # print "response not OK:", response 88 continue 89 et = etxrd.parseXRDS(response.body) 90 canonicalID = etxrd.getCanonicalID(xri, et) 91 some_services = list(iterServices(et)) 92 services.extend(some_services) 93 # TODO: 94 # * If we do get hits for multiple service_types, we're almost 95 # certainly going to have duplicated service entries and 96 # broken priority ordering. 97 return canonicalID, services
98 99
100 -def _appendArgs(url, args):
101 """Append some arguments to an HTTP query. 102 """ 103 # to be merged with oidutil.appendArgs when we combine the projects. 104 if hasattr(args, 'items'): 105 args = args.items() 106 args.sort() 107 108 if len(args) == 0: 109 return url 110 111 # According to XRI Resolution section "QXRI query parameters": 112 # 113 # """If the original QXRI had a null query component (only a leading 114 # question mark), or a query component consisting of only question 115 # marks, one additional leading question mark MUST be added when 116 # adding any XRI resolution parameters.""" 117 118 if '?' in url.rstrip('?'): 119 sep = '&' 120 else: 121 sep = '?' 122 123 return '%s%s%s' % (url, sep, urlencode(args))
124