Skip to content

Commit 4fdbcc5

Browse files
authored
Ensure that 'Blob.reload' passes encryption headers. (googleapis#7441)
Closes googleapis#7440.
1 parent aea0a99 commit 4fdbcc5

File tree

6 files changed

+60
-19
lines changed

6 files changed

+60
-19
lines changed

storage/google/cloud/storage/_helpers.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ def _require_client(self, client):
8686
client = self.client
8787
return client
8888

89+
def _encryption_headers(self):
90+
"""Return any encryption headers needed to fetch the object.
91+
92+
.. note::
93+
Defined here because :meth:`reload` calls it, but this method is
94+
really only relevant for :class:`~google.cloud.storage.blob.Blob`.
95+
96+
:rtype: dict
97+
:returns: a mapping of encryption-related headers.
98+
"""
99+
return {}
100+
89101
def reload(self, client=None):
90102
"""Reload properties from Cloud Storage.
91103
@@ -103,7 +115,11 @@ def reload(self, client=None):
103115
if self.user_project is not None:
104116
query_params["userProject"] = self.user_project
105117
api_response = client._connection.api_request(
106-
method="GET", path=self.path, query_params=query_params, _target_object=self
118+
method="GET",
119+
path=self.path,
120+
query_params=query_params,
121+
headers=self._encryption_headers(),
122+
_target_object=self
107123
)
108124
self._set_properties(api_response)
109125

storage/google/cloud/storage/blob.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,14 @@ def user_project(self):
257257
"""
258258
return self.bucket.user_project
259259

260+
def _encryption_headers(self):
261+
"""Return any encryption headers needed to fetch the object.
262+
263+
:rtype: List(Tuple(str, str))
264+
:returns: a list of tuples to be passed as headers.
265+
"""
266+
return _get_encryption_headers(self._encryption_key)
267+
260268
@property
261269
def public_url(self):
262270
"""The public URL for this blob.

storage/google/cloud/storage/bucket.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
from google.cloud.storage.acl import BucketACL
3737
from google.cloud.storage.acl import DefaultObjectACL
3838
from google.cloud.storage.blob import Blob
39-
from google.cloud.storage.blob import _get_encryption_headers
4039
from google.cloud.storage.notification import BucketNotification
4140
from google.cloud.storage.notification import NONE_PAYLOAD_FORMAT
4241

@@ -671,31 +670,18 @@ def get_blob(self, blob_name, client=None, encryption_key=None, **kwargs):
671670
:rtype: :class:`google.cloud.storage.blob.Blob` or None
672671
:returns: The blob object if it exists, otherwise None.
673672
"""
674-
client = self._require_client(client)
675-
query_params = {}
676-
677-
if self.user_project is not None:
678-
query_params["userProject"] = self.user_project
679673
blob = Blob(
680674
bucket=self, name=blob_name, encryption_key=encryption_key, **kwargs
681675
)
682676
try:
683-
headers = _get_encryption_headers(encryption_key)
684-
response = client._connection.api_request(
685-
method="GET",
686-
path=blob.path,
687-
query_params=query_params,
688-
headers=headers,
689-
_target_object=blob,
690-
)
691-
# NOTE: We assume response.get('name') matches `blob_name`.
692-
blob._set_properties(response)
693677
# NOTE: This will not fail immediately in a batch. However, when
694678
# Batch.finish() is called, the resulting `NotFound` will be
695679
# raised.
696-
return blob
680+
blob.reload(client=client)
697681
except NotFound:
698682
return None
683+
else:
684+
return blob
699685

700686
def list_blobs(
701687
self,

storage/tests/unit/test__helpers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ def test_user_project_is_abstract(self):
5555
with self.assertRaises(NotImplementedError):
5656
mixin.user_project
5757

58+
def test__encryption_headers(self):
59+
mixin = self._make_one()
60+
self.assertEqual(mixin._encryption_headers(), {})
61+
5862
def test_reload(self):
5963
connection = _Connection({"foo": "Foo"})
6064
client = _Client(connection)
@@ -72,6 +76,7 @@ def test_reload(self):
7276
"method": "GET",
7377
"path": "/path",
7478
"query_params": {"projection": "noAcl"},
79+
"headers": {},
7580
"_target_object": derived,
7681
},
7782
)
@@ -95,6 +100,7 @@ def test_reload_w_user_project(self):
95100
"method": "GET",
96101
"path": "/path",
97102
"query_params": {"projection": "noAcl", "userProject": user_project},
103+
"headers": {},
98104
"_target_object": derived,
99105
},
100106
)

storage/tests/unit/test_blob.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,27 @@ def test_user_project(self):
280280
blob = self._make_one(blob_name, bucket=bucket)
281281
self.assertEqual(blob.user_project, user_project)
282282

283+
def test__encryption_headers_wo_encryption_key(self):
284+
BLOB_NAME = "blob-name"
285+
bucket = _Bucket()
286+
blob = self._make_one(BLOB_NAME, bucket=bucket)
287+
expected = {}
288+
self.assertEqual(blob._encryption_headers(), expected)
289+
290+
def test__encryption_headers_w_encryption_key(self):
291+
key = b"aa426195405adee2c8081bb9e7e74b19"
292+
header_key_value = "YWE0MjYxOTU0MDVhZGVlMmM4MDgxYmI5ZTdlNzRiMTk="
293+
header_key_hash_value = "V3Kwe46nKc3xLv96+iJ707YfZfFvlObta8TQcx2gpm0="
294+
BLOB_NAME = "blob-name"
295+
bucket = _Bucket()
296+
blob = self._make_one(BLOB_NAME, bucket=bucket, encryption_key=key)
297+
expected = {
298+
"X-Goog-Encryption-Algorithm": "AES256",
299+
"X-Goog-Encryption-Key": header_key_value,
300+
"X-Goog-Encryption-Key-Sha256": header_key_hash_value,
301+
}
302+
self.assertEqual(blob._encryption_headers(), expected)
303+
283304
def test_public_url(self):
284305
BLOB_NAME = "blob-name"
285306
bucket = _Bucket()

storage/tests/unit/test_bucket.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,13 @@ def test_get_blob_hit_w_user_project(self):
669669
self.assertIs(blob.bucket, bucket)
670670
self.assertEqual(blob.name, BLOB_NAME)
671671
kw, = connection._requested
672+
expected_qp = {
673+
"userProject": USER_PROJECT,
674+
"projection": "noAcl",
675+
}
672676
self.assertEqual(kw["method"], "GET")
673677
self.assertEqual(kw["path"], "/b/%s/o/%s" % (NAME, BLOB_NAME))
674-
self.assertEqual(kw["query_params"], {"userProject": USER_PROJECT})
678+
self.assertEqual(kw["query_params"], expected_qp)
675679

676680
def test_get_blob_hit_with_kwargs(self):
677681
from google.cloud.storage.blob import _get_encryption_headers

0 commit comments

Comments
 (0)