def upload_hash_content_to_blobstore( generate_upload_url, data, hash_key, content): """Uploads the given hash contents directly to the blobstore via a generated url. Arguments: generate_upload_url: The url to get the new upload url from. data: extra POST data. hash_key: sha1 of the uncompressed version of content. content: The contents to upload. Must fit in memory for now. """ logging.debug('Generating url to directly upload file to blobstore') assert isinstance(hash_key, str), hash_key assert isinstance(content, str), (hash_key, content) # TODO(maruel): Support large files. This would require streaming support. content_type, body = encode_multipart_formdata( data, [('content', hash_key, content)]) for attempt in xrange(run_isolated.URL_OPEN_MAX_ATTEMPTS): # Retry HTTP 50x here. upload_url = run_isolated.url_read(generate_upload_url, data=data) if not upload_url: raise run_isolated.MappingError( 'Unable to connect to server %s' % generate_upload_url) # Do not retry this request on HTTP 50x. Regenerate an upload url each time # since uploading "consumes" the upload url. result = run_isolated.url_read( upload_url, data=body, content_type=content_type, retry_50x=False) if result is not None: return result if attempt != run_isolated.URL_OPEN_MAX_ATTEMPTS - 1: run_isolated.HttpService.sleep_before_retry(attempt, None) raise run_isolated.MappingError( 'Unable to connect to server %s' % generate_upload_url)
def url_read(url, **kwargs): result = run_isolated.url_read(url, **kwargs) if result is None: # If we get no response from the server, assume it is down and raise an # exception. raise run_isolated.MappingError('Unable to connect to server %s' % url) return result
def test_url_read(self): # Successfully reads the data. self.mock(run_isolated, 'url_open', lambda url, **_kwargs: fake_http_response('111', url)) self.assertEqual(run_isolated.url_read('https://fake_url.com/test'), '111') # Respects url_open connection errors. self.mock(run_isolated, 'url_open', lambda _url, **_kwargs: None) self.assertIsNone(run_isolated.url_read('https://fake_url.com/test')) # Respects read timeout errors. def timeouting_http_response(url): def read_mock(_size=None): raise run_isolated.TimeoutError() stream = StringIO.StringIO('') stream.headers = {'content-length': 0} response = run_isolated.HttpResponse(stream, url) response.read = read_mock return response self.mock(run_isolated, 'url_open', lambda url, **_kwargs: timeouting_http_response(url)) self.assertIsNone(run_isolated.url_read('https://fake_url.com/test'))