~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: v.ladeuil+lp at free
  • Date: 2006-12-01 15:06:29 UTC
  • mto: (2172.3.1 bzr.73948)
  • mto: This revision was merged to the branch mainline in revision 2181.
  • Revision ID: v.ladeuil+lp@free.fr-20061201150629-zjd2an87u0r7nhhw
The tests that would have help avoid bug #73948 and all that mess :)

* bzrlib/transport/http/response.py:
(handle_response): Translate a 416 http error code into a bzr
exception.

* bzrlib/transport/http/_urllib2_wrappers.py:
(HTTPDefaultErrorHandler.http_error_default): Translate a 416 http
error code into a bzr exception.

* bzrlib/transport/http/_pycurl.py:
(PyCurlTransport._curl_perform): It could happen that pycrul
itself detect a short read.

* bzrlib/transport/http/__init__.py:
(HttpTransportBase._retry_get): New method, factorizing the retry
logic.
(HttpTransportBase.readv): We can have exception during the
initial GET worth degrading the range requirements (i.e. retrying
the GET request with either single or not ranges).

* bzrlib/tests/test_transport_implementations.py:
(TransportTests.test_readv_short_read): InvalidRange can also be
raised.

* bzrlib/tests/test_http.py:
(TestRangeRequestServer.test_readv_invalid_ranges): Was named
test_readv_short_read, the new name make the intent
clearer. Depending of the code path used (urllib or pycurl), both
exceptions can be raised.

* bzrlib/tests/HttpServer.py:
(TestingHTTPRequestHandler.do_GET): If invalid ranges are
specified, returns a 416 instead of the whole file (both are valid
according to the RFC).

Show diffs side-by-side

added added

removed removed

Lines of Context:
251
251
        """
252
252
        return self
253
253
 
 
254
    def _retry_get(self, relpath, ranges, exception):
 
255
        """A GET request have failed, let's retry with a simpler request."""
 
256
 
 
257
        try_again = False
 
258
        # The server does not gives us enough data or
 
259
        # bogus-looking result, let's try again with
 
260
        # a simpler request if possible.
 
261
        if self._range_hint == 'multi':
 
262
            self._range_hint = 'single'
 
263
            mutter('Retry %s with single range request' % relpath)
 
264
            try_again = True
 
265
        elif self._range_hint == 'single':
 
266
            self._range_hint = None
 
267
            mutter('Retry %s without ranges' % relpath)
 
268
            try_again = True
 
269
        if try_again:
 
270
            # Note that since the offsets and the ranges may not
 
271
            # be in the same order we dont't try to calculate a
 
272
            # restricted single range encompassing unprocessed
 
273
            # offsets.
 
274
            code, f = self._get(relpath, ranges)
 
275
            return try_again, code, f
 
276
        else:
 
277
            # We tried all the tricks, nothing worked
 
278
            raise exception
 
279
 
254
280
    def readv(self, relpath, offsets):
255
281
        """Get parts of the file at the given relative path.
256
282
 
260
286
        ranges = self.offsets_to_ranges(offsets)
261
287
        mutter('http readv of %s collapsed %s offsets => %s',
262
288
                relpath, len(offsets), ranges)
263
 
        code, f = self._get(relpath, ranges)
 
289
 
 
290
        try_again = True
 
291
        while try_again:
 
292
            try_again = False
 
293
            try:
 
294
                code, f = self._get(relpath, ranges)
 
295
            except (errors.InvalidRange, errors.ShortReadvError), exception:
 
296
                try_again, code, f = self._retry_get(relpath, ranges, exception)
 
297
 
264
298
        for start, size in offsets:
265
299
            try_again = True
266
300
            while try_again:
272
306
                    if len(data) != size:
273
307
                        raise errors.ShortReadvError(relpath, start, size,
274
308
                                                     actual=len(data))
275
 
                except (errors.InvalidRange, errors.ShortReadvError):
276
 
                    # The server does not gives us enough data or
277
 
                    # bogus-looking result, let's try again with
278
 
                    # a simpler request if possible.
279
 
                    if self._range_hint == 'multi':
280
 
                        self._range_hint = 'single'
281
 
                        mutter('Retry %s with single range request' % relpath)
282
 
                        try_again = True
283
 
                    elif self._range_hint == 'single':
284
 
                        self._range_hint = None
285
 
                        mutter('Retry %s without ranges' % relpath)
286
 
                        try_again = True
287
 
                    if try_again:
288
 
                        # Note that since the offsets and the
289
 
                        # ranges may not be in the same order we
290
 
                        # dont't try to calculate a restricted
291
 
                        # single range encompassing unprocessed
292
 
                        # offsets. Note that we replace 'f' here
293
 
                        # and that it may need cleaning one day
294
 
                        # before being thrown that way.
295
 
                        code, f = self._get(relpath, ranges)
296
 
                    else:
297
 
                        # We tried all the tricks, nothing worked
298
 
                        raise
299
 
 
 
309
                except (errors.InvalidRange, errors.ShortReadvError), exception:
 
310
                    # Note that we replace 'f' here and that it
 
311
                    # may need cleaning one day before being
 
312
                    # thrown that way.
 
313
                    try_again, code, f = self._retry_get(relpath, ranges,
 
314
                                                         exception)
 
315
            # After one or more tries, we get the data.
300
316
            yield start, data
301
317
 
302
318
    @staticmethod