123
123
# connect to the http server until the first request (which had
124
124
# just called us).
125
125
connection = pycurl.Curl()
126
self._set_connection(connection, None)
126
# First request, initialize credentials.
127
auth = self._create_auth()
128
# Proxy handling is out of reach, so we punt
129
self._set_connection(connection, auth)
127
130
return connection
129
132
def has(self, relpath):
209
212
return code, data
214
# The parent class use 0 to minimize the requests, but since we can't
215
# exploit the results as soon as they are received (pycurl limitation) we'd
216
# better issue more requests and provide a more responsive UI do the cost
217
# of more latency costs.
218
# If you modify this, think about modifying the comment in http/__init__.py
220
_get_max_size = 4 * 1024 * 1024
211
222
def _get_ranged(self, relpath, offsets, tail_amount):
212
223
"""Make a request for just part of the file."""
213
224
curl = self._get_curl()
224
235
code = curl.getinfo(pycurl.HTTP_CODE)
225
# mutter('header:\n%r', header.getvalue())
226
headers = _extract_headers(header.getvalue(), abspath)
227
# handle_response will raise NoSuchFile, etc based on the response code
228
return code, response.handle_response(abspath, code, headers, data)
237
if code == 404: # not found
238
raise errors.NoSuchFile(abspath)
239
elif code in (400, 416):
240
# We don't know which, but one of the ranges we specified was
242
raise errors.InvalidHttpRange(abspath, range_header,
243
'Server return code %d'
244
% curl.getinfo(pycurl.HTTP_CODE))
245
msg = self._parse_headers(header)
246
return code, response.handle_response(abspath, code, msg, data)
248
def _parse_headers(self, status_and_headers):
249
"""Transform the headers provided by curl into an HTTPMessage"""
250
status_and_headers.seek(0)
252
status_and_headers.readline()
253
msg = httplib.HTTPMessage(status_and_headers)
230
256
def _post(self, body_bytes):
231
257
fake_file = StringIO(body_bytes)
242
268
self._curl_perform(curl, header, ['Expect: '])
244
270
code = curl.getinfo(pycurl.HTTP_CODE)
245
headers = _extract_headers(header.getvalue(), abspath)
246
return code, response.handle_response(abspath, code, headers, data)
271
msg = self._parse_headers(header)
272
return code, response.handle_response(abspath, code, msg, data)
248
274
def _raise_curl_http_error(self, curl, info=None):
249
275
code = curl.getinfo(pycurl.HTTP_CODE)
272
298
curl.setopt(pycurl.USERAGENT, ua_str)
273
299
if self.cabundle:
274
300
curl.setopt(pycurl.CAINFO, self.cabundle)
301
# Set accepted auth methods
302
curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_ANY)
303
curl.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_ANY)
304
auth = self._get_credentials()
305
user = auth.get('user', None)
306
password = auth.get('password', None)
309
userpass = user + ':'
310
if password is not None: # '' is a valid password
312
curl.setopt(pycurl.USERPWD, userpass)
276
314
def _curl_perform(self, curl, header, more_headers=[]):
277
315
"""Perform curl operation and translate exceptions."""
297
335
raise errors.ConnectionError(
298
336
'curl connection error (%s)\non %s' % (e[1], url))
299
337
elif e[0] == CURLE_PARTIAL_FILE:
300
# Pycurl itself has detected a short read. We do
301
# not have all the information for the
302
# ShortReadvError, but that should be enough
338
# Pycurl itself has detected a short read. We do not have all
339
# the information for the ShortReadvError, but that should be
303
341
raise errors.ShortReadvError(url,
304
342
offset='unknown', length='unknown',
305
343
actual='unknown',
306
344
extra='Server aborted the request')
307
# jam 20060713 The code didn't use to re-raise the exception here,
308
# but that seemed bogus
310
346
code = curl.getinfo(pycurl.HTTP_CODE)
311
347
if code in (301, 302, 303, 307):
312
348
url = curl.getinfo(pycurl.EFFECTIVE_URL)
313
headers = _extract_headers(header.getvalue(), url)
314
redirected_to = headers['Location']
349
msg = self._parse_headers(header)
350
redirected_to = msg.getheader('location')
315
351
raise errors.RedirectRequested(url,
317
353
is_permanent=(code == 301),