Skip to content

Commit fd79135

Browse files
Merge pull request #638 from adamtheturtle/bad-image
Validate query image is not corrupted
2 parents 3221062 + d2f3e3c commit fd79135

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

src/mock_vws/_mock_web_query_api.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,60 @@ def validate_image_format(
8383
)
8484

8585

86+
@wrapt.decorator
87+
def validate_image_file_contents(
88+
wrapped: Callable[..., str],
89+
instance: Any, # pylint: disable=unused-argument
90+
args: Tuple[_RequestObjectProxy, _Context],
91+
kwargs: Dict,
92+
) -> str:
93+
"""
94+
Validate the format of the image given to the query endpoint.
95+
96+
Args:
97+
wrapped: An endpoint function for `requests_mock`.
98+
instance: The class that the endpoint function is in.
99+
args: The arguments given to the endpoint function.
100+
kwargs: The keyword arguments given to the endpoint function.
101+
102+
Returns:
103+
The result of calling the endpoint.
104+
An `UNPROCESSABLE_ENTITY` response if the image is given and is not
105+
either a PNG or a JPEG.
106+
"""
107+
request, context = args
108+
body_file = io.BytesIO(request.body)
109+
110+
_, pdict = cgi.parse_header(request.headers['Content-Type'])
111+
parsed = cgi.parse_multipart(
112+
fp=body_file,
113+
pdict={
114+
'boundary': pdict['boundary'].encode(),
115+
},
116+
)
117+
118+
[image] = parsed['image']
119+
120+
image_file = io.BytesIO(image)
121+
try:
122+
Image.open(image_file).verify()
123+
except SyntaxError:
124+
context.status_code = codes.UNPROCESSABLE_ENTITY
125+
transaction_id = uuid.uuid4().hex
126+
result_code = ResultCodes.BAD_IMAGE.value
127+
128+
# The response has an unusual format of separators, so we construct it
129+
# manually.
130+
return (
131+
'{"transaction_id": '
132+
f'"{transaction_id}",'
133+
f'"result_code":"{result_code}"'
134+
'}'
135+
)
136+
137+
return wrapped(*args, **kwargs)
138+
139+
86140
@wrapt.decorator
87141
def validate_date_header_given(
88142
wrapped: Callable[..., str],
@@ -476,6 +530,7 @@ def decorator(method: Callable[..., str]) -> Callable[..., str]:
476530
validate_date_header_given,
477531
validate_include_target_data,
478532
validate_max_num_results,
533+
validate_image_file_contents,
479534
validate_image_format,
480535
validate_image_field_given,
481536
validate_extra_fields,

tests/mock_vws/test_query.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,51 @@ def test_inactive(
10541054
assert response.json()['results'] == []
10551055

10561056

1057+
@pytest.mark.usefixtures('verify_mock_vuforia')
1058+
class TestBadImage:
1059+
"""
1060+
Tests for bad images.
1061+
"""
1062+
1063+
def test_corrupted(
1064+
self,
1065+
vuforia_database_keys: VuforiaDatabaseKeys,
1066+
png_rgb: io.BytesIO,
1067+
) -> None:
1068+
"""
1069+
A "BadImage" result is returned when a corrupted image is given.
1070+
"""
1071+
original_data = png_rgb.getvalue()
1072+
corrupted_data = original_data.replace(b'IEND', b'\x00' + b'IEND')
1073+
1074+
body = {'image': ('image.jpeg', corrupted_data, 'image/jpeg')}
1075+
1076+
response = query(
1077+
vuforia_database_keys=vuforia_database_keys,
1078+
body=body,
1079+
)
1080+
1081+
assert_vwq_failure(
1082+
response=response,
1083+
status_code=codes.UNPROCESSABLE_ENTITY,
1084+
content_type='application/json',
1085+
)
1086+
assert response.json().keys() == {'transaction_id', 'result_code'}
1087+
assert_valid_transaction_id(response=response)
1088+
assert_valid_date_header(response=response)
1089+
result_code = response.json()['result_code']
1090+
transaction_id = response.json()['transaction_id']
1091+
assert result_code == ResultCodes.BAD_IMAGE.value
1092+
# The separators are inconsistent and we test this.
1093+
expected_text = (
1094+
'{"transaction_id": '
1095+
f'"{transaction_id}",'
1096+
f'"result_code":"{result_code}"'
1097+
'}'
1098+
)
1099+
assert response.text == expected_text
1100+
1101+
10571102
@pytest.mark.usefixtures('verify_mock_vuforia')
10581103
class TestMaximumImageSize:
10591104
"""

0 commit comments

Comments
 (0)