Skip to content

Commit 145c26f

Browse files
committed
Always escape special chars in URL query params
1 parent 1396809 commit 145c26f

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

pyodata/v2/service.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,8 @@
1313
from email.parser import Parser
1414
from http.client import HTTPResponse
1515
from io import BytesIO
16+
from urllib.parse import urlencode
1617

17-
try:
18-
# For Python 3.0 and later
19-
from urllib.parse import quote
20-
except ImportError:
21-
# Fallback to urllib2
22-
from urllib2 import quote
2318

2419
from pyodata.exceptions import HttpError, PyODataException, ExpressionError, ProgramError
2520
from . import model
@@ -54,7 +49,7 @@ def encode_multipart(boundary, http_requests):
5449

5550
# request line (method + path + query params)
5651
line = f'{req.get_method()} {req.get_path()}'
57-
query_params = '&'.join(['{}={}'.format(key, val) for key, val in req.get_query_params().items()])
52+
query_params = urlencode(req.get_query_params())
5853
if query_params:
5954
line += '?' + query_params
6055
line += ' HTTP/1.1'
@@ -316,7 +311,7 @@ def execute(self):
316311
if body:
317312
self._logger.debug(' body: %s', body)
318313

319-
params = "&".join("%s=%s" % (k, v) for k, v in self.get_query_params().items())
314+
params = urlencode(self.get_query_params())
320315
response = self._connection.request(
321316
self.get_method(), url, headers=headers, params=params, data=body)
322317

@@ -1216,7 +1211,7 @@ def _build_expression(self, field_name, operator, value):
12161211
def __str__(self):
12171212
expressions = self._process_expressions()
12181213
result = self._combine_expressions(expressions)
1219-
return quote(result)
1214+
return result
12201215

12211216

12221217
class GetEntitySetRequest(QueryRequest):

tests/test_service_v2.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,25 @@ def test_function_import_primitive(service):
378378
assert result == 6
379379

380380

381+
@responses.activate
382+
def test_function_import_escape_parameter(service):
383+
"""Simple function call with special URL characters in parameter value"""
384+
385+
# pylint: disable=redefined-outer-name
386+
387+
responses.add(
388+
responses.GET,
389+
f"{service.url}/retrieve?Param=%27%26|%2B|%3D|%2F|%3F|+|%40%27",
390+
headers={'Content-type': 'application/json'},
391+
json={'d': True},
392+
status=200)
393+
394+
chars = "|".join("&+=/? @")
395+
result = service.functions.retrieve.parameter('Param', chars).execute()
396+
assert result is True
397+
398+
399+
381400
@responses.activate
382401
@patch('logging.Logger.warning')
383402
def test_function_import_primitive_unexpected_status_code(mock_warning, service):

0 commit comments

Comments
 (0)