Skip to content

Commit

Permalink
Updating Blob.generate_signed_url to accept a client.
Browse files Browse the repository at this point in the history
Towards #952, removing connection from methods / constructors.
  • Loading branch information
dhermes committed Jul 13, 2015
1 parent 8373227 commit 872a101
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 28 deletions.
17 changes: 10 additions & 7 deletions gcloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def public_url(self):
quoted_name=quote(self.name, safe=''))

def generate_signed_url(self, expiration, method='GET',
connection=None, credentials=None):
client=None, credentials=None):
"""Generates a signed URL for this blob.
If you have a blob that you want to allow access to for a set
Expand All @@ -171,10 +171,9 @@ def generate_signed_url(self, expiration, method='GET',
:type method: string
:param method: The HTTP verb that will be used when requesting the URL.
:type connection: :class:`gcloud.storage.connection.Connection` or
``NoneType``
:param connection: Optional. The connection to use when sending
requests. If not provided, falls back to default.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
to the ``connection`` stored on the blob's bucket.
:type credentials: :class:`oauth2client.client.OAuth2Credentials` or
:class:`NoneType`
Expand All @@ -183,14 +182,18 @@ def generate_signed_url(self, expiration, method='GET',
:rtype: string
:returns: A signed URL you can use to access the resource
until expiration.
:raises: :class:`ValueError` if no credentials could be determined
from the arguments.
"""
resource = '/{bucket_name}/{quoted_name}'.format(
bucket_name=self.bucket.name,
quoted_name=quote(self.name, safe=''))

if credentials is None:
connection = _require_connection(connection)
credentials = connection.credentials
if client is not None:
credentials = client.connection.credentials
else:
raise ValueError('Credentials could be determined.')

return generate_signed_url(
credentials, resource=resource,
Expand Down
44 changes: 25 additions & 19 deletions gcloud/storage/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,37 +146,31 @@ def test_public_url_w_slash_in_name(self):
blob.public_url,
'https://storage.googleapis.com/name/parent%2Fchild')

def _basic_generate_signed_url_helper(self, credentials=None):
def _basic_generate_signed_url_helper(self, credentials=None,
use_client=True):
from gcloud._testing import _Monkey
from gcloud.storage import blob as MUT

BLOB_NAME = 'blob-name'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=2014-10-16T20:34:37.000Z')

_called_require = []

def mock_require(connection):
_called_require.append(connection)
return connection

SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER,
_require_connection=mock_require):
signed_uri = blob.generate_signed_url(EXPIRATION,
connection=connection,
credentials=credentials)
with _Monkey(MUT, generate_signed_url=SIGNER):
if use_client:
signed_uri = blob.generate_signed_url(EXPIRATION,
client=client,
credentials=credentials)
else:
signed_uri = blob.generate_signed_url(EXPIRATION,
credentials=credentials)
self.assertEqual(signed_uri, URI)

if credentials is None:
self.assertEqual(_called_require, [connection])
else:
self.assertEqual(_called_require, [])

PATH = '/name/%s' % (BLOB_NAME,)
if credentials is None:
EXPECTED_ARGS = (_Connection.credentials,)
Expand All @@ -190,6 +184,10 @@ def mock_require(connection):
}
self.assertEqual(SIGNER._signed, [(EXPECTED_ARGS, EXPECTED_KWARGS)])

def test_generate_signed_url_w_no_creds(self):
with self.assertRaises(ValueError):
self._basic_generate_signed_url_helper(use_client=False)

def test_generate_signed_url_w_default_method(self):
self._basic_generate_signed_url_helper()

Expand All @@ -204,6 +202,7 @@ def test_generate_signed_url_w_slash_in_name(self):
BLOB_NAME = 'parent/child'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
Expand All @@ -212,7 +211,7 @@ def test_generate_signed_url_w_slash_in_name(self):
SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_url = blob.generate_signed_url(EXPIRATION,
connection=connection)
client=client)
self.assertEqual(signed_url, URI)

EXPECTED_ARGS = (_Connection.credentials,)
Expand All @@ -231,6 +230,7 @@ def test_generate_signed_url_w_explicit_method(self):
BLOB_NAME = 'blob-name'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
Expand All @@ -239,7 +239,7 @@ def test_generate_signed_url_w_explicit_method(self):
SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_uri = blob.generate_signed_url(EXPIRATION, method='POST',
connection=connection)
client=client)
self.assertEqual(signed_uri, URI)

PATH = '/name/%s' % (BLOB_NAME,)
Expand Down Expand Up @@ -1152,3 +1152,9 @@ def __call__(self, *args, **kwargs):
self._signed.append((args, kwargs))
return ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=%s' % kwargs.get('expiration'))


class _Client(object):

def __init__(self, connection):
self.connection = connection
6 changes: 4 additions & 2 deletions system_tests/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ def tearDown(self):
def test_create_signed_read_url(self):
blob = storage.Blob(bucket=self.bucket, name='LogoToSign.jpg')
expiration = int(time.time() + 5)
signed_url = blob.generate_signed_url(expiration, method='GET')
signed_url = blob.generate_signed_url(expiration, method='GET',
client=CLIENT)

response, content = HTTP.request(signed_url, method='GET')
self.assertEqual(response.status, 200)
Expand All @@ -331,7 +332,8 @@ def test_create_signed_delete_url(self):
blob = storage.Blob(bucket=self.bucket, name='LogoToSign.jpg')
expiration = int(time.time() + 283473274)
signed_delete_url = blob.generate_signed_url(expiration,
method='DELETE')
method='DELETE',
client=CLIENT)

response, content = HTTP.request(signed_delete_url, method='DELETE')
self.assertEqual(response.status, 204)
Expand Down

1 comment on commit 872a101

@tseaver
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit LGTM.

Please sign in to comment.