Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 4 additions & 9 deletions pyodata/v2/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@
from email.parser import Parser
from http.client import HTTPResponse
from io import BytesIO
from urllib.parse import urlencode

try:
# For Python 3.0 and later
from urllib.parse import quote
except ImportError:
# Fallback to urllib2
from urllib2 import quote

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

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

params = "&".join("%s=%s" % (k, v) for k, v in self.get_query_params().items())
params = urlencode(self.get_query_params())
response = self._connection.request(
self.get_method(), url, headers=headers, params=params, data=body)

Expand Down Expand Up @@ -1216,7 +1211,7 @@ def _build_expression(self, field_name, operator, value):
def __str__(self):
expressions = self._process_expressions()
result = self._combine_expressions(expressions)
return quote(result)
return result


class GetEntitySetRequest(QueryRequest):
Expand Down
19 changes: 19 additions & 0 deletions tests/test_service_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,25 @@ def test_function_import_primitive(service):
assert result == 6


@responses.activate
def test_function_import_escape_parameter(service):
"""Simple function call with special URL characters in parameter value"""

# pylint: disable=redefined-outer-name

responses.add(
responses.GET,
f"{service.url}/retrieve?Param=%27%26|%2B|%3D|%2F|%3F|+|%40%27",
headers={'Content-type': 'application/json'},
json={'d': True},
status=200)

chars = "|".join("&+=/? @")
result = service.functions.retrieve.parameter('Param', chars).execute()
assert result is True



@responses.activate
@patch('logging.Logger.warning')
def test_function_import_primitive_unexpected_status_code(mock_warning, service):
Expand Down