70
class _BufferedMakefileSocket(object):
72
def __init__(self, sock):
76
class _ReportingFileSocket(object):
78
def __init__(self, filesock, report_activity=None):
79
self.filesock = filesock
80
self._report_activity = report_activity
83
def read(self, size=1):
84
s = self.filesock.read(size)
85
self._report_activity(len(s), 'read')
89
# This should be readline(self, size=-1), but httplib in python 2.4 and
90
# 2.5 defines a SSLFile wrapper whose readline method lacks the size
91
# parameter. So until we drop support for 2.4 and 2.5 and since we
92
# don't *need* the size parameter we'll stay with readline(self)
94
s = self.filesock.readline()
95
self._report_activity(len(s), 'read')
98
def __getattr__(self, name):
99
return getattr(self.filesock, name)
102
class _ReportingSocket(object):
104
def __init__(self, sock, report_activity=None):
106
self._report_activity = report_activity
108
def send(self, s, *args):
109
self.sock.send(s, *args)
110
self._report_activity(len(s), 'write')
112
def sendall(self, s, *args):
113
self.sock.send(s, *args)
114
self._report_activity(len(s), 'write')
116
def recv(self, *args):
117
s = self.sock.recv(*args)
118
self._report_activity(len(s), 'read')
75
121
def makefile(self, mode='r', bufsize=-1):
76
return self.sock.makefile(mode, 65536)
122
# httplib creates a fileobject that doesn't do buffering, which
123
# makes fp.readline() very expensive because it only reads one byte
124
# at a time. So we wrap the socket in an object that forces
125
# sock.makefile to make a buffered file.
126
fsock = self.sock.makefile(mode, 65536)
127
# And wrap that into a reporting kind of fileobject
128
return _ReportingFileSocket(fsock, self._report_activity)
78
130
def __getattr__(self, name):
79
131
return getattr(self.sock, name)
96
148
# 8k chunks should be fine.
97
149
_discarded_buf_size = 8192
99
def __init__(self, sock, *args, **kwargs):
100
# httplib creates a fileobject that doesn't do buffering, which
101
# makes fp.readline() very expensive because it only reads one byte
102
# at a time. So we wrap the socket in an object that forces
103
# sock.makefile to make a buffered file.
104
sock = _BufferedMakefileSocket(sock)
105
httplib.HTTPResponse.__init__(self, sock, *args, **kwargs)
108
152
"""Begin to read the response from the server.
211
257
# Preserve our preciousss
214
# Let httplib.HTTPConnection do its housekeeping
260
# Let httplib.HTTPConnection do its housekeeping
216
262
# Restore our preciousss
265
def _wrap_socket_for_reporting(self, sock):
266
"""Wrap the socket before anybody use it."""
267
self.sock = _ReportingSocket(sock, self._report_activity)
220
270
class HTTPConnection(AbstractHTTPConnection, httplib.HTTPConnection):
222
272
# XXX: Needs refactoring at the caller level.
223
def __init__(self, host, port=None, proxied_host=None):
224
AbstractHTTPConnection.__init__(self)
273
def __init__(self, host, port=None, proxied_host=None,
274
report_activity=None):
275
AbstractHTTPConnection.__init__(self, report_activity=report_activity)
225
276
# Use strict=True since we don't support HTTP/0.9
226
277
httplib.HTTPConnection.__init__(self, host, port, strict=True)
227
278
self.proxied_host = proxied_host
248
300
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
250
302
def __init__(self, host, port=None, key_file=None, cert_file=None,
252
AbstractHTTPConnection.__init__(self)
304
report_activity=None):
305
AbstractHTTPConnection.__init__(self, report_activity=report_activity)
253
306
# Use strict=True since we don't support HTTP/0.9
254
307
httplib.HTTPSConnection.__init__(self, host, port,
255
308
key_file, cert_file, strict=True)
259
312
if 'http' in debug.debug_flags:
260
313
self._mutter_connect()
261
314
httplib.HTTPConnection.connect(self)
315
self._wrap_socket_for_reporting(self.sock)
262
316
if self.proxied_host is None:
263
317
self.connect_to_origin()
265
319
def connect_to_origin(self):
266
self.sock = _ssl_wrap_socket(self.sock, self.key_file, self.cert_file)
320
ssl_sock = _ssl_wrap_socket(self.sock, self.key_file, self.cert_file)
321
# Wrap the ssl socket before anybody use it
322
self._wrap_socket_for_reporting(ssl_sock)
269
325
class Request(urllib2.Request):
356
412
handler_order = 1000 # after all pre-processings
414
def __init__(self, report_activity=None):
415
self._report_activity = report_activity
358
417
def create_connection(self, request, http_connection_class):
359
418
host = request.get_host()
366
425
# request is made)
368
427
connection = http_connection_class(
369
host, proxied_host=request.proxied_host)
428
host, proxied_host=request.proxied_host,
429
report_activity=self._report_activity)
370
430
except httplib.InvalidURL, exception:
371
431
# There is only one occurrence of InvalidURL in httplib
372
432
raise errors.InvalidURL(request.get_full_url(),
638
698
connect.proxied_host, self.host))
640
700
connection.cleanup_pipe()
641
# Establish the connection encryption
701
# Establish the connection encryption
642
702
connection.connect_to_origin()
643
703
# Propagate the connection to the original request
644
704
request.connection = connection
889
949
preventively set authentication headers after the first
890
950
successful authentication.
892
This can be used for http and proxy, as well as for basic and
952
This can be used for http and proxy, as well as for basic, negotiate and
893
953
digest authentications.
895
955
This provides an unified interface for all authentication handlers
1089
1149
https_request = http_request # FIXME: Need test
1152
class NegotiateAuthHandler(AbstractAuthHandler):
1153
"""A authentication handler that handles WWW-Authenticate: Negotiate.
1155
At the moment this handler supports just Kerberos. In the future,
1156
NTLM support may also be added.
1161
def auth_match(self, header, auth):
1162
scheme = header.lower()
1163
if scheme != 'negotiate':
1165
self.update_auth(auth, 'scheme', scheme)
1166
resp = self._auth_match_kerberos(auth)
1169
# Optionally should try to authenticate using NTLM here
1170
self.update_auth(auth, 'negotiate_response', resp)
1173
def _auth_match_kerberos(self, auth):
1174
"""Try to create a GSSAPI response for authenticating against a host."""
1175
if not have_kerberos:
1177
ret, vc = kerberos.authGSSClientInit("HTTP@%(host)s" % auth)
1179
trace.warning('Unable to create GSSAPI context for %s: %d',
1182
ret = kerberos.authGSSClientStep(vc, "")
1184
trace.mutter('authGSSClientStep failed: %d', ret)
1186
return kerberos.authGSSClientResponse(vc)
1188
def build_auth_header(self, auth, request):
1189
return "Negotiate %s" % auth['negotiate_response']
1191
def auth_params_reusable(self, auth):
1192
# If the auth scheme is known, it means a previous
1193
# authentication was successful, all information is
1194
# available, no further checks are needed.
1195
return (auth.get('scheme', None) == 'negotiate' and
1196
auth.get('negotiate_response', None) is not None)
1092
1199
class BasicAuthHandler(AbstractAuthHandler):
1093
1200
"""A custom basic authentication handler."""
1314
1421
"""Custom proxy basic authentication handler"""
1424
class HTTPNegotiateAuthHandler(NegotiateAuthHandler, HTTPAuthHandler):
1425
"""Custom http negotiate authentication handler"""
1428
class ProxyNegotiateAuthHandler(NegotiateAuthHandler, ProxyAuthHandler):
1429
"""Custom proxy negotiate authentication handler"""
1317
1432
class HTTPErrorProcessor(urllib2.HTTPErrorProcessor):
1318
1433
"""Process HTTP error responses.
1370
1485
def __init__(self,
1371
1486
connection=ConnectionHandler,
1372
1487
redirect=HTTPRedirectHandler,
1373
error=HTTPErrorProcessor,):
1374
self._opener = urllib2.build_opener( \
1375
connection, redirect, error,
1488
error=HTTPErrorProcessor,
1489
report_activity=None):
1490
self._opener = urllib2.build_opener(
1491
connection(report_activity=report_activity),
1376
1493
ProxyHandler(),
1377
1494
HTTPBasicAuthHandler(),
1378
1495
HTTPDigestAuthHandler(),
1496
HTTPNegotiateAuthHandler(),
1379
1497
ProxyBasicAuthHandler(),
1380
1498
ProxyDigestAuthHandler(),
1499
ProxyNegotiateAuthHandler(),
1383
1502
HTTPDefaultErrorHandler,