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

Source Code for Module openid.yadis.discover

  1  # -*- test-case-name: openid.test.test_yadis_discover -*- 
  2  __all__ = ['discover', 'DiscoveryResult', 'DiscoveryFailure'] 
  3   
  4  from cStringIO import StringIO 
  5   
  6  from openid import fetchers 
  7   
  8  from openid.yadis.constants import \ 
  9       YADIS_HEADER_NAME, YADIS_CONTENT_TYPE, YADIS_ACCEPT_HEADER 
 10  from openid.yadis.parsehtml import MetaNotFound, findHTMLMeta 
 11   
12 -class DiscoveryFailure(Exception):
13 """Raised when a YADIS protocol error occurs in the discovery process""" 14 identity_url = None 15
16 - def __init__(self, message, http_response):
17 Exception.__init__(self, message) 18 self.http_response = http_response
19
20 -class DiscoveryResult(object):
21 """Contains the result of performing Yadis discovery on a URI""" 22 23 # The URI that was passed to the fetcher 24 request_uri = None 25 26 # The result of following redirects from the request_uri 27 normalized_uri = None 28 29 # The URI from which the response text was returned (set to 30 # None if there was no XRDS document found) 31 xrds_uri = None 32 33 # The content-type returned with the response_text 34 content_type = None 35 36 # The document returned from the xrds_uri 37 response_text = None 38
39 - def __init__(self, request_uri):
40 """Initialize the state of the object 41 42 sets all attributes to None except the request_uri 43 """ 44 self.request_uri = request_uri
45
46 - def usedYadisLocation(self):
47 """Was the Yadis protocol's indirection used?""" 48 return self.normalized_uri != self.xrds_uri
49
50 - def isXRDS(self):
51 """Is the response text supposed to be an XRDS document?""" 52 return (self.usedYadisLocation() or 53 self.content_type == YADIS_CONTENT_TYPE)
54
55 -def discover(uri):
56 """Discover services for a given URI. 57 58 @param uri: The identity URI as a well-formed http or https 59 URI. The well-formedness and the protocol are not checked, but 60 the results of this function are undefined if those properties 61 do not hold. 62 63 @return: DiscoveryResult object 64 65 @raises Exception: Any exception that can be raised by fetching a URL with 66 the given fetcher. 67 """ 68 result = DiscoveryResult(uri) 69 resp = fetchers.fetch(uri, headers={'Accept': YADIS_ACCEPT_HEADER}) 70 if resp.status != 200: 71 raise DiscoveryFailure( 72 'HTTP Response status from identity URL host is not 200. ' 73 'Got status %r' % (resp.status,), resp) 74 75 # Note the URL after following redirects 76 result.normalized_uri = resp.final_url 77 78 # Attempt to find out where to go to discover the document 79 # or if we already have it 80 result.content_type = resp.headers.get('content-type') 81 82 result.xrds_uri = whereIsYadis(resp) 83 84 if result.xrds_uri and result.usedYadisLocation(): 85 resp = fetchers.fetch(result.xrds_uri) 86 if resp.status != 200: 87 exc = DiscoveryFailure( 88 'HTTP Response status from Yadis host is not 200. ' 89 'Got status %r' % (resp.status,), resp) 90 exc.identity_url = result.normalized_uri 91 raise exc 92 result.content_type = resp.headers.get('content-type') 93 94 result.response_text = resp.body 95 return result
96 97 98
99 -def whereIsYadis(resp):
100 """Given a HTTPResponse, return the location of the Yadis document. 101 102 May be the URL just retrieved, another URL, or None, if I can't 103 find any. 104 105 [non-blocking] 106 107 @returns: str or None 108 """ 109 # Attempt to find out where to go to discover the document 110 # or if we already have it 111 content_type = resp.headers.get('content-type') 112 113 # According to the spec, the content-type header must be an exact 114 # match, or else we have to look for an indirection. 115 if (content_type and 116 content_type.split(';', 1)[0].lower() == YADIS_CONTENT_TYPE): 117 return resp.final_url 118 else: 119 # Try the header 120 yadis_loc = resp.headers.get(YADIS_HEADER_NAME.lower()) 121 122 if not yadis_loc: 123 # Parse as HTML if the header is missing. 124 # 125 # XXX: do we want to do something with content-type, like 126 # have a whitelist or a blacklist (for detecting that it's 127 # HTML)? 128 try: 129 yadis_loc = findHTMLMeta(StringIO(resp.body)) 130 except MetaNotFound: 131 pass 132 133 return yadis_loc
134