/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

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

  • Committer: Andrew Bennetts
  • Date: 2010-04-13 04:33:55 UTC
  • mfrom: (5147 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5149.
  • Revision ID: andrew.bennetts@canonical.com-20100413043355-lg3id0uwtju0k3zs
MergeĀ lp:bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""http/https transport using pycurl"""
18
18
 
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_RECV_ERROR = _get_pycurl_errcode('E_RECV_ERROR', 56)
 
96
CURLE_SSL_CACERT = _get_pycurl_errcode('E_SSL_CACERT', 60)
 
97
CURLE_SSL_CACERT_BADFILE = _get_pycurl_errcode('E_SSL_CACERT_BADFILE', 77)
96
98
 
97
99
 
98
100
class PyCurlTransport(HttpTransportBase):
105
107
    """
106
108
 
107
109
    def __init__(self, base, _from_transport=None):
108
 
        super(PyCurlTransport, self).__init__(base,
 
110
        super(PyCurlTransport, self).__init__(base, 'pycurl',
109
111
                                              _from_transport=_from_transport)
110
 
        if base.startswith('https'):
 
112
        if self._unqualified_scheme == 'https':
111
113
            # Check availability of https into pycurl supported
112
114
            # protocols
113
115
            supported = pycurl.version_info()[8]
179
181
 
180
182
        :param curl: The curl object to place the request on
181
183
        :param relpath: The relative path that we want to get
182
 
        :return: (abspath, data, header) 
 
184
        :return: (abspath, data, header)
183
185
                 abspath: full url
184
186
                 data: file that will be filled with the body
185
187
                 header: file that will be filled with the headers
214
216
 
215
217
    # The parent class use 0 to minimize the requests, but since we can't
216
218
    # 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.
 
219
    # better issue more requests and provide a more responsive UI incurring
 
220
    # more latency costs.
219
221
    # If you modify this, think about modifying the comment in http/__init__.py
220
222
    # too.
221
223
    _get_max_size = 4 * 1024 * 1024
286
288
        msg = self._parse_headers(header)
287
289
        return code, response.handle_response(abspath, code, msg, data)
288
290
 
 
291
 
289
292
    def _raise_curl_http_error(self, curl, info=None):
290
293
        code = curl.getinfo(pycurl.HTTP_CODE)
291
294
        url = curl.getinfo(pycurl.EFFECTIVE_URL)
303
306
            raise errors.InvalidHttpResponse(
304
307
                url, 'Unable to handle http code %d%s' % (code,msg))
305
308
 
 
309
    def _debug_cb(self, kind, text):
 
310
        if kind in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN,
 
311
                    pycurl.INFOTYPE_SSL_DATA_IN):
 
312
            self._report_activity(len(text), 'read')
 
313
            if (kind == pycurl.INFOTYPE_HEADER_IN
 
314
                and 'http' in debug.debug_flags):
 
315
                mutter('< %s' % text)
 
316
        elif kind in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT,
 
317
                      pycurl.INFOTYPE_SSL_DATA_OUT):
 
318
            self._report_activity(len(text), 'write')
 
319
            if (kind == pycurl.INFOTYPE_HEADER_OUT
 
320
                and 'http' in debug.debug_flags):
 
321
                mutter('> %s' % text)
 
322
        elif kind == pycurl.INFOTYPE_TEXT and 'http' in debug.debug_flags:
 
323
            mutter('* %s' % text)
 
324
 
306
325
    def _set_curl_options(self, curl):
307
326
        """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
327
        ua_str = 'bzr/%s (pycurl: %s)' % (bzrlib.__version__, pycurl.version)
314
328
        curl.setopt(pycurl.USERAGENT, ua_str)
 
329
        curl.setopt(pycurl.VERBOSE, 1)
 
330
        curl.setopt(pycurl.DEBUGFUNCTION, self._debug_cb)
315
331
        if self.cabundle:
316
332
            curl.setopt(pycurl.CAINFO, self.cabundle)
317
333
        # Set accepted auth methods
343
359
            url = curl.getinfo(pycurl.EFFECTIVE_URL)
344
360
            mutter('got pycurl error: %s, %s, %s, url: %s ',
345
361
                    e[0], e[1], e, url)
346
 
            if e[0] in (CURLE_SSL_CACERT_BADFILE,
347
 
                        CURLE_COULDNT_RESOLVE_HOST,
 
362
            if e[0] in (CURLE_COULDNT_RESOLVE_HOST,
 
363
                        CURLE_COULDNT_RESOLVE_PROXY,
348
364
                        CURLE_COULDNT_CONNECT,
349
365
                        CURLE_GOT_NOTHING,
350
 
                        CURLE_COULDNT_RESOLVE_PROXY,):
 
366
                        CURLE_SSL_CACERT,
 
367
                        CURLE_SSL_CACERT_BADFILE,
 
368
                        ):
351
369
                raise errors.ConnectionError(
352
370
                    'curl connection error (%s)\non %s' % (e[1], url))
 
371
            elif e[0] == CURLE_RECV_ERROR:
 
372
                raise errors.ConnectionReset(
 
373
                    'curl connection error (%s)\non %s' % (e[1], url))
353
374
            elif e[0] == CURLE_PARTIAL_FILE:
354
375
                # Pycurl itself has detected a short read.  We do not have all
355
376
                # the information for the ShortReadvError, but that should be
366
387
            redirected_to = msg.getheader('location')
367
388
            raise errors.RedirectRequested(url,
368
389
                                           redirected_to,
369
 
                                           is_permanent=(code == 301),
370
 
                                           qual_proto=self._scheme)
 
390
                                           is_permanent=(code == 301))
371
391
 
372
392
 
373
393
def get_test_permutations():
374
394
    """Return the permutations to be used in testing."""
375
 
    from bzrlib.tests.http_server import HttpServer_PyCurl
376
 
    return [(PyCurlTransport, HttpServer_PyCurl),
377
 
            ]
 
395
    from bzrlib import tests
 
396
    from bzrlib.tests import http_server
 
397
    permutations = [(PyCurlTransport, http_server.HttpServer_PyCurl),]
 
398
    if tests.HTTPSServerFeature.available():
 
399
        from bzrlib.tests import (
 
400
            https_server,
 
401
            ssl_certs,
 
402
            )
 
403
 
 
404
        class HTTPS_pycurl_transport(PyCurlTransport):
 
405
 
 
406
            def __init__(self, base, _from_transport=None):
 
407
                super(HTTPS_pycurl_transport, self).__init__(base,
 
408
                                                             _from_transport)
 
409
                self.cabundle = str(ssl_certs.build_path('ca.crt'))
 
410
 
 
411
        permutations.append((HTTPS_pycurl_transport,
 
412
                             https_server.HTTPSServer_PyCurl))
 
413
    return permutations