Skip to content

Commit 5d61c7f

Browse files
committed
format
1 parent 8bcf06c commit 5d61c7f

File tree

4 files changed

+114
-40
lines changed

4 files changed

+114
-40
lines changed

api_app/analyzers_manager/classes.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ class DockerBasedAnalyzer(BaseAnalyzerMixin, metaclass=ABCMeta):
278278
poll_distance: int
279279
key_not_found_max_retries: int = 10
280280

281+
@staticmethod
282+
def __get_response_json(resp: requests.Response) -> dict:
283+
try:
284+
data = resp.json()
285+
except ValueError:
286+
return {}
287+
if isinstance(data, dict):
288+
return data
289+
return {}
290+
281291
@staticmethod
282292
def __raise_in_case_bad_request(name, resp, params_to_check=None) -> bool:
283293
"""
@@ -289,14 +299,15 @@ def __raise_in_case_bad_request(name, resp, params_to_check=None) -> bool:
289299
# different error messages for different cases
290300
if resp.status_code == 404:
291301
raise AnalyzerConfigurationException(f"{name} docker container is not running.")
302+
resp_json = DockerBasedAnalyzer.__get_response_json(resp)
292303
if resp.status_code == 400:
293-
err = resp.json().get("error", "")
304+
err = resp_json.get("error") or resp.text or "Bad Request"
294305
raise AnalyzerRunException(err)
295306
if resp.status_code == 500:
296307
raise AnalyzerRunException(f"Internal Server Error in {name} docker container")
297308
# check to make sure there was a valid params in response
298309
for param in params_to_check:
299-
param_value = resp.json().get(param, None)
310+
param_value = resp_json.get(param, None)
300311
if not param_value:
301312
raise AnalyzerRunException(
302313
f"Unexpected Error. Please check log files under /var/log/intel_owl/{name.lower()}/"
@@ -310,12 +321,12 @@ def __raise_in_case_bad_request(name, resp, params_to_check=None) -> bool:
310321
def __query_for_result(url: str, key: str) -> Tuple[int, dict]:
311322
headers = {"Accept": "application/json"}
312323
resp = requests.get(f"{url}?key={key}", headers=headers)
313-
return resp.status_code, resp.json()
324+
return resp.status_code, DockerBasedAnalyzer.__get_response_json(resp)
314325

315326
def __polling(self, req_key: str, chance: int, re_poll_try: int = 0):
316327
try:
317328
status_code, json_data = self.__query_for_result(self.url, req_key)
318-
except (requests.RequestException, json.JSONDecodeError) as e:
329+
except (requests.RequestException, ValueError) as e:
319330
raise AnalyzerRunException(e)
320331
if status_code == 404:
321332
# This happens when they key does not exist.
@@ -392,23 +403,31 @@ def _docker_run(
392403
try:
393404
if req_files:
394405
form_data = {"request_json": json.dumps(req_data)}
395-
resp1 = requests.post(self.url, files=req_files, data=form_data)
406+
normalized_files = {}
407+
for field_name, value in req_files.items():
408+
if isinstance(value, (bytes, bytearray)):
409+
normalized_files[field_name] = (field_name, value)
410+
else:
411+
normalized_files[field_name] = value
412+
resp1 = requests.post(self.url, files=normalized_files, data=form_data)
396413
else:
397414
resp1 = requests.post(self.url, json=req_data)
398415
except requests.exceptions.ConnectionError:
399416
self._raise_container_not_running()
400417

418+
resp1_json = DockerBasedAnalyzer.__get_response_json(resp1)
419+
401420
# step #2: raise AnalyzerRunException in case of error
402421
# Modified to support synchronous analyzers that return results directly in the initial response, avoiding unnecessary polling.
403422
if avoid_polling:
404-
report = resp1.json().get("report", None)
405-
err = resp1.json().get("error", None)
423+
report = resp1_json.get("report", None)
424+
err = resp1_json.get("error", None)
406425
else:
407426
if not self.__raise_in_case_bad_request(self.name, resp1):
408427
raise AssertionError
409428

410429
# step #3: if no error, continue and try to fetch result
411-
key = resp1.json().get("key")
430+
key = resp1_json.get("key")
412431
final_resp = self.__poll_for_result(key)
413432
err = final_resp.get("error", None)
414433
report = final_resp.get("report", None)

api_app/helpers.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,12 @@ def get_default_requests_timeout() -> tuple[float, float]:
9393
read_timeout_default = 30.0
9494

9595
try:
96-
connect_timeout = float(
97-
environ.get("INTELOWL_REQUESTS_CONNECT_TIMEOUT", connect_timeout_default)
98-
)
96+
connect_timeout = float(environ.get("INTELOWL_REQUESTS_CONNECT_TIMEOUT", connect_timeout_default))
9997
except (TypeError, ValueError):
10098
connect_timeout = connect_timeout_default
10199

102100
try:
103-
read_timeout = float(
104-
environ.get("INTELOWL_REQUESTS_READ_TIMEOUT", read_timeout_default)
105-
)
101+
read_timeout = float(environ.get("INTELOWL_REQUESTS_READ_TIMEOUT", read_timeout_default))
106102
except (TypeError, ValueError):
107103
read_timeout = read_timeout_default
108104

@@ -112,16 +108,16 @@ def get_default_requests_timeout() -> tuple[float, float]:
112108
def patch_requests_default_timeout() -> None:
113109
import requests
114110

115-
session_request = requests.sessions.Session.request
116-
if getattr(session_request, "_intelowl_default_timeout_patched", False):
111+
api_request = requests.api.request
112+
if getattr(api_request, "_intelowl_default_timeout_patched", False):
117113
return
118114

119-
@wraps(session_request)
120-
def request(self, method, url, **kwargs):
115+
@wraps(api_request)
116+
def wrapped(method, url, **kwargs):
121117
if "timeout" not in kwargs or kwargs["timeout"] is None:
122118
kwargs["timeout"] = get_default_requests_timeout()
123-
return request._intelowl_original(self, method, url, **kwargs)
119+
return wrapped._intelowl_original(method, url, **kwargs)
124120

125-
request._intelowl_default_timeout_patched = True
126-
request._intelowl_original = session_request
127-
requests.sessions.Session.request = request
121+
wrapped._intelowl_default_timeout_patched = True
122+
wrapped._intelowl_original = api_request
123+
requests.api.request = wrapped
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# This file is a part of IntelOwl https://github.com/intelowlproject/IntelOwl
2+
# See the file 'LICENSE' for copying permission.
3+
4+
from unittest.mock import patch
5+
6+
from django.test import SimpleTestCase
7+
from requests import Response
8+
9+
from api_app.analyzers_manager.classes import DockerBasedAnalyzer
10+
from api_app.analyzers_manager.exceptions import AnalyzerRunException
11+
12+
13+
class DockerBasedAnalyzerHttpErrorsTests(SimpleTestCase):
14+
def test_bad_request_with_non_json_body_raises_analyzer_run_exception(self):
15+
resp = Response()
16+
resp.status_code = 400
17+
resp._content = b""
18+
19+
with self.assertRaises(AnalyzerRunException):
20+
DockerBasedAnalyzer._DockerBasedAnalyzer__raise_in_case_bad_request(
21+
"StringsInfo",
22+
resp,
23+
)
24+
25+
def test_docker_run_normalizes_bytes_files_to_requests_file_tuples(self):
26+
captured = {}
27+
28+
class FakeResponse:
29+
status_code = 200
30+
text = ""
31+
32+
def json(self):
33+
return {"report": {"ok": True}}
34+
35+
def stub_post(url, files=None, data=None, **kwargs):
36+
captured["files"] = files
37+
captured["data"] = data
38+
return FakeResponse()
39+
40+
class Dummy:
41+
url = "http://example.com/analyze"
42+
name = "Dummy"
43+
44+
def __repr__(self):
45+
return "<Dummy>"
46+
47+
def _raise_container_not_running(self):
48+
raise AssertionError
49+
50+
with patch("api_app.analyzers_manager.classes.requests.post", side_effect=stub_post):
51+
result = DockerBasedAnalyzer._docker_run(
52+
Dummy(),
53+
req_data={"args": []},
54+
req_files={"sample.bin": b"123"},
55+
avoid_polling=True,
56+
)
57+
58+
self.assertEqual(result, {"ok": True})
59+
self.assertEqual(captured["files"]["sample.bin"], ("sample.bin", b"123"))

tests/api_app/test_requests_timeout.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,38 @@ def setUp(self):
1414
patch_requests_default_timeout()
1515

1616
def test_injects_default_timeout_when_missing(self):
17-
session_request = requests.sessions.Session.request
18-
original = session_request._intelowl_original
17+
api_request = requests.api.request
18+
original = api_request._intelowl_original
1919
captured = {}
2020

21-
def stub(self, method, url, **kwargs):
21+
def stub(method, url, **kwargs):
2222
captured["timeout"] = kwargs.get("timeout")
2323
return "ok"
2424

25-
session_request._intelowl_original = stub
25+
api_request._intelowl_original = stub
2626
try:
27-
result = requests.Session().request("GET", "http://example.com")
27+
result = requests.get("http://example.com")
2828
self.assertEqual(result, "ok")
2929
self.assertEqual(captured["timeout"], get_default_requests_timeout())
3030
finally:
31-
session_request._intelowl_original = original
31+
api_request._intelowl_original = original
3232

3333
def test_keeps_explicit_timeout(self):
34-
session_request = requests.sessions.Session.request
35-
original = session_request._intelowl_original
34+
api_request = requests.api.request
35+
original = api_request._intelowl_original
3636
captured = {}
3737

38-
def stub(self, method, url, **kwargs):
38+
def stub(method, url, **kwargs):
3939
captured["timeout"] = kwargs.get("timeout")
4040
return "ok"
4141

42-
session_request._intelowl_original = stub
42+
api_request._intelowl_original = stub
4343
try:
44-
result = requests.Session().request("GET", "http://example.com", timeout=5)
44+
result = requests.get("http://example.com", timeout=5)
4545
self.assertEqual(result, "ok")
4646
self.assertEqual(captured["timeout"], 5)
4747
finally:
48-
session_request._intelowl_original = original
48+
api_request._intelowl_original = original
4949

5050
def test_timeout_can_be_configured_via_env(self):
5151
old_connect = os.environ.get("INTELOWL_REQUESTS_CONNECT_TIMEOUT")
@@ -54,20 +54,20 @@ def test_timeout_can_be_configured_via_env(self):
5454
os.environ["INTELOWL_REQUESTS_READ_TIMEOUT"] = "2.5"
5555

5656
try:
57-
session_request = requests.sessions.Session.request
58-
original = session_request._intelowl_original
57+
api_request = requests.api.request
58+
original = api_request._intelowl_original
5959
captured = {}
6060

61-
def stub(self, method, url, **kwargs):
61+
def stub(method, url, **kwargs):
6262
captured["timeout"] = kwargs.get("timeout")
6363
return "ok"
6464

65-
session_request._intelowl_original = stub
65+
api_request._intelowl_original = stub
6666
try:
67-
requests.Session().request("GET", "http://example.com")
67+
requests.get("http://example.com")
6868
self.assertEqual(captured["timeout"], (1.5, 2.5))
6969
finally:
70-
session_request._intelowl_original = original
70+
api_request._intelowl_original = original
7171
finally:
7272
if old_connect is None:
7373
os.environ.pop("INTELOWL_REQUESTS_CONNECT_TIMEOUT", None)

0 commit comments

Comments
 (0)