37
class ResponseFile(object):
38
"""A wrapper around the http socket containing the result of a GET request.
40
Only read() and seek() (forward) are supported.
42
def __init__(self, path, infile):
45
:param path: File url, for error reports.
47
:param infile: File-like socket set at body start.
56
Dummy implementation for consistency with the 'file' API.
59
def read(self, size=-1):
60
"""Read size bytes from the current position in the file.
62
:param size: The number of bytes to read. Leave unspecified or pass
65
data = self._file.read(size)
66
self._pos += len(data)
69
def seek(self, offset, whence=os.SEEK_SET):
70
if whence == os.SEEK_SET:
71
if offset < self._pos:
72
raise AsserttionError(
73
"Can't seek backwards, pos: %s, offset: %s"
74
% (self._pos, offfset))
75
to_discard = offset - self._pos
76
elif whence == os.SEEK_CUR:
79
raise AssertionError("Can't seek backwards")
81
# Just discard the unwanted bytes
35
84
# A RangeFile expects the following grammar (simplified to outline the
36
85
# assumptions we rely upon).
42
# whole_file: [content_length_header] data
44
90
# single_range: content_range_header data
46
92
# multiple_range: boundary_header boundary (content_range_header data boundary)+
48
class RangeFile(object):
94
class RangeFile(ResponseFile):
49
95
"""File-like object that allow access to partial available data.
51
97
All accesses should happen sequentially since the acquisition occurs during
72
118
:param path: File url, for error reports.
73
120
:param infile: File-like socket set at body start.
122
super(RangeFile, self).__init__(path, infile)
77
123
self._boundary = None
78
124
# When using multi parts response, this will be set with the headers
79
125
# associated with the range currently read.
297
343
:return: A file-like object that can seek()+read() the
298
344
ranges indicated by the headers.
300
rfile = RangeFile(url, data)
303
size = msg.getheader('content-length', None)
308
rfile.set_range(0, size)
348
rfile = ResponseFile(url, data)
309
349
elif code == 206:
350
rfile = RangeFile(url, data)
310
351
content_type = msg.getheader('content-type', None)
311
352
if content_type is None:
312
353
# When there is no content-type header we treat the response as