Example #1
0
 def _seek_to_next_range(self):
     # We will cross range boundaries
     if self._boundary is None:
         # If we don't have a boundary, we can't find another range
         raise errors.InvalidRange(
             self._path, self._pos,
             "Range (%s, %s) exhausted" % (self._start, self._size))
     self.read_boundary()
     self.read_range_definition()
Example #2
0
    def read(self, size=-1):
        """Read size bytes from the current position in the file.

        Reading across ranges is not supported. We rely on the underlying http
        client to clean the socket if we leave bytes unread. This may occur for
        the final boundary line of a multipart response or for any range
        request not entirely consumed by the client (due to offset coalescing)

        :param size:  The number of bytes to read.  Leave unspecified or pass
            -1 to read to EOF.
        """
        if (self._size > 0 and self._pos == self._start + self._size):
            if size == 0:
                return ''
            else:
                self._seek_to_next_range()
        elif self._pos < self._start:
            raise errors.InvalidRange(
                self._path, self._pos,
                "Can't read %s bytes before range (%s, %s)" %
                (size, self._start, self._size))
        if self._size > 0:
            if size > 0 and self._pos + size > self._start + self._size:
                raise errors.InvalidRange(
                    self._path, self._pos,
                    "Can't read %s bytes across range (%s, %s)" %
                    (size, self._start, self._size))

        # read data from file
        buf = StringIO()
        limited = size
        if self._size > 0:
            # Don't read past the range definition
            limited = self._start + self._size - self._pos
            if size >= 0:
                limited = min(limited, size)
        osutils.pumpfile(self._file, buf, limited, self._max_read_size)
        data = buf.getvalue()

        # Update _pos respecting the data effectively read
        self._pos += len(data)
        return data
Example #3
0
    def seek(self, offset, whence=0):
        start_pos = self._pos
        if whence == 0:
            final_pos = offset
        elif whence == 1:
            final_pos = start_pos + offset
        elif whence == 2:
            if self._size > 0:
                final_pos = self._start + self._size + offset  # offset < 0
            else:
                raise errors.InvalidRange(
                    self._path, self._pos,
                    "RangeFile: can't seek from end while size is unknown")
        else:
            raise ValueError("Invalid value %s for whence." % whence)

        if final_pos < self._pos:
            # Can't seek backwards
            raise errors.InvalidRange(
                self._path, self._pos,
                'RangeFile: trying to seek backwards to %s' % final_pos)

        if self._size > 0:
            cur_limit = self._start + self._size
            while final_pos > cur_limit:
                # We will cross range boundaries
                remain = cur_limit - self._pos
                if remain > 0:
                    # Finish reading the current range
                    self._checked_read(remain)
                self._seek_to_next_range()
                cur_limit = self._start + self._size

        size = final_pos - self._pos
        if size > 0:  # size can be < 0 if we crossed a range boundary
            # We don't need the data, just read it and throw it away
            self._checked_read(size)
Example #4
0
 def test_invalid_range(self):
     error = errors.InvalidRange('path', 12, 'bad range')
     self.assertEquals("Invalid range access in path at 12: bad range",
                       str(error))