Skip to content

Commit 69834eb

Browse files
authored
fix: Fix JSON response validation retry strategy (#831)
1 parent 6efa3ec commit 69834eb

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

boxsdk/session/session.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,8 @@ def _raise_on_unsuccessful_request(network_response: 'NetworkResponse', request:
279279
context_info=response_json.get('context_info', None),
280280
network_response=network_response
281281
)
282-
if request.expect_json_response and not is_json_response(network_response):
282+
283+
if not Session._is_json_response_if_expected(network_response, request):
283284
raise BoxAPIException(
284285
status=network_response.status_code,
285286
headers=network_response.headers,
@@ -289,6 +290,18 @@ def _raise_on_unsuccessful_request(network_response: 'NetworkResponse', request:
289290
network_response=network_response,
290291
)
291292

293+
@staticmethod
294+
def _is_json_response_if_expected(network_response: 'NetworkResponse', request: '_BoxRequest') -> bool:
295+
"""
296+
Validate that the response is json if the request expects json response.
297+
298+
:param network_response:
299+
The network response which is being tested for success.
300+
:param request:
301+
The API request that could be unsuccessful.
302+
"""
303+
return not request.expect_json_response or is_json_response(network_response)
304+
292305
def _prepare_and_send_request(
293306
self,
294307
method: str,
@@ -391,13 +404,15 @@ def _get_retry_request_callable(
391404
Callable that, when called, will retry the request. Takes the same parameters as :meth:`_send_request`.
392405
"""
393406
# pylint:disable=unused-argument
394-
if network_response is None:
407+
# pylint:disable=line-too-long
408+
if network_response is None or (network_response.ok and request.method == 'GET' and not self._is_json_response_if_expected(network_response, request)):
395409
return partial(
396410
self._network_layer.retry_after,
397411
self.get_retry_after_time(attempt_number, None),
398412
self._send_request,
399413
)
400414
code = network_response.status_code
415+
401416
if (code in (202, 429) or code >= 500) and code not in skip_retry_codes and not self._is_server_auth_type(kwargs):
402417
return partial(
403418
self._network_layer.retry_after,
@@ -541,6 +556,7 @@ def _get_retry_request_callable(
541556
self._renew_session(request.access_token)
542557
request.auto_session_renewal = False
543558
return self._send_request
559+
544560
return super()._get_retry_request_callable(
545561
network_response,
546562
attempt_number,

test/unit/session/test_session.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,18 @@ def test_box_session_seeks_file_after_retry(box_session, mock_network_layer, ser
221221
assert mock_file_2.seek.has_calls(call(3) * 2)
222222

223223

224-
def test_box_session_raises_for_non_json_response(box_session, mock_network_layer, non_json_response, test_url):
224+
def test_box_session_raises_for_non_json_response(box_session, mock_network_layer, non_json_response, generic_successful_response, test_url):
225225
# pylint:disable=redefined-outer-name
226-
mock_network_layer.request.side_effect = [non_json_response]
226+
mock_network_layer.request.side_effect = [non_json_response, generic_successful_response]
227+
mock_network_layer.retry_after.side_effect = lambda delay, request, *args, **kwargs: request(*args, **kwargs)
228+
229+
box_session.get(url=test_url)
230+
231+
232+
def test_box_session_raises_for_non_json_response_after_retry(box_session, mock_network_layer, non_json_response, test_url):
233+
# pylint:disable=redefined-outer-name
234+
mock_network_layer.request.side_effect = [non_json_response] * (API.MAX_RETRY_ATTEMPTS + 1)
235+
mock_network_layer.retry_after.side_effect = lambda delay, request, *args, **kwargs: request(*args, **kwargs)
227236

228237
with pytest.raises(BoxAPIException):
229238
box_session.get(url=test_url)

0 commit comments

Comments
 (0)