예제 #1
0
    def _process_response(self, response):
        """Update attribtes and writing stream, based on response.

        :type response: :class:`google.cloud.streaming.http_wrapper.Response`
        :param response: response from a download request.

        :rtype: :class:`google.cloud.streaming.http_wrapper.Response`
        :returns: the response
        :raises: :exc:`google.cloud.streaming.exceptions.HttpError` for
                 missing / unauthorized responses;
                 :exc:`google.cloud.streaming.exceptions.TransferRetryError`
                 for other error responses.
        """
        if response.status_code not in self._ACCEPTABLE_STATUSES:
            # We distinguish errors that mean we made a mistake in setting
            # up the transfer versus something we should attempt again.
            if response.status_code in (http_client.FORBIDDEN,
                                        http_client.NOT_FOUND):
                raise HttpError.from_response(response)
            else:
                raise TransferRetryError(response.content)
        if response.status_code in (http_client.OK,
                                    http_client.PARTIAL_CONTENT):
            self.stream.write(response.content)
            self._progress += response.length
            if response.info and 'content-encoding' in response.info:
                self._encoding = response.info['content-encoding']
        elif response.status_code == http_client.NO_CONTENT:
            # It's important to write something to the stream for the case
            # of a 0-byte download to a file, as otherwise python won't
            # create the file.
            self.stream.write('')
        return response
예제 #2
0
    def get_range(self, start, end=None, use_chunks=True):
        """Retrieve a given byte range from this download, inclusive.

        Writes retrieved bytes into :attr:`stream`.

        Range must be of one of these three forms:
        * 0 <= start, end = None: Fetch from start to the end of the file.
        * 0 <= start <= end: Fetch the bytes from start to end.
        * start < 0, end = None: Fetch the last -start bytes of the file.

        (These variations correspond to those described in the HTTP 1.1
        protocol for range headers in RFC 2616, sec. 14.35.1.)

        :type start: int
        :param start: Where to start fetching bytes. (See above.)

        :type end: int
        :param end: (Optional) Where to stop fetching bytes. (See above.)

        :type use_chunks: bool
        :param use_chunks: If False, ignore :attr:`chunksize`
                           and fetch this range in a single request.
                           If True, streams via chunks.

        :raises: :exc:`google.cloud.streaming.exceptions.TransferRetryError`
                 if a request returns an empty response.
        """
        self._ensure_initialized()
        progress_end_normalized = False
        if self.total_size is not None:
            progress, end_byte = self._normalize_start_end(start, end)
            progress_end_normalized = True
        else:
            progress = start
            end_byte = end
        while (not progress_end_normalized or end_byte is None
               or progress <= end_byte):
            end_byte = self._compute_end_byte(progress,
                                              end=end_byte,
                                              use_chunks=use_chunks)
            response = self._get_chunk(progress, end_byte)
            if not progress_end_normalized:
                self._set_total(response.info)
                progress, end_byte = self._normalize_start_end(start, end)
                progress_end_normalized = True
            response = self._process_response(response)
            progress += response.length
            if response.length == 0:
                raise TransferRetryError(
                    'Zero bytes unexpectedly returned in download response')