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
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')