~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2007-12-10 10:41:24 UTC
  • mto: (3097.2.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 3099.
  • Revision ID: v.ladeuil+lp@free.fr-20071210104124-0brt3h7ed1kiug0v
Take spiv review comments into account.

* bzrlib/transport/http/response.py:
(RangeFile._seek_to_next_range): Factored out since this is now
used by both seek and read.
(RangeFile.read): Trigger next range recognition when needed.
(RangeFile.seek): Don't seek over the range boundary if not
required to.

* bzrlib/transport/http/__init__.py:
(HttpTransportBase._coalesce_readv.get_and_yield): Add a
prophylactic assertionError.

* bzrlib/tests/test_transport_implementations.py:
Fix typos.

* bzrlib/tests/test_http_response.py:
(TestRangeFileMixin.test_read_zero,
TestRangeFileMixin.test_seek_at_range_end,
TestRangeFileMixin.test_read_at_range_end,
TestRangeFileSizeUnknown.test_read_at_range_end,
TestRangeFilMultipleRanges.test_seek_at_range_end,
TestRangeFilMultipleRanges.test_read_at_range_end): More tests
covering read(0).

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    )
31
31
 
32
32
 
33
 
# A RangeFile epxects the following grammar (simplified to outline the
 
33
# A RangeFile expects the following grammar (simplified to outline the
34
34
# assumptions we rely upon).
35
35
 
36
36
# file: whole_file
80
80
    def set_boundary(self, boundary):
81
81
        """Define the boundary used in a multi parts message.
82
82
        
83
 
        The file should be at the beggining of the body, the first range
 
83
        The file should be at the beginning of the body, the first range
84
84
        definition is read and taken into account.
85
85
        """
86
86
        self._boundary = boundary
92
92
        """Read the boundary headers defining a new range"""
93
93
        boundary_line = '\r\n'
94
94
        while boundary_line == '\r\n':
95
 
            # RFC2616 19.2 Additional CRLFs may preceed the first boundary
 
95
            # RFC2616 19.2 Additional CRLFs may precede the first boundary
96
96
            # string entity.
97
97
            # To be on the safe side we allow it before any boundary line
98
98
            boundary_line = self._file.readline()
154
154
        self._pos += data_len
155
155
        return data
156
156
 
 
157
    def _seek_to_next_range(self):
 
158
        # We will cross range boundaries
 
159
        if self._boundary is None:
 
160
            # If we don't have a boundary, we can't find another range
 
161
            raise errors.InvalidRange(
 
162
                self._path, self._pos,
 
163
                "Range (%s, %s) exhausted"
 
164
                % (self._start, self._size))
 
165
        self.read_boundary()
 
166
        self.read_range_definition()
 
167
 
157
168
    def read(self, size=-1):
158
169
        """Read size bytes from the current position in the file.
159
170
 
162
173
        the final boundary line of a multipart response or for any range
163
174
        request not entirely consumed by the client (due to offset coalescing)
164
175
        """
165
 
        if self._pos < self._start:
166
 
            raise errors.InvalidRange(self._path, self._pos,
167
 
                                      "Can't read before range (%s, %s)"
168
 
                                      % (self._start, self._size))
 
176
        if (self._size > 0
 
177
            and self._pos == self._start + self._size):
 
178
            if size == 0:
 
179
                return ''
 
180
            else:
 
181
                self._seek_to_next_range()
 
182
        elif self._pos < self._start:
 
183
            raise errors.InvalidRange(
 
184
                self._path, self._pos,
 
185
                "Can't read %s bytes before range (%s, %s)"
 
186
                % (size, self._start, self._size))
169
187
        if self._size > 0:
170
188
            if size > 0 and self._pos + size > self._start + self._size:
171
189
                raise errors.InvalidRange(
176
194
        if self._size > 0:
177
195
            # Don't read past the range definition
178
196
            limited = self._start + self._size - self._pos
179
 
            if size > 0:
 
197
            if size >= 0:
180
198
                limited = min(limited, size)
181
199
            data = self._file.read(limited)
182
200
        else:
183
 
            # Size of file unknown
 
201
            # Size of file unknown, the user may have specified a size or not,
 
202
            # we delegate that to the filesocket object (-1 means read until
 
203
            # EOF)
184
204
            data = self._file.read(size)
185
205
        # Update _pos respecting the data effectively read
186
206
        self._pos += len(data)
210
230
 
211
231
        if self._size > 0:
212
232
            cur_limit = self._start + self._size
213
 
            while final_pos >= cur_limit:
 
233
            while final_pos > cur_limit:
214
234
                # We will cross range boundaries
215
235
                remain = cur_limit - self._pos
216
236
                if remain > 0:
217
237
                    # Finish reading the current range
218
238
                    self._checked_read(remain)
219
 
                if self._boundary is None:
220
 
                    # If we don't have a boundary, we can't find another range
221
 
                    raise errors.InvalidRange(self._path, self._pos,
222
 
                                              'Range (%s, %s) exhausted'
223
 
                                              % (self._start, self._size))
224
 
                self.read_boundary()
225
 
                self.read_range_definition()
 
239
                self._seek_to_next_range()
226
240
                cur_limit = self._start + self._size
227
241
 
228
242
        size = final_pos - self._pos