45
48
_opener_class = Opener
47
def __init__(self, base, from_transport=None):
48
"""Set the base path where files will be stored."""
49
if from_transport is not None:
50
super(HttpTransport_urllib, self).__init__(base, from_transport)
51
self._connection = from_transport._connection
52
self._auth = from_transport._auth
53
self._proxy_auth = from_transport._proxy_auth
55
self._opener = from_transport._opener
50
def __init__(self, base, _from_transport=None):
51
super(HttpTransport_urllib, self).__init__(
52
base, _from_transport=_from_transport)
53
if _from_transport is not None:
54
self._opener = _from_transport._opener
57
# urllib2 will be confused if it find authentication
58
# info in the urls. So we handle them separatly.
59
# Note: we don't need to when cloning because it was
61
clean_base, user, password = extract_credentials(base)
62
super(HttpTransport_urllib, self).__init__(clean_base,
64
self._connection = None
65
56
self._opener = self._opener_class()
67
authuri = extract_authentication_uri(self._real_abspath(self._path))
68
self._auth = {'user': user, 'password': password,
58
def _remote_path(self, relpath):
59
"""Produce absolute path, adjusting protocol."""
60
relative = urlutils.unescape(relpath).encode('utf-8')
61
path = self._combine_paths(self._path, relative)
62
# urllib2 will be confused if it find authentication
63
# info (user, password) in the urls. So we handle them separatly.
64
return self._unsplit_url(self._unqualified_scheme,
65
None, None, self._host, self._port, path)
67
def _perform(self, request):
68
"""Send the request to the server and handles common errors.
70
:returns: urllib2 Response object
72
connection = self._get_connection()
73
if connection is not None:
74
# Give back shared info
75
request.connection = connection
76
(auth, proxy_auth) = self._get_credentials()
78
# First request, intialize credentials
80
password = self._password
81
authuri = self._remote_path('.')
82
auth = {'user': user, 'password': password, 'authuri': authuri}
70
84
if user and password is not None: # '' is a valid password
71
85
# Make the (user, password) available to urllib2
72
86
# We default to a realm of None to catch them all.
73
87
self._opener.password_manager.add_password(None, authuri,
77
def _perform(self, request):
78
"""Send the request to the server and handles common errors.
80
:returns: urllib2 Response object
82
if self._connection is not None:
83
# Give back shared info
84
request.connection = self._connection
85
90
# Ensure authentication info is provided
86
request.auth = self._auth
87
request.proxy_auth = self._proxy_auth
92
request.proxy_auth = proxy_auth
89
94
mutter('%s: [%s]' % (request.method, request.get_full_url()))
90
95
if self._debuglevel > 0:
91
96
print 'perform: %s base: %s, url: %s' % (request.method, self.base,
92
97
request.get_full_url())
93
98
response = self._opener.open(request)
94
if self._connection is None:
95
# Acquire connection when the first request is able
96
# to connect to the server
97
self._connection = request.connection
98
# Always get auth parameters, they may change
99
self._auth = request.auth
100
self._proxy_auth = request.proxy_auth
99
if self._get_connection() is not request.connection:
100
# First connection or reconnection
101
self._set_connection(request.connection,
102
(request.auth, request.proxy_auth))
104
# http may change the credentials while keeping the
106
self._update_credentials((request.auth, request.proxy_auth))
102
108
code = response.code
103
109
if request.follow_redirections is False \
134
140
code = response.code
135
141
if code == 404: # not found
136
self._connection.fake_close()
142
self._get_connection().fake_close()
137
143
raise errors.NoSuchFile(abspath)
139
145
data = handle_response(abspath, code, response.headers, response)
140
146
# Close response to free the httplib.HTTPConnection pipeline
141
self._connection.fake_close()
147
self._get_connection().fake_close()
142
148
return code, data
144
150
def _post(self, body_bytes):
145
abspath = self._real_abspath('.bzr/smart')
151
abspath = self._remote_path('.bzr/smart')
146
152
response = self._perform(Request('POST', abspath, body_bytes))
147
153
code = response.code
148
154
data = handle_response(abspath, code, response.headers, response)
149
155
# Close response to free the httplib.HTTPConnection pipeline
150
self._connection.fake_close()
156
self._get_connection().fake_close()
151
157
return code, data
153
159
def should_cache(self):