Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions google/cloud/storage/_signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ def generate_signed_url_v4(

:type query_parameters: dict
:param query_parameters:
(Optional) Additional query paramtersto be included as part of the
(Optional) Additional query parameters to be included as part of the
signed URLs. See:
https://cloud.google.com/storage/docs/xml-api/reference-headers#query

Expand Down Expand Up @@ -586,8 +586,7 @@ def generate_signed_url_v4(
if generation is not None:
query_parameters["generation"] = generation

ordered_query_parameters = sorted(query_parameters.items())
canonical_query_string = six.moves.urllib.parse.urlencode(ordered_query_parameters)
Comment thread
IlyaFaer marked this conversation as resolved.
canonical_query_string = _url_encode(query_parameters)

canonical_elements = [
method,
Expand Down Expand Up @@ -666,3 +665,33 @@ def _sign_message(message, access_token, service_account_email):

data = json.loads(response.data.decode("utf-8"))
return data["signature"]


def _url_encode(query_params):
"""Encode query params into URL.

:type query_params: dict
:param query_params: Query params to be encoded.

:rtype: str
:returns: URL encoded query params.
"""
params = []
for name, value in query_params.items():
params.append(_quote_param(name) + "=" + _quote_param(value))
Comment thread
IlyaFaer marked this conversation as resolved.
Outdated

return "&".join(sorted(params))
Comment thread
IlyaFaer marked this conversation as resolved.


def _quote_param(param):
"""Quote query param.

:type param: dict
Comment thread
IlyaFaer marked this conversation as resolved.
Outdated
:param param: Query param to be encoded.

:rtype: str
:returns: URL encoded query param.
"""
if not isinstance(param, bytes):
param = str(param)
Comment thread
IlyaFaer marked this conversation as resolved.
return six.moves.urllib.parse.quote(param, safe="~")
Comment thread
IlyaFaer marked this conversation as resolved.
13 changes: 13 additions & 0 deletions tests/unit/test__signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,19 @@ def test_sign_bytes_failure(self):
)


class TestCustomURLEncoding(unittest.TestCase):
def test_url_encode(self):
from google.cloud.storage._signing import _url_encode

# param1 includes safe symbol ~
# param# includes symbols, which must be encoded
query_params = {"param1": "value~1-2", "param#": "*value+value/"}

self.assertEqual(
_url_encode(query_params), "param%23=%2Avalue%2Bvalue%2F&param1=value~1-2"
)
Comment thread
IlyaFaer marked this conversation as resolved.


_DUMMY_SERVICE_ACCOUNT = None


Expand Down