def RefreshResumableUploadState(self): """Talk to the server and refresh the state of this resumable upload. Returns: Response if the upload is complete. """ if self.strategy != RESUMABLE_UPLOAD: return self.EnsureInitialized() refresh_request = http_wrapper.Request( url=self.url, http_method='PUT', headers={'Content-Range': 'bytes */*'}) refresh_response = http_wrapper.MakeRequest(self.http, refresh_request, redirections=0, retries=self.num_retries) range_header = self._GetRangeHeaderFromResponse(refresh_response) if refresh_response.status_code in (httplib.OK, httplib.CREATED): self.__complete = True self.__progress = self.total_size self.stream.seek(self.progress) # If we're finished, the refresh response will contain the metadata # originally requested. Cache it so it can be returned in StreamInChunks. self.__final_response = refresh_response elif refresh_response.status_code == http_wrapper.RESUME_INCOMPLETE: if range_header is None: self.__progress = 0 else: self.__progress = self.__GetLastByte(range_header) + 1 self.stream.seek(self.progress) else: raise exceptions.HttpError.FromResponse(refresh_response)
def PrepareHttpRequest(self, method_config, request, global_params=None, upload=None, upload_config=None, download=None): """Prepares an HTTP request to be sent.""" request_type = _LoadClass(method_config.request_type_name, self.__client.MESSAGES_MODULE) util.Typecheck(request, request_type) request = self.__client.ProcessRequest(method_config, request) http_request = http_wrapper.Request( http_method=method_config.http_method) self.__SetBaseHeaders(http_request, self.__client) self.__SetBody(http_request, method_config, request, upload) url_builder = _UrlBuilder(self.__client.url, relative_path=method_config.relative_path) url_builder.query_params = self.__ConstructQueryParams( method_config.query_params, request, global_params) # It's important that upload and download go before we fill in the # relative path, so that they can replace it. if upload is not None: upload.ConfigureRequest(upload_config, http_request, url_builder) if download is not None: download.ConfigureRequest(http_request, url_builder) url_builder.relative_path = self.__ConstructRelativePath( method_config, request, relative_path=url_builder.relative_path) self.__FinalizeRequest(http_request, url_builder) return self.__client.ProcessHttpRequest(http_request)
def __SendChunk(self, start, additional_headers=None): """Send the specified chunk.""" self.EnsureInitialized() 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 = buffered_stream.BufferedStream( self.stream, start, self.chunksize) end = body_stream.stream_end_position if body_stream.stream_exhausted: self.__total_size = end else: end = min(start + self.chunksize, self.total_size) body_stream = stream_slice.StreamSlice(self.stream, end - start) # TODO: Think about clearer errors on "no data in stream". request = http_wrapper.Request(url=self.url, http_method='PUT', body=body_stream) request.headers['Content-Type'] = self.mime_type 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 if additional_headers: request.headers.update(additional_headers) return self.__SendMediaRequest(request, end)
def __SendMediaBody(self, start, additional_headers=None): """Send the entire media stream in a single request.""" self.EnsureInitialized() if self.total_size is None: raise exceptions.TransferInvalidError( 'Total size must be known for SendMediaBody') body_stream = stream_slice.StreamSlice(self.stream, self.total_size - start) request = http_wrapper.Request(url=self.url, http_method='PUT', body=body_stream) request.headers['Content-Type'] = self.mime_type if start == self.total_size: # End of an upload with 0 bytes left to send; just finalize. range_string = 'bytes */%s' % self.total_size else: range_string = 'bytes %s-%s/%s' % (start, self.total_size - 1, self.total_size) request.headers['Content-Range'] = range_string if additional_headers: request.headers.update(additional_headers) return self.__SendMediaRequest(request, self.total_size)
def __SendChunk(self, start, additional_headers=None): """Send the specified chunk.""" self.EnsureInitialized() end = min(start + self.chunksize, self.total_size) body_stream = stream_slice.StreamSlice(self.stream, end - start) # TODO: Think about clearer errors on "no data in stream". request = http_wrapper.Request(url=self.url, http_method='PUT', body=body_stream) request.headers['Content-Type'] = self.mime_type request.headers['Content-Range'] = 'bytes %s-%s/%s' % (start, end - 1, self.total_size) if additional_headers: request.headers.update(additional_headers) response = http_wrapper.MakeRequest(self.bytes_http, request, retry_func=self.retry_func) if response.status_code not in (httplib.OK, httplib.CREATED, http_wrapper.RESUME_INCOMPLETE): # We want to reset our state to wherever the server left us # before this failed request, and then raise. self.RefreshResumableUploadState() raise exceptions.HttpError.FromResponse(response) if response.status_code == http_wrapper.RESUME_INCOMPLETE: last_byte = self.__GetLastByte( self._GetRangeHeaderFromResponse(response)) if last_byte + 1 != end: self.stream.seek(last_byte) return response
def __GetChunk(self, start, end=None, additional_headers=None): """Retrieve a chunk, and return the full response.""" self.EnsureInitialized() end_byte = end if self.total_size and end: end_byte = min(end, self.total_size) request = http_wrapper.Request(url=self.url) self.__SetRangeHeader(request, start, end=end_byte) if additional_headers is not None: request.headers.update(additional_headers) return http_wrapper.MakeRequest(self.bytes_http, request, retry_func=self.retry_func)
def __SendChunk(self, start, additional_headers=None): """Send the specified chunk.""" self.EnsureInitialized() 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 = buffered_stream.BufferedStream( self.stream, start, self.chunksize) end = body_stream.stream_end_position if body_stream.stream_exhausted: self.__total_size = end else: end = min(start + self.chunksize, self.total_size) body_stream = stream_slice.StreamSlice(self.stream, end - start) # TODO: Think about clearer errors on "no data in stream". request = http_wrapper.Request(url=self.url, http_method='PUT', body=body_stream) request.headers['Content-Type'] = self.mime_type 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 if additional_headers: request.headers.update(additional_headers) response = http_wrapper.MakeRequest(self.bytes_http, request, retry_func=self.retry_func, retries=self.num_retries) if response.status_code not in (httplib.OK, httplib.CREATED, http_wrapper.RESUME_INCOMPLETE): # We want to reset our state to wherever the server left us # before this failed request, and then raise. self.RefreshResumableUploadState() raise exceptions.HttpError.FromResponse(response) if response.status_code == http_wrapper.RESUME_INCOMPLETE: last_byte = self.__GetLastByte( self._GetRangeHeaderFromResponse(response)) if last_byte + 1 != end: self.stream.seek(last_byte) return response