def _send_chunk(self, start): """Send a chunk of the stream. Helper for :meth:`stream_file`: :type start: integer :param start: start byte of the range. :rtype: :class:`google.cloud.streaming.http_wrapper.Response` :returns: The response from the chunked upload request. """ self._ensure_initialized() no_log_body = self.total_size is None if self.total_size is None: # For the streaming resumable case, we need to detect when # we're at the end of the stream. body_stream = BufferedStream( self.stream, start, self.chunksize) end = body_stream.stream_end_position if body_stream.stream_exhausted: self._total_size = end # Here, change body_stream from a stream to a string object, # which means reading a chunk into memory. This works around # https://code.google.com/p/httplib2/issues/detail?id=176 which can # cause httplib2 to skip bytes on 401's for file objects. body_stream = body_stream.read(self.chunksize) else: end = min(start + self.chunksize, self.total_size) body_stream = StreamSlice(self.stream, end - start) request = Request(url=self.url, http_method='PUT', body=body_stream) request.headers['Content-Type'] = self.mime_type if no_log_body: # Disable logging of streaming body. request.loggable_body = '<media body>' if self.total_size is None: # Streaming resumable upload case, unknown total size. range_string = 'bytes %s-%s/*' % (start, end - 1) elif end == start: # End of an upload with 0 bytes left to send; just finalize. range_string = 'bytes */%s' % self.total_size else: # Normal resumable upload case with known sizes. range_string = 'bytes %s-%s/%s' % (start, end - 1, self.total_size) request.headers['Content-Range'] = range_string return self._send_media_request(request, end)