httpdbg 0.31.6__tar.gz → 0.32.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {httpdbg-0.31.6 → httpdbg-0.32.0}/PKG-INFO +1 -1
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/__init__.py +1 -1
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/env.py +1 -1
- httpdbg-0.32.0/httpdbg/hooks/external.py +80 -0
- httpdbg-0.32.0/httpdbg/hooks/template_sitecustomize.py +65 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/mode_script.py +15 -13
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/PKG-INFO +1 -1
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/SOURCES.txt +2 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_mode_script.py +2 -2
- httpdbg-0.32.0/tests/test_multiprocess.py +52 -0
- httpdbg-0.31.6/httpdbg/hooks/external.py +0 -61
- {httpdbg-0.31.6 → httpdbg-0.32.0}/LICENSE +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/README.md +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/__main__.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/args.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/exception.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/__init__.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/aiohttp.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/all.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/generic.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/httpx.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/pytest.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/requests.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/socket.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/unittest.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/urllib3.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/hooks/utils.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/initiator.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/log.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/mode_console.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/mode_module.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/preview.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/records.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/server.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/utils.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/__init__.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/api.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/app.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/api.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/column.css +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/configuration.css +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/configuration.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/detail.css +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/favicon.ico +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/filter.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/eye-blind-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/eye-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/lock-line-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/lock-open-line-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/index.htm +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/main.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/mustache.min.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/render.js +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/style.css +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/table.css +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/dependency_links.txt +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/entry_points.txt +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/requires.txt +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg.egg-info/top_level.txt +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/pyproject.toml +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/setup.cfg +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_api.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_cli.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_context_manager.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_aiohttp.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_httpx.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_pytest.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_requests.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_unittest.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_hook_urllib3.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_initiator.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_mode_console.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_mode_module_pytest.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_preview.py +0 -0
- {httpdbg-0.31.6 → httpdbg-0.32.0}/tests/test_server.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
HTTPDBG_CURRENT_GROUP = "HTTPDBG_CURRENT_GROUP"
|
|
2
2
|
HTTPDBG_CURRENT_INITIATOR = "HTTPDBG_CURRENT_INITIATOR"
|
|
3
3
|
HTTPDBG_CURRENT_TAG = "HTTPDBG_CURRENT_TAG"
|
|
4
|
-
|
|
4
|
+
HTTPDBG_MULTIPROCESS_DIR = "HTTPDBG_MULTIPROCESS_DIR"
|
|
5
5
|
|
|
6
6
|
HTTPDBG_LOG_LEVEL = "HTTPDBG_LOG_LEVEL"
|
|
7
7
|
HTTPDBG_LOG_PATH = "HTTPDBG_LOG_PATH"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from typing import Generator
|
|
4
|
+
import glob
|
|
5
|
+
import os
|
|
6
|
+
import pickle
|
|
7
|
+
import shutil
|
|
8
|
+
import tempfile
|
|
9
|
+
import time
|
|
10
|
+
import threading
|
|
11
|
+
|
|
12
|
+
from httpdbg.env import HTTPDBG_MULTIPROCESS_DIR
|
|
13
|
+
from httpdbg.log import logger
|
|
14
|
+
from httpdbg.records import HTTPRecords
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@contextmanager
|
|
18
|
+
def watcher_external(records: HTTPRecords) -> Generator[HTTPRecords, None, None]:
|
|
19
|
+
if HTTPDBG_MULTIPROCESS_DIR not in os.environ:
|
|
20
|
+
with tempfile.TemporaryDirectory(prefix="httpdbg_") as httpdbg_multiprocess_dir:
|
|
21
|
+
|
|
22
|
+
logger().info(f"watcher_external {httpdbg_multiprocess_dir}")
|
|
23
|
+
os.environ[HTTPDBG_MULTIPROCESS_DIR] = httpdbg_multiprocess_dir
|
|
24
|
+
|
|
25
|
+
# we use a custom sitecustomize.py script to record the request in the subprocesses.
|
|
26
|
+
# It doesn't work if the subprocess is created using the "fork" method
|
|
27
|
+
# instead of the "spawn" method.
|
|
28
|
+
template = os.path.join(
|
|
29
|
+
os.path.dirname(os.path.abspath(__file__)),
|
|
30
|
+
"template_sitecustomize.py",
|
|
31
|
+
)
|
|
32
|
+
sitecustomize = os.path.join(httpdbg_multiprocess_dir, "sitecustomize.py")
|
|
33
|
+
|
|
34
|
+
shutil.copy(template, sitecustomize)
|
|
35
|
+
|
|
36
|
+
if "PYTHONPATH" in os.environ:
|
|
37
|
+
os.environ["PYTHONPATH"] = (
|
|
38
|
+
f"{httpdbg_multiprocess_dir}:{os.environ['PYTHONPATH']}"
|
|
39
|
+
)
|
|
40
|
+
else:
|
|
41
|
+
os.environ["PYTHONPATH"] = httpdbg_multiprocess_dir
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
watcher = WatcherSubprocessDirThread(
|
|
45
|
+
records, httpdbg_multiprocess_dir, 1.0
|
|
46
|
+
)
|
|
47
|
+
watcher.start()
|
|
48
|
+
|
|
49
|
+
yield records
|
|
50
|
+
finally:
|
|
51
|
+
watcher.shutdown()
|
|
52
|
+
else:
|
|
53
|
+
yield records
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class WatcherSubprocessDirThread(threading.Thread):
|
|
57
|
+
def __init__(self, records: HTTPRecords, directory: str, delay: float) -> None:
|
|
58
|
+
self.records: HTTPRecords = records
|
|
59
|
+
self.directory: str = directory
|
|
60
|
+
self.delay: float = delay
|
|
61
|
+
self._running: bool = True
|
|
62
|
+
threading.Thread.__init__(self)
|
|
63
|
+
|
|
64
|
+
def load_dump(self):
|
|
65
|
+
for dump in glob.glob(os.path.join(self.directory, "*.httpdbgrecords")):
|
|
66
|
+
with open(dump, "rb") as dumpfile:
|
|
67
|
+
newrecords: HTTPRecords = pickle.load(dumpfile)
|
|
68
|
+
self.records.requests.update(newrecords.requests)
|
|
69
|
+
self.records.initiators.update(newrecords.initiators)
|
|
70
|
+
self.records.groups.update(newrecords.groups)
|
|
71
|
+
|
|
72
|
+
def run(self):
|
|
73
|
+
while self._running:
|
|
74
|
+
self.load_dump()
|
|
75
|
+
time.sleep(self.delay)
|
|
76
|
+
|
|
77
|
+
def shutdown(self):
|
|
78
|
+
self._running = False
|
|
79
|
+
self.join(timeout=5)
|
|
80
|
+
self.load_dump()
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import os
|
|
3
|
+
import pickle
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
import threading
|
|
7
|
+
from typing import Union
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
from httpdbg.hooks.all import httprecord
|
|
11
|
+
from httpdbg import HTTPRecords
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HttpdbgRecorder:
|
|
15
|
+
"""Records the HTTP requests in subprocesses and saves them to disk."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self._running: bool = False
|
|
19
|
+
self.fname: str = os.path.join(
|
|
20
|
+
os.environ["HTTPDBG_MULTIPROCESS_DIR"], str(uuid.uuid1())
|
|
21
|
+
)
|
|
22
|
+
self.context = None
|
|
23
|
+
self.records: Union[HTTPRecords, None] = None
|
|
24
|
+
|
|
25
|
+
def _save_to_disk_loop(self):
|
|
26
|
+
while self._running:
|
|
27
|
+
self.save_to_disk()
|
|
28
|
+
time.sleep(1)
|
|
29
|
+
|
|
30
|
+
def save_to_disk(self):
|
|
31
|
+
if self.records and len(self.records.requests) > 0:
|
|
32
|
+
with open(f"{self.fname}.httpdbgrecords.tmp", "wb") as f:
|
|
33
|
+
pickle.dump(self.records, f)
|
|
34
|
+
os.replace(
|
|
35
|
+
f"{self.fname}.httpdbgrecords.tmp", f"{self.fname}.httpdbgrecords"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def start(self):
|
|
39
|
+
"""Start recording."""
|
|
40
|
+
self.context = httprecord()
|
|
41
|
+
self.records = self.context.__enter__()
|
|
42
|
+
self._running = True
|
|
43
|
+
self._thread = threading.Thread(target=self._save_to_disk_loop, daemon=True)
|
|
44
|
+
self._thread.start()
|
|
45
|
+
|
|
46
|
+
def stop(self):
|
|
47
|
+
"""Stop recording."""
|
|
48
|
+
self._running = False
|
|
49
|
+
if self._thread:
|
|
50
|
+
self._thread.join(timeout=5)
|
|
51
|
+
self.save_to_disk()
|
|
52
|
+
if self.context:
|
|
53
|
+
self.context.__exit__(None, None, None)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if "HTTPDBG_MULTIPROCESS_DIR" in os.environ:
|
|
57
|
+
|
|
58
|
+
if not hasattr(sys, "_httpdbg_enabled"):
|
|
59
|
+
sys._httpdbg_enabled = True # type: ignore[attr-defined]
|
|
60
|
+
|
|
61
|
+
# start recording when the process starts and stop it when process exists
|
|
62
|
+
httprecorder = HttpdbgRecorder()
|
|
63
|
+
httprecorder.start()
|
|
64
|
+
|
|
65
|
+
atexit.register(httprecorder.stop)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
import
|
|
2
|
+
import os
|
|
3
|
+
import runpy
|
|
3
4
|
import sys
|
|
4
5
|
import traceback
|
|
5
6
|
from typing import List
|
|
@@ -8,24 +9,25 @@ from httpdbg.log import logger
|
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def run_script(argv: List[str]) -> None:
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
if len(argv) == 0:
|
|
13
14
|
exit("script mode - error - python file required, but none set")
|
|
15
|
+
|
|
14
16
|
try:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
spec.loader.exec_module(module) # type: ignore
|
|
23
|
-
except Exception:
|
|
24
|
-
traceback.print_exc()
|
|
17
|
+
original_sys_path = sys.path
|
|
18
|
+
original_sys_argv = sys.argv
|
|
19
|
+
|
|
20
|
+
sys.path.insert(0, os.path.abspath(argv[0]))
|
|
21
|
+
sys.argv = argv
|
|
22
|
+
|
|
23
|
+
runpy.run_path(argv[0], run_name="__main__")
|
|
25
24
|
except SystemExit as ex:
|
|
26
25
|
# in some case, for example when executing unittest tests from a script,
|
|
27
26
|
# the SystemExit exception is raised by the script itself so we catch it.
|
|
28
27
|
# TODO propagate the SystemExit value when httpdbg terminates.
|
|
29
28
|
logger().info(f"run_script - exception SystemExit - {str(ex)}")
|
|
29
|
+
except Exception:
|
|
30
|
+
traceback.print_exc()
|
|
30
31
|
finally:
|
|
31
|
-
sys.
|
|
32
|
+
sys.path = original_sys_path
|
|
33
|
+
sys.argv = original_sys_argv
|
|
@@ -31,6 +31,7 @@ httpdbg/hooks/httpx.py
|
|
|
31
31
|
httpdbg/hooks/pytest.py
|
|
32
32
|
httpdbg/hooks/requests.py
|
|
33
33
|
httpdbg/hooks/socket.py
|
|
34
|
+
httpdbg/hooks/template_sitecustomize.py
|
|
34
35
|
httpdbg/hooks/unittest.py
|
|
35
36
|
httpdbg/hooks/urllib3.py
|
|
36
37
|
httpdbg/hooks/utils.py
|
|
@@ -78,5 +79,6 @@ tests/test_initiator.py
|
|
|
78
79
|
tests/test_mode_console.py
|
|
79
80
|
tests/test_mode_module_pytest.py
|
|
80
81
|
tests/test_mode_script.py
|
|
82
|
+
tests/test_multiprocess.py
|
|
81
83
|
tests/test_preview.py
|
|
82
84
|
tests/test_server.py
|
|
@@ -67,8 +67,8 @@ def test_run_script_no_args(httpbin, capsys):
|
|
|
67
67
|
|
|
68
68
|
@pytest.mark.script
|
|
69
69
|
def test_run_script_not_a_python_script(httpbin, capsys):
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
# should not raise an exception
|
|
71
|
+
run_script(["not_a_path_to_a_python_script"])
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
@pytest.mark.api
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from httpdbg import httprecord
|
|
7
|
+
from httpdbg.env import HTTPDBG_MULTIPROCESS_DIR
|
|
8
|
+
from httpdbg.mode_script import run_script
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.mark.script
|
|
12
|
+
def test_run_script_multithread(httpbin):
|
|
13
|
+
|
|
14
|
+
if HTTPDBG_MULTIPROCESS_DIR in os.environ:
|
|
15
|
+
del os.environ[HTTPDBG_MULTIPROCESS_DIR]
|
|
16
|
+
|
|
17
|
+
with httprecord() as records:
|
|
18
|
+
os.environ["HTTPDBG_TEST_MULTITHREAD_BASE_URL"] = httpbin.url
|
|
19
|
+
script_to_run = os.path.join(
|
|
20
|
+
os.path.dirname(os.path.realpath(__file__)), "demo_run_multithread.py"
|
|
21
|
+
)
|
|
22
|
+
run_script([script_to_run, httpbin.url])
|
|
23
|
+
|
|
24
|
+
assert len(records) == 3
|
|
25
|
+
pids = []
|
|
26
|
+
for record in records:
|
|
27
|
+
pids.append(record.url.split("/")[-1])
|
|
28
|
+
assert len(set(pids)) == 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.script
|
|
32
|
+
@pytest.mark.xfail(
|
|
33
|
+
platform.system().lower() == "windows",
|
|
34
|
+
reason="the test fails on the CI but the feature works on windows",
|
|
35
|
+
)
|
|
36
|
+
def test_run_script_multiprocess(httpbin):
|
|
37
|
+
|
|
38
|
+
if HTTPDBG_MULTIPROCESS_DIR in os.environ:
|
|
39
|
+
del os.environ[HTTPDBG_MULTIPROCESS_DIR]
|
|
40
|
+
|
|
41
|
+
with httprecord() as records:
|
|
42
|
+
os.environ["HTTPDBG_TEST_MULTIPROCESS_BASE_URL"] = httpbin.url
|
|
43
|
+
script_to_run = os.path.join(
|
|
44
|
+
os.path.dirname(os.path.realpath(__file__)), "demo_run_multiprocess.py"
|
|
45
|
+
)
|
|
46
|
+
run_script([script_to_run, httpbin.url])
|
|
47
|
+
|
|
48
|
+
assert len(records) == 3
|
|
49
|
+
pids = []
|
|
50
|
+
for record in records:
|
|
51
|
+
pids.append(record.url.split("/")[-1])
|
|
52
|
+
assert len(set(pids)) == 3
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from contextlib import contextmanager
|
|
3
|
-
from typing import Generator
|
|
4
|
-
import glob
|
|
5
|
-
import os
|
|
6
|
-
import pickle
|
|
7
|
-
import tempfile
|
|
8
|
-
import time
|
|
9
|
-
import threading
|
|
10
|
-
|
|
11
|
-
from httpdbg.env import HTTPDBG_SUBPROCESS_DIR
|
|
12
|
-
from httpdbg.records import HTTPRecords
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@contextmanager
|
|
16
|
-
def watcher_external(records: HTTPRecords) -> Generator[HTTPRecords, None, None]:
|
|
17
|
-
try:
|
|
18
|
-
watcher = None
|
|
19
|
-
if HTTPDBG_SUBPROCESS_DIR not in os.environ:
|
|
20
|
-
with tempfile.TemporaryDirectory(
|
|
21
|
-
prefix="httpdbg"
|
|
22
|
-
) as httpdbg_subprocess_dir:
|
|
23
|
-
os.environ[HTTPDBG_SUBPROCESS_DIR] = httpdbg_subprocess_dir
|
|
24
|
-
|
|
25
|
-
watcher = WatcherSubprocessDirThread(records)
|
|
26
|
-
watcher.start()
|
|
27
|
-
|
|
28
|
-
yield records
|
|
29
|
-
|
|
30
|
-
watcher.shutdown()
|
|
31
|
-
watcher.join()
|
|
32
|
-
else:
|
|
33
|
-
yield records
|
|
34
|
-
except Exception as ex:
|
|
35
|
-
if watcher:
|
|
36
|
-
watcher.shutdown()
|
|
37
|
-
raise ex
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class WatcherSubprocessDirThread(threading.Thread):
|
|
41
|
-
def __init__(self, records: HTTPRecords, delay: int = 2) -> None:
|
|
42
|
-
self.stop = False
|
|
43
|
-
self.records = records
|
|
44
|
-
self.delay = delay
|
|
45
|
-
threading.Thread.__init__(self)
|
|
46
|
-
|
|
47
|
-
def load_dump(self):
|
|
48
|
-
for dump in glob.glob(f"{os.environ[HTTPDBG_SUBPROCESS_DIR]}/*.httpdbgrecords"):
|
|
49
|
-
with open(dump, "rb") as dumpfile:
|
|
50
|
-
newrecords: HTTPRecords = pickle.load(dumpfile)
|
|
51
|
-
self.records.requests.update(newrecords.requests)
|
|
52
|
-
self.records.initiators.update(newrecords.initiators)
|
|
53
|
-
self.records.groups.update(newrecords.groups)
|
|
54
|
-
|
|
55
|
-
def run(self):
|
|
56
|
-
while not self.stop:
|
|
57
|
-
time.sleep(self.delay)
|
|
58
|
-
self.load_dump()
|
|
59
|
-
|
|
60
|
-
def shutdown(self):
|
|
61
|
-
self.stop = True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg
RENAMED
|
File without changes
|
{httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/download-install-line-icon.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{httpdbg-0.31.6 → httpdbg-0.32.0}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|