Tres Seaver
2011-04-05 1d896cb7da0c7061887c6e451e85caff612b1b34
commit | author | age
d85ba6 1 from paste.httpheaders import REQUEST_METHOD
CM 2 from paste.httpheaders import CONTENT_TYPE
0dd808 3 from paste.httpheaders import USER_AGENT
d85ba6 4
1d896c 5 from zope.interface import directlyProvides
cb5426 6 from repoze.who.interfaces import IRequestClassifier
CM 7 from repoze.who.interfaces import IChallengeDecider
d85ba6 8
c51195 9 _DAV_METHODS = (
CM 10     'OPTIONS',
11     'PROPFIND',
12     'PROPPATCH',
13     'MKCOL',
14     'LOCK',
15     'UNLOCK',
16     'TRACE',
17     'DELETE',
18     'COPY',
19     'MOVE'
20     )
d85ba6 21
c51195 22 _DAV_USERAGENTS = (
CM 23     'Microsoft Data Access Internet Publishing Provider',
24     'WebDrive',
25     'Zope External Editor',
26     'WebDAVFS',
27     'Goliath',
28     'neon',
29     'davlib',
30     'wsAPI',
31     'Microsoft-WebDAV'
32     )
d85ba6 33
c51195 34 def default_request_classifier(environ):
CM 35     """ Returns one of the classifiers 'dav', 'xmlpost', or 'browser',
36     depending on the imperative logic below"""
37     request_method = REQUEST_METHOD(environ)
38     if request_method in _DAV_METHODS:
39         return 'dav'
40     useragent = USER_AGENT(environ)
41     if useragent:
42         for agent in _DAV_USERAGENTS:
43             if useragent.find(agent) != -1:
44                 return 'dav'
45     if request_method == 'POST':
6b7b34 46         if CONTENT_TYPE(environ).lower().startswith('text/xml'):
c51195 47             return 'xmlpost'
CM 48     return 'browser'
1d896c 49 directlyProvides(default_request_classifier, IRequestClassifier)
d85ba6 50
c51195 51 def default_challenge_decider(environ, status, headers):
79a95b 52     return status.startswith('401 ')
1d896c 53 directlyProvides(default_challenge_decider, IChallengeDecider)
0dd808 54
TS 55 def passthrough_challenge_decider(environ, status, headers):
56     """ Don't challenge for pre-challenged responses.
57
58     o Assume responsese with 'WWW-Authenticate' or an HTML content type
59       are pre-challenged.
60     """
61     if not status.startswith('401 '):
62         return False
63     h_dict = dict(headers)
64     if 'WWW-Authenticate' in h_dict:
65         return False
66     ct = h_dict.get('Content-Type')
67     if ct is not None:
68         return not ct.startswith('text/html')
69     return True
1d896c 70 directlyProvides(passthrough_challenge_decider, IChallengeDecider)