/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

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
import os
27
27
from cStringIO import StringIO
28
28
 
29
 
from bzrlib import errors
 
29
from bzrlib import (
 
30
    errors,
 
31
    __version__ as bzrlib_version,
 
32
    )
30
33
import bzrlib
31
 
from bzrlib.errors import (TransportNotPossible, NoSuchFile,
32
 
                           TransportError, ConnectionError,
 
34
from bzrlib.errors import (NoSuchFile,
 
35
                           ConnectionError,
33
36
                           DependencyNotPresent)
34
37
from bzrlib.trace import mutter
35
38
from bzrlib.transport import register_urlparse_netloc_protocol
36
 
from bzrlib.transport.http import (HttpTransportBase, HttpServer,
37
 
                                   _extract_headers,
38
 
                                   response, _pycurl_errors)
 
39
from bzrlib.transport.http import (
 
40
    _extract_headers,
 
41
    HttpTransportBase,
 
42
    _pycurl_errors,
 
43
    response,
 
44
    )
39
45
 
40
46
try:
41
47
    import pycurl
67
73
 
68
74
    PyCurl is a Python binding to the C "curl" multiprotocol client.
69
75
 
70
 
    This transport can be significantly faster than the builtin Python client. 
71
 
    Advantages include: DNS caching, connection keepalive, and ability to 
72
 
    set headers to allow caching.
 
76
    This transport can be significantly faster than the builtin
 
77
    Python client.  Advantages include: DNS caching.
73
78
    """
74
79
 
75
80
    def __init__(self, base, from_transport=None):
97
102
        # don't want the body - ie just do a HEAD request
98
103
        # This means "NO BODY" not 'nobody'
99
104
        curl.setopt(pycurl.NOBODY, 1)
 
105
        # In some erroneous cases, pycurl will emit text on
 
106
        # stdout if we don't catch it (see InvalidStatus tests
 
107
        # for one such occurrence).
 
108
        blackhole = StringIO()
 
109
        curl.setopt(pycurl.WRITEFUNCTION, blackhole.write)
100
110
        self._curl_perform(curl)
101
111
        code = curl.getinfo(pycurl.HTTP_CODE)
102
112
        if code == 404: # not found
164
174
        curl = self._curl
165
175
        abspath, data, header = self._setup_get_request(curl, relpath)
166
176
 
167
 
        self._curl_perform(curl, ['Range: bytes=%s'
168
 
                                  % self.range_header(ranges, tail_amount)])
 
177
        range_header = self.attempted_range_header(ranges, tail_amount)
 
178
        if range_header is None:
 
179
            # Forget ranges, the server can't handle them
 
180
            return self._get_full(relpath)
 
181
 
 
182
        curl.setopt(pycurl.RANGE, range_header)
 
183
        self._curl_perform(curl)
169
184
        data.seek(0)
170
185
 
171
186
        code = curl.getinfo(pycurl.HTTP_CODE)
195
210
    def _raise_curl_http_error(self, curl, info=None):
196
211
        code = curl.getinfo(pycurl.HTTP_CODE)
197
212
        url = curl.getinfo(pycurl.EFFECTIVE_URL)
198
 
        if info is None:
199
 
            msg = ''
 
213
        # Some error codes can be handled the same way for all
 
214
        # requests
 
215
        if code == 403:
 
216
            raise errors.TransportError(
 
217
                'Server refuses to fullfil the request for: %s' % url)
200
218
        else:
201
 
            msg = ': ' + info
202
 
        raise errors.InvalidHttpResponse(url, 'Unable to handle http code %d%s'
203
 
                                              % (code,msg))
 
219
            if info is None:
 
220
                msg = ''
 
221
            else:
 
222
                msg = ': ' + info
 
223
            raise errors.InvalidHttpResponse(
 
224
                url, 'Unable to handle http code %d%s' % (code,msg))
204
225
 
205
226
    def _set_curl_options(self, curl):
206
227
        """Set options for all requests"""
223
244
            curl.setopt(pycurl.HTTPHEADER, headers + more_headers)
224
245
            curl.perform()
225
246
        except pycurl.error, e:
226
 
            # XXX: There seem to be no symbolic constants for these values.
227
247
            url = curl.getinfo(pycurl.EFFECTIVE_URL)
228
248
            mutter('got pycurl error: %s, %s, %s, url: %s ',
229
249
                    e[0], _pycurl_errors.errorcode[e[0]], e, url)
230
250
            if e[0] in (_pycurl_errors.CURLE_COULDNT_RESOLVE_HOST,
231
251
                        _pycurl_errors.CURLE_COULDNT_CONNECT,
 
252
                        _pycurl_errors.CURLE_GOT_NOTHING,
232
253
                        _pycurl_errors.CURLE_COULDNT_RESOLVE_PROXY):
233
254
                raise ConnectionError('curl connection error (%s)\non %s'
234
255
                              % (e[1], url))
237
258
            raise
238
259
 
239
260
 
240
 
class HttpServer_PyCurl(HttpServer):
241
 
    """Subclass of HttpServer that gives http+pycurl urls.
242
 
 
243
 
    This is for use in testing: connections to this server will always go
244
 
    through pycurl where possible.
245
 
    """
246
 
 
247
 
    # urls returned by this server should require the pycurl client impl
248
 
    _url_protocol = 'http+pycurl'
249
 
 
250
 
 
251
261
def get_test_permutations():
252
262
    """Return the permutations to be used in testing."""
 
263
    from bzrlib.tests.HttpServer import HttpServer_PyCurl
253
264
    return [(PyCurlTransport, HttpServer_PyCurl),
254
265
            ]