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 @raises DiscoveryFailure: When the HTTP response does not have a 200 code. 68 """ 69 result = DiscoveryResult(uri) 70 resp = fetchers.fetch(uri, headers={'Accept': YADIS_ACCEPT_HEADER}) 71 if resp.status not in (200, 206): 72 raise DiscoveryFailure( 73 'HTTP Response status from identity URL host is not 200. ' 74 'Got status %r' % (resp.status,), resp) 75 76 # Note the URL after following redirects 77 result.normalized_uri = resp.final_url 78 79 # Attempt to find out where to go to discover the document 80 # or if we already have it 81 result.content_type = resp.headers.get('content-type') 82 83 result.xrds_uri = whereIsYadis(resp) 84 85 if result.xrds_uri and result.usedYadisLocation(): 86 resp = fetchers.fetch(result.xrds_uri) 87 if resp.status not in (200, 206): 88 exc = DiscoveryFailure( 89 'HTTP Response status from Yadis host is not 200. ' 90 'Got status %r' % (resp.status,), resp) 91 exc.identity_url = result.normalized_uri 92 raise exc 93 result.content_type = resp.headers.get('content-type') 94 95 result.response_text = resp.body 96 return result
97 98 99
100 -def whereIsYadis(resp):
101 """Given a HTTPResponse, return the location of the Yadis document. 102 103 May be the URL just retrieved, another URL, or None, if I can't 104 find any. 105 106 [non-blocking] 107 108 @returns: str or None 109 """ 110 # Attempt to find out where to go to discover the document 111 # or if we already have it 112 content_type = resp.headers.get('content-type') 113 114 # According to the spec, the content-type header must be an exact 115 # match, or else we have to look for an indirection. 116 if (content_type and 117 content_type.split(';', 1)[0].lower() == YADIS_CONTENT_TYPE): 118 return resp.final_url 119 else: 120 # Try the header 121 yadis_loc = resp.headers.get(YADIS_HEADER_NAME.lower()) 122 123 if not yadis_loc: 124 # Parse as HTML if the header is missing. 125 # 126 # XXX: do we want to do something with content-type, like 127 # have a whitelist or a blacklist (for detecting that it's 128 # HTML)? 129 try: 130 yadis_loc = findHTMLMeta(StringIO(resp.body)) 131 except MetaNotFound: 132 pass 133 134 return yadis_loc
135