52
52
"""Set the base path where files will be stored."""
53
53
super(HttpTransport_urllib, self).__init__(base)
55
def readv(self, relpath, offsets):
56
"""Get parts of the file at the given relative path.
58
:param offsets: A list of (offset, size) tuples.
59
:param return: A list or generator of (offset, data) tuples
61
mutter('readv of %s [%s]', relpath, offsets)
62
ranges = self._offsets_to_ranges(offsets)
63
code, f = self._get(relpath, ranges)
64
for start, size in offsets:
67
assert len(data) == size
70
def _is_multipart(self, content_type):
71
return content_type.startswith('multipart/byteranges;')
73
def _handle_response(self, path, response):
74
"""Interpret the code & headers and return a HTTP response.
76
This is a factory method which returns an appropriate HTTP response
77
based on the code & headers it's given.
79
content_type = response.headers['Content-Type']
80
mutter('handling response code %s ctype %s', response.code,
83
if response.code == 206 and self._is_multipart(content_type):
84
# Full fledged multipart response
85
return HttpMultipartRangeResponse(path, content_type, response)
86
elif response.code == 206:
87
# A response to a range request, but not multipart
88
content_range = response.headers['Content-Range']
89
return HttpRangeResponse(path, content_range, response)
90
elif response.code == 200:
91
# A regular non-range response, unfortunately the result from
92
# urllib doesn't support seek, so we wrap it in a StringIO
93
return StringIO(response.read())
94
elif response.code == 404:
95
raise NoSuchFile(path)
97
raise BzrError("HTTP couldn't handle code %s", response.code)
99
55
def _get(self, relpath, ranges):