~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/_pycurl.py

  • Committer: Benoît Pierre
  • Date: 2009-02-24 00:25:32 UTC
  • mfrom: (4035 +trunk)
  • mto: (4056.1.1 trunk2)
  • mto: This revision was merged to the branch mainline in revision 4058.
  • Revision ID: benoit.pierre@gmail.com-20090224002532-i2f64ou15pa7if2y
Merge with upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
59
59
try:
60
60
    # see if we can actually initialize PyCurl - sometimes it will load but
61
61
    # fail to start up due to this bug:
62
 
    #  
 
62
    #
63
63
    #   32. (At least on Windows) If libcurl is built with c-ares and there's
64
64
    #   no DNS server configured in the system, the ares_init() call fails and
65
65
    #   thus curl_easy_init() fails as well. This causes weird effects for
86
86
    """
87
87
    return pycurl.__dict__.get(symbol, default)
88
88
 
89
 
CURLE_SSL_CACERT_BADFILE = _get_pycurl_errcode('E_SSL_CACERT_BADFILE', 77)
90
89
CURLE_COULDNT_CONNECT = _get_pycurl_errcode('E_COULDNT_CONNECT', 7)
91
90
CURLE_COULDNT_RESOLVE_HOST = _get_pycurl_errcode('E_COULDNT_RESOLVE_HOST', 6)
92
91
CURLE_COULDNT_RESOLVE_PROXY = _get_pycurl_errcode('E_COULDNT_RESOLVE_PROXY', 5)
93
92
CURLE_GOT_NOTHING = _get_pycurl_errcode('E_GOT_NOTHING', 52)
94
93
CURLE_PARTIAL_FILE = _get_pycurl_errcode('E_PARTIAL_FILE', 18)
95
94
CURLE_SEND_ERROR = _get_pycurl_errcode('E_SEND_ERROR', 55)
 
95
CURLE_SSL_CACERT = _get_pycurl_errcode('E_SSL_CACERT', 60)
 
96
CURLE_SSL_CACERT_BADFILE = _get_pycurl_errcode('E_SSL_CACERT_BADFILE', 77)
96
97
 
97
98
 
98
99
class PyCurlTransport(HttpTransportBase):
105
106
    """
106
107
 
107
108
    def __init__(self, base, _from_transport=None):
108
 
        super(PyCurlTransport, self).__init__(base,
 
109
        super(PyCurlTransport, self).__init__(base, 'pycurl',
109
110
                                              _from_transport=_from_transport)
110
 
        if base.startswith('https'):
 
111
        if self._unqualified_scheme == 'https':
111
112
            # Check availability of https into pycurl supported
112
113
            # protocols
113
114
            supported = pycurl.version_info()[8]
179
180
 
180
181
        :param curl: The curl object to place the request on
181
182
        :param relpath: The relative path that we want to get
182
 
        :return: (abspath, data, header) 
 
183
        :return: (abspath, data, header)
183
184
                 abspath: full url
184
185
                 data: file that will be filled with the body
185
186
                 header: file that will be filled with the headers
214
215
 
215
216
    # The parent class use 0 to minimize the requests, but since we can't
216
217
    # exploit the results as soon as they are received (pycurl limitation) we'd
217
 
    # better issue more requests and provide a more responsive UI do the cost
218
 
    # of more latency costs.
 
218
    # better issue more requests and provide a more responsive UI incurring
 
219
    # more latency costs.
219
220
    # If you modify this, think about modifying the comment in http/__init__.py
220
221
    # too.
221
222
    _get_max_size = 4 * 1024 * 1024
286
287
        msg = self._parse_headers(header)
287
288
        return code, response.handle_response(abspath, code, msg, data)
288
289
 
 
290
 
289
291
    def _raise_curl_http_error(self, curl, info=None):
290
292
        code = curl.getinfo(pycurl.HTTP_CODE)
291
293
        url = curl.getinfo(pycurl.EFFECTIVE_URL)
303
305
            raise errors.InvalidHttpResponse(
304
306
                url, 'Unable to handle http code %d%s' % (code,msg))
305
307
 
 
308
    def _debug_cb(self, kind, text):
 
309
        if kind in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN,
 
310
                    pycurl.INFOTYPE_SSL_DATA_IN):
 
311
            self._report_activity(len(text), 'read')
 
312
            if (kind == pycurl.INFOTYPE_HEADER_IN
 
313
                and 'http' in debug.debug_flags):
 
314
                mutter('< %s' % text)
 
315
        elif kind in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT,
 
316
                      pycurl.INFOTYPE_SSL_DATA_OUT):
 
317
            self._report_activity(len(text), 'write')
 
318
            if (kind == pycurl.INFOTYPE_HEADER_OUT
 
319
                and 'http' in debug.debug_flags):
 
320
                mutter('> %s' % text)
 
321
        elif kind == pycurl.INFOTYPE_TEXT and 'http' in debug.debug_flags:
 
322
            mutter('* %s' % text)
 
323
 
306
324
    def _set_curl_options(self, curl):
307
325
        """Set options for all requests"""
308
 
        if 'http' in debug.debug_flags:
309
 
            curl.setopt(pycurl.VERBOSE, 1)
310
 
            # pycurl doesn't implement the CURLOPT_STDERR option, so we can't
311
 
            # do : curl.setopt(pycurl.STDERR, trace._trace_file)
312
 
 
313
326
        ua_str = 'bzr/%s (pycurl: %s)' % (bzrlib.__version__, pycurl.version)
314
327
        curl.setopt(pycurl.USERAGENT, ua_str)
 
328
        curl.setopt(pycurl.VERBOSE, 1)
 
329
        curl.setopt(pycurl.DEBUGFUNCTION, self._debug_cb)
315
330
        if self.cabundle:
316
331
            curl.setopt(pycurl.CAINFO, self.cabundle)
317
332
        # Set accepted auth methods
343
358
            url = curl.getinfo(pycurl.EFFECTIVE_URL)
344
359
            mutter('got pycurl error: %s, %s, %s, url: %s ',
345
360
                    e[0], e[1], e, url)
346
 
            if e[0] in (CURLE_SSL_CACERT_BADFILE,
347
 
                        CURLE_COULDNT_RESOLVE_HOST,
 
361
            if e[0] in (CURLE_COULDNT_RESOLVE_HOST,
 
362
                        CURLE_COULDNT_RESOLVE_PROXY,
348
363
                        CURLE_COULDNT_CONNECT,
349
364
                        CURLE_GOT_NOTHING,
350
 
                        CURLE_COULDNT_RESOLVE_PROXY,):
 
365
                        CURLE_SSL_CACERT,
 
366
                        CURLE_SSL_CACERT_BADFILE,
 
367
                        ):
351
368
                raise errors.ConnectionError(
352
369
                    'curl connection error (%s)\non %s' % (e[1], url))
353
370
            elif e[0] == CURLE_PARTIAL_FILE:
366
383
            redirected_to = msg.getheader('location')
367
384
            raise errors.RedirectRequested(url,
368
385
                                           redirected_to,
369
 
                                           is_permanent=(code == 301),
370
 
                                           qual_proto=self._scheme)
 
386
                                           is_permanent=(code == 301))
371
387
 
372
388
 
373
389
def get_test_permutations():
374
390
    """Return the permutations to be used in testing."""
375
 
    from bzrlib.tests.http_server import HttpServer_PyCurl
376
 
    return [(PyCurlTransport, HttpServer_PyCurl),
377
 
            ]
 
391
    from bzrlib import tests
 
392
    from bzrlib.tests import http_server
 
393
    permutations = [(PyCurlTransport, http_server.HttpServer_PyCurl),]
 
394
    if tests.HTTPSServerFeature.available():
 
395
        from bzrlib.tests import (
 
396
            https_server,
 
397
            ssl_certs,
 
398
            )
 
399
 
 
400
        class HTTPS_pycurl_transport(PyCurlTransport):
 
401
 
 
402
            def __init__(self, base, _from_transport=None):
 
403
                super(HTTPS_pycurl_transport, self).__init__(base,
 
404
                                                             _from_transport)
 
405
                self.cabundle = str(ssl_certs.build_path('ca.crt'))
 
406
 
 
407
        permutations.append((HTTPS_pycurl_transport,
 
408
                             https_server.HTTPSServer_PyCurl))
 
409
    return permutations