Skip to content

Commit bfaf049

Browse files
committed
Feedback updates
1 parent f713c3e commit bfaf049

File tree

3 files changed

+69
-21
lines changed

3 files changed

+69
-21
lines changed

gcloud/_helpers.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,30 @@ def _to_bytes(value, encoding='ascii'):
394394
raise TypeError('%r could not be converted to bytes' % (value,))
395395

396396

397+
def _from_bytes(value):
398+
"""Converts bytes to a string value, if necessary.
399+
400+
Args:
401+
value: The string/bytes value to be converted.
402+
403+
Returns:
404+
The original value converted to unicode (if bytes) or as passed in
405+
if it started out as unicode.
406+
407+
Raises:
408+
ValueError if the value could not be converted to unicode.
409+
410+
:type value: bytes
411+
:param value: bytes value to attempt string conversion on.
412+
"""
413+
result = (value.decode('utf-8')
414+
if isinstance(value, six.binary_type) else value)
415+
if isinstance(result, six.text_type):
416+
return result
417+
else:
418+
raise ValueError('%r could not be converted to unicode' % (value,))
419+
420+
397421
def _pb_timestamp_to_datetime(timestamp):
398422
"""Convert a Timestamp protobuf to a datetime object.
399423

gcloud/storage/blob.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""Create / interact with Google Cloud Storage blobs."""
1616

17-
import base64
17+
from base64 import b64encode
1818
import copy
1919
import hashlib
2020
from io import BytesIO
@@ -28,6 +28,8 @@
2828
from six.moves.urllib.parse import quote
2929

3030
from gcloud._helpers import _rfc3339_to_datetime
31+
from gcloud._helpers import _to_bytes
32+
from gcloud._helpers import _from_bytes
3133
from gcloud.credentials import generate_signed_url
3234
from gcloud.exceptions import NotFound
3335
from gcloud.exceptions import make_exception
@@ -111,23 +113,6 @@ def path_helper(bucket_path, blob_name):
111113
"""
112114
return bucket_path + '/o/' + quote(blob_name, safe='')
113115

114-
@staticmethod
115-
def _get_customer_encryption_headers(key):
116-
"""Builds customer encyrption key headers
117-
118-
:type key: str
119-
:param key: 32 byte key to build request key and hash.
120-
"""
121-
headers = {}
122-
key_hash = base64.encodestring(hashlib.sha256(key.encode('utf-8'))
123-
.digest()).rstrip()
124-
encoded_key = base64.encodestring(bytes(key.encode('utf-8'))).rstrip()
125-
headers['X-Goog-Encryption-Algorithm'] = 'AES256'
126-
headers['X-Goog-Encryption-Key'] = encoded_key.decode('utf-8')
127-
headers['X-Goog-Encryption-Key-Sha256'] = key_hash.decode('utf-8')
128-
129-
return headers
130-
131116
@property
132117
def acl(self):
133118
"""Create our ACL on demand."""
@@ -343,7 +328,7 @@ def download_to_file(self, file_obj, key=None, client=None):
343328

344329
headers = {}
345330
if key:
346-
headers.update(self._get_customer_encryption_headers(key))
331+
set_customer_encryption_headers(key, headers)
347332

348333
request = Request(download_url, 'GET', headers)
349334

@@ -417,7 +402,7 @@ def _check_response_error(request, http_response):
417402
raise make_exception(faux_response, http_response.content,
418403
error_info=request.url)
419404

420-
# pylint: disable=too-many-arguments,too-many-locals
405+
# pylint: disable=too-many-locals
421406
def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
422407
content_type=None, num_retries=6, client=None):
423408
"""Upload the contents of this blob from a file-like object.
@@ -498,7 +483,7 @@ def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
498483
}
499484

500485
if key:
501-
headers.update(self._get_customer_encryption_headers(key))
486+
set_customer_encryption_headers(key, headers)
502487

503488
upload = Upload(file_obj, content_type, total_bytes,
504489
auto_transfer=False)
@@ -923,3 +908,21 @@ def __init__(self, bucket_name, object_name):
923908
self.query_params = {'name': object_name}
924909
self._bucket_name = bucket_name
925910
self._relative_path = ''
911+
912+
913+
def set_customer_encryption_headers(key, headers):
914+
"""Builds customer encyrption key headers
915+
916+
:type key: str
917+
:param key: 32 byte key to build request key and hash.
918+
919+
:type headers: dict
920+
:param headers: dict of HTTP headers being sent in request.
921+
"""
922+
key = _to_bytes(key)
923+
sha256_key = hashlib.sha256(key).digest()
924+
key_hash = b64encode(sha256_key).rstrip()
925+
encoded_key = b64encode(key).rstrip()
926+
headers['X-Goog-Encryption-Algorithm'] = 'AES256'
927+
headers['X-Goog-Encryption-Key'] = _from_bytes(encoded_key)
928+
headers['X-Goog-Encryption-Key-Sha256'] = _from_bytes(key_hash)

gcloud/test__helpers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,27 @@ def test_with_nonstring_type(self):
586586
self.assertRaises(TypeError, self._callFUT, value)
587587

588588

589+
class Test__from_bytes(unittest2.TestCase):
590+
591+
def _callFUT(self, *args, **kwargs):
592+
from gcloud._helpers import _from_bytes
593+
return _from_bytes(*args, **kwargs)
594+
595+
def test_with_bytes(self):
596+
value = b'bytes-val'
597+
encoded_value = 'bytes-val'
598+
self.assertEqual(self._callFUT(value), encoded_value)
599+
600+
def test_with_unicode(self):
601+
value = u'string-val'
602+
encoded_value = 'string-val'
603+
self.assertEqual(self._callFUT(value), encoded_value)
604+
605+
def test_with_nonstring_type(self):
606+
value = object()
607+
self.assertRaises(ValueError, self._callFUT, value)
608+
609+
589610
class Test__pb_timestamp_to_datetime(unittest2.TestCase):
590611

591612
def _callFUT(self, timestamp):

0 commit comments

Comments
 (0)