httpdbg 0.29.0__tar.gz → 0.29.2__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.29.0 → httpdbg-0.29.2}/PKG-INFO +1 -1
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/__init__.py +1 -1
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/__main__.py +1 -1
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/aiohttp.py +5 -4
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/httpx.py +10 -8
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/requests.py +5 -4
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/urllib3.py +5 -4
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/initiator.py +28 -17
- httpdbg-0.29.2/httpdbg/mode_console.py +81 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/records.py +3 -2
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/api.py +6 -1
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/api.js +1 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/index.htm +2 -2
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/PKG-INFO +1 -1
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_mode_console.py +29 -1
- httpdbg-0.29.0/httpdbg/mode_console.py +0 -37
- {httpdbg-0.29.0 → httpdbg-0.29.2}/LICENSE +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/README.md +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/args.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/env.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/exception.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/__init__.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/all.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/external.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/generic.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/pytest.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/socket.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/hooks/utils.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/log.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/mode_module.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/mode_script.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/preview.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/server.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/utils.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/__init__.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/app.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/column.css +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/configuration.js +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/detail.css +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/favicon.ico +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/filter.js +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/information-mark-circle-outline-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/main.js +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/mustache.min.js +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/render.js +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/style.css +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/table.css +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/SOURCES.txt +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/dependency_links.txt +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/entry_points.txt +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/requires.txt +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/httpdbg.egg-info/top_level.txt +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/pyproject.toml +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/setup.cfg +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_api.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_cli.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_context_manager.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_hook_aiohttp.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_hook_httpx.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_hook_requests.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_hook_urllib3.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_initiator.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_mode_module_pytest.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_mode_script.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_preview.py +0 -0
- {httpdbg-0.29.0 → httpdbg-0.29.2}/tests/test_server.py +0 -0
|
@@ -35,7 +35,7 @@ def pyhttpdbg(params, subparams, test_mode=False):
|
|
|
35
35
|
elif params.script:
|
|
36
36
|
run_script(subparams)
|
|
37
37
|
else:
|
|
38
|
-
run_console(test_mode)
|
|
38
|
+
run_console(records, test_mode)
|
|
39
39
|
|
|
40
40
|
if not (params.force_quit or test_mode):
|
|
41
41
|
print_msg(f" httpdbg - HTTP(S) requests available at {url}")
|
|
@@ -13,20 +13,21 @@ from httpdbg.records import HTTPRecords
|
|
|
13
13
|
|
|
14
14
|
def set_hook_for_aiohttp_async(records: HTTPRecords, method: Callable):
|
|
15
15
|
async def hook(*args, **kwargs):
|
|
16
|
-
|
|
16
|
+
initiator_and_group = None
|
|
17
17
|
try:
|
|
18
18
|
with httpdbg_initiator(
|
|
19
19
|
records, traceback.extract_stack(), method, *args, **kwargs
|
|
20
|
-
) as
|
|
20
|
+
) as initiator_and_group:
|
|
21
21
|
ret = await method(*args, **kwargs)
|
|
22
22
|
return ret
|
|
23
23
|
except Exception as ex:
|
|
24
24
|
callargs = getcallargs(method, *args, **kwargs)
|
|
25
25
|
|
|
26
26
|
if "str_or_url" in callargs:
|
|
27
|
-
if
|
|
27
|
+
if initiator_and_group:
|
|
28
|
+
initiator, group = initiator_and_group
|
|
28
29
|
records.add_new_record_exception(
|
|
29
|
-
initiator, str(callargs["str_or_url"]), ex
|
|
30
|
+
initiator, group, str(callargs["str_or_url"]), ex
|
|
30
31
|
)
|
|
31
32
|
raise
|
|
32
33
|
|
|
@@ -13,20 +13,21 @@ from httpdbg.records import HTTPRecords
|
|
|
13
13
|
|
|
14
14
|
def set_hook_for_httpx_async(records: HTTPRecords, method: Callable):
|
|
15
15
|
async def hook(*args, **kwargs):
|
|
16
|
-
|
|
16
|
+
initiator_and_group = None
|
|
17
17
|
try:
|
|
18
18
|
with httpdbg_initiator(
|
|
19
19
|
records, traceback.extract_stack(), method, *args, **kwargs
|
|
20
|
-
) as
|
|
20
|
+
) as initiator_and_group:
|
|
21
21
|
ret = await method(*args, **kwargs)
|
|
22
22
|
return ret
|
|
23
23
|
except Exception as ex:
|
|
24
24
|
callargs = getcallargs(method, *args, **kwargs)
|
|
25
25
|
|
|
26
26
|
if "url" in callargs:
|
|
27
|
-
if
|
|
27
|
+
if initiator_and_group:
|
|
28
|
+
initiator, group = initiator_and_group
|
|
28
29
|
records.add_new_record_exception(
|
|
29
|
-
initiator, str(callargs["url"]), ex
|
|
30
|
+
initiator, group, str(callargs["url"]), ex
|
|
30
31
|
)
|
|
31
32
|
raise
|
|
32
33
|
|
|
@@ -35,20 +36,21 @@ def set_hook_for_httpx_async(records: HTTPRecords, method: Callable):
|
|
|
35
36
|
|
|
36
37
|
def set_hook_for_httpx(records: HTTPRecords, method: Callable):
|
|
37
38
|
def hook(*args, **kwargs):
|
|
38
|
-
|
|
39
|
+
initiator_and_group = None
|
|
39
40
|
try:
|
|
40
41
|
with httpdbg_initiator(
|
|
41
42
|
records, traceback.extract_stack(), method, *args, **kwargs
|
|
42
|
-
) as
|
|
43
|
+
) as initiator_and_group:
|
|
43
44
|
ret = method(*args, **kwargs)
|
|
44
45
|
return ret
|
|
45
46
|
except Exception as ex:
|
|
46
47
|
callargs = getcallargs(method, *args, **kwargs)
|
|
47
48
|
|
|
48
49
|
if "url" in callargs:
|
|
49
|
-
if
|
|
50
|
+
if initiator_and_group:
|
|
51
|
+
initiator, group = initiator_and_group
|
|
50
52
|
records.add_new_record_exception(
|
|
51
|
-
initiator, str(callargs["url"]), ex
|
|
53
|
+
initiator, group, str(callargs["url"]), ex
|
|
52
54
|
)
|
|
53
55
|
raise
|
|
54
56
|
|
|
@@ -13,20 +13,21 @@ from httpdbg.records import HTTPRecords
|
|
|
13
13
|
|
|
14
14
|
def set_hook_for_requests(records: HTTPRecords, method: Callable):
|
|
15
15
|
def hook(*args, **kwargs):
|
|
16
|
-
|
|
16
|
+
initiator_and_group = None
|
|
17
17
|
try:
|
|
18
18
|
with httpdbg_initiator(
|
|
19
19
|
records, traceback.extract_stack(), method, *args, **kwargs
|
|
20
|
-
) as
|
|
20
|
+
) as initiator_and_group:
|
|
21
21
|
ret = method(*args, **kwargs)
|
|
22
22
|
return ret
|
|
23
23
|
except Exception as ex:
|
|
24
24
|
callargs = getcallargs(method, *args, **kwargs)
|
|
25
25
|
|
|
26
26
|
if "url" in callargs:
|
|
27
|
-
if
|
|
27
|
+
if initiator_and_group:
|
|
28
|
+
initiator, group = initiator_and_group
|
|
28
29
|
records.add_new_record_exception(
|
|
29
|
-
initiator, str(callargs["url"]), ex
|
|
30
|
+
initiator, group, str(callargs["url"]), ex
|
|
30
31
|
)
|
|
31
32
|
raise
|
|
32
33
|
|
|
@@ -13,20 +13,21 @@ from httpdbg.records import HTTPRecords
|
|
|
13
13
|
|
|
14
14
|
def set_hook_for_urllib3(records: HTTPRecords, method: Callable):
|
|
15
15
|
def hook(*args, **kwargs):
|
|
16
|
-
|
|
16
|
+
initiator_and_group = None
|
|
17
17
|
try:
|
|
18
18
|
with httpdbg_initiator(
|
|
19
19
|
records, traceback.extract_stack(), method, *args, **kwargs
|
|
20
|
-
) as
|
|
20
|
+
) as initiator_and_group:
|
|
21
21
|
ret = method(*args, **kwargs)
|
|
22
22
|
return ret
|
|
23
23
|
except Exception as ex:
|
|
24
24
|
callargs = getcallargs(method, *args, **kwargs)
|
|
25
25
|
|
|
26
26
|
if "url" in callargs:
|
|
27
|
-
if
|
|
27
|
+
if initiator_and_group:
|
|
28
|
+
initiator, group = initiator_and_group
|
|
28
29
|
records.add_new_record_exception(
|
|
29
|
-
initiator, str(callargs["url"]), ex
|
|
30
|
+
initiator, group, str(callargs["url"]), ex
|
|
30
31
|
)
|
|
31
32
|
raise
|
|
32
33
|
|
|
@@ -23,12 +23,11 @@ from httpdbg.log import logger
|
|
|
23
23
|
class Initiator:
|
|
24
24
|
def __init__(
|
|
25
25
|
self,
|
|
26
|
-
id: str,
|
|
27
26
|
label: str,
|
|
28
27
|
short_stack: str,
|
|
29
28
|
stack: List[str],
|
|
30
29
|
):
|
|
31
|
-
self.id =
|
|
30
|
+
self.id = get_new_uuid()
|
|
32
31
|
self.label = label
|
|
33
32
|
self.short_stack = short_stack
|
|
34
33
|
self.stack = stack
|
|
@@ -61,10 +60,10 @@ class Initiator:
|
|
|
61
60
|
|
|
62
61
|
|
|
63
62
|
class Group:
|
|
64
|
-
def __init__(self,
|
|
65
|
-
self.id =
|
|
66
|
-
self.label = label
|
|
67
|
-
self.full_label = full_label
|
|
63
|
+
def __init__(self, label: str, full_label: str):
|
|
64
|
+
self.id: str = get_new_uuid()
|
|
65
|
+
self.label: str = label
|
|
66
|
+
self.full_label: str = full_label
|
|
68
67
|
|
|
69
68
|
def to_json(self) -> dict:
|
|
70
69
|
return {"id": self.id, "label": self.label, "full_label": self.full_label}
|
|
@@ -195,7 +194,7 @@ def extract_short_stack_from_file(
|
|
|
195
194
|
@contextmanager
|
|
196
195
|
def httpdbg_initiator(
|
|
197
196
|
records, extracted_stack: traceback.StackSummary, original_method, *args, **kwargs
|
|
198
|
-
) -> Generator[Union[Initiator, None], None, None]:
|
|
197
|
+
) -> Generator[Union[Tuple[Initiator, Group], None], None, None]:
|
|
199
198
|
envname = f"{HTTPDBG_CURRENT_INITIATOR}_{records.id}"
|
|
200
199
|
|
|
201
200
|
if not os.environ.get(envname):
|
|
@@ -215,7 +214,7 @@ def httpdbg_initiator(
|
|
|
215
214
|
short_stack += f" {k}={v}\n"
|
|
216
215
|
short_stack += ")"
|
|
217
216
|
|
|
218
|
-
current_initiator = Initiator(
|
|
217
|
+
current_initiator = Initiator(instruction, short_stack, stack)
|
|
219
218
|
records.initiators[current_initiator.id] = current_initiator
|
|
220
219
|
|
|
221
220
|
os.environ[envname] = current_initiator.id
|
|
@@ -223,8 +222,8 @@ def httpdbg_initiator(
|
|
|
223
222
|
try:
|
|
224
223
|
with httpdbg_group(
|
|
225
224
|
records, instruction, short_stack
|
|
226
|
-
): # by default we group the requests by initiator
|
|
227
|
-
yield current_initiator
|
|
225
|
+
) as group: # by default we group the requests by initiator
|
|
226
|
+
yield current_initiator, group
|
|
228
227
|
except Exception:
|
|
229
228
|
del os.environ[envname]
|
|
230
229
|
raise
|
|
@@ -258,21 +257,33 @@ def httpdbg_tag(tag: str) -> Generator[None, None, None]:
|
|
|
258
257
|
@contextmanager
|
|
259
258
|
def httpdbg_group(
|
|
260
259
|
records: "HTTPRecords", label: str, full_label: str
|
|
261
|
-
) -> Generator[
|
|
262
|
-
|
|
263
|
-
|
|
260
|
+
) -> Generator[Group, None, None]:
|
|
261
|
+
|
|
262
|
+
# A group is considered set if the environment variable exists and the group
|
|
263
|
+
# is recorded.If the environment variable exists but the group is not recorded,
|
|
264
|
+
# it means httpdbg was called reentrantly, and we need to record the group again
|
|
265
|
+
# using the same id.
|
|
266
|
+
group_already_set = (HTTPDBG_CURRENT_GROUP in os.environ) and (
|
|
267
|
+
os.environ[HTTPDBG_CURRENT_GROUP] in records.groups
|
|
268
|
+
)
|
|
264
269
|
|
|
265
270
|
if not group_already_set:
|
|
266
271
|
logger().info("httpdbg_group (new)")
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
os.environ
|
|
272
|
+
group = Group(label, full_label)
|
|
273
|
+
# in case of a reentrant call to httpdbg, we force the group id to be the same
|
|
274
|
+
if HTTPDBG_CURRENT_GROUP in os.environ:
|
|
275
|
+
group.id = os.environ[HTTPDBG_CURRENT_GROUP]
|
|
276
|
+
logger().info("httpdbg_group (reentrant) keep id {group.id}")
|
|
277
|
+
records.groups[group.id] = group
|
|
278
|
+
os.environ[HTTPDBG_CURRENT_GROUP] = group.id
|
|
279
|
+
else:
|
|
280
|
+
group = records.groups[os.environ[HTTPDBG_CURRENT_GROUP]]
|
|
270
281
|
|
|
271
282
|
try:
|
|
272
283
|
logger().info(
|
|
273
284
|
f"httpdbg_group {records.groups} group_id={os.environ[HTTPDBG_CURRENT_GROUP]} label={label} full_label={full_label}"
|
|
274
285
|
)
|
|
275
|
-
yield
|
|
286
|
+
yield group
|
|
276
287
|
except Exception:
|
|
277
288
|
if (not group_already_set) and (HTTPDBG_CURRENT_GROUP in os.environ):
|
|
278
289
|
del os.environ[HTTPDBG_CURRENT_GROUP]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import code
|
|
3
|
+
from typing import List
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
from httpdbg.records import HTTPRecords
|
|
7
|
+
from httpdbg.initiator import httpdbg_group
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def console_exit():
|
|
11
|
+
raise SystemExit
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InteractiveConsoleWithHistory(code.InteractiveConsole):
|
|
15
|
+
|
|
16
|
+
def __init__(self, records: HTTPRecords, locals=None):
|
|
17
|
+
self.records: HTTPRecords = records
|
|
18
|
+
self.history: List[str] = []
|
|
19
|
+
self.incomplete_block: bool = False
|
|
20
|
+
super().__init__(locals)
|
|
21
|
+
|
|
22
|
+
def push(self, line):
|
|
23
|
+
if line: # if the line is empty, we don't add it in the history
|
|
24
|
+
if (
|
|
25
|
+
self.incomplete_block
|
|
26
|
+
): # if the latest instruction is part of a block, we group it with the previous one
|
|
27
|
+
self.history[-1] += (
|
|
28
|
+
"\n " + line
|
|
29
|
+
) # to simulate the block indentation
|
|
30
|
+
else:
|
|
31
|
+
self.history.append(line)
|
|
32
|
+
|
|
33
|
+
# if the latest instruction is part of a block, the label is generic
|
|
34
|
+
label = self.history[-1] if not self.incomplete_block else "(block)"
|
|
35
|
+
|
|
36
|
+
# in the full label, we keep the last 5 instructions/blocks
|
|
37
|
+
latest_history = self.history[-5:]
|
|
38
|
+
if not self.incomplete_block:
|
|
39
|
+
# in case of a block, we don't know which line within the block is the initiator.
|
|
40
|
+
# this is why we do not mark it in that case.
|
|
41
|
+
# this information is displayed in the initiator tooltip of the requests (in console, line X,)
|
|
42
|
+
latest_history[-1] += " <===="
|
|
43
|
+
|
|
44
|
+
full_label = ">>> " + "\n>>> ".join(latest_history)
|
|
45
|
+
|
|
46
|
+
with httpdbg_group(self.records, label, full_label):
|
|
47
|
+
self.incomplete_block = super().push(line)
|
|
48
|
+
|
|
49
|
+
return self.incomplete_block
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_console(
|
|
53
|
+
records: HTTPRecords, test_mode: bool = False
|
|
54
|
+
) -> Union[InteractiveConsoleWithHistory, None]:
|
|
55
|
+
try:
|
|
56
|
+
vars = globals()
|
|
57
|
+
vars.update(locals())
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
# adds history and autocompletion capabilities
|
|
61
|
+
import readline
|
|
62
|
+
import rlcompleter
|
|
63
|
+
|
|
64
|
+
readline.set_completer(rlcompleter.Completer(vars).complete)
|
|
65
|
+
readline.parse_and_bind("tab: complete")
|
|
66
|
+
except ImportError: # pragma: no cover
|
|
67
|
+
# readline is not available on Windows
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
vars.update({"exit": console_exit})
|
|
71
|
+
|
|
72
|
+
new_console = InteractiveConsoleWithHistory(records, vars)
|
|
73
|
+
if not test_mode:
|
|
74
|
+
new_console.interact() # pragma: no cover
|
|
75
|
+
else:
|
|
76
|
+
new_console.push("print('test_mode is on')")
|
|
77
|
+
return new_console
|
|
78
|
+
except SystemExit: # pragma: no cover
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
return None
|
|
@@ -330,7 +330,7 @@ class HTTPRecords:
|
|
|
330
330
|
stack.append(line)
|
|
331
331
|
long_label = stack[-1]
|
|
332
332
|
label = long_label.split("\n")[1]
|
|
333
|
-
initiator = Initiator(
|
|
333
|
+
initiator = Initiator(label, long_label, stack)
|
|
334
334
|
|
|
335
335
|
if initiator.id not in self.initiators:
|
|
336
336
|
self.initiators[initiator.id] = initiator
|
|
@@ -410,13 +410,14 @@ class HTTPRecords:
|
|
|
410
410
|
del self._sockets[id(obj)]
|
|
411
411
|
|
|
412
412
|
def add_new_record_exception(
|
|
413
|
-
self, initiator: Initiator, url: str, exception: Exception
|
|
413
|
+
self, initiator: Initiator, group: Group, url: str, exception: Exception
|
|
414
414
|
) -> HTTPRecord:
|
|
415
415
|
if initiator.id not in self.initiators:
|
|
416
416
|
self.initiators[initiator.id] = initiator
|
|
417
417
|
new_record = HTTPRecord()
|
|
418
418
|
new_record.url = url
|
|
419
419
|
new_record.initiator_id = initiator.id
|
|
420
|
+
new_record.group_id = group.id
|
|
420
421
|
new_record.exception = exception
|
|
421
422
|
self.requests[new_record.id] = new_record
|
|
422
423
|
return new_record
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from json import JSONEncoder
|
|
3
|
+
import traceback
|
|
3
4
|
from typing import Any
|
|
4
5
|
from typing import Dict
|
|
5
6
|
|
|
@@ -53,7 +54,11 @@ class RequestPayload(JSONEncoder):
|
|
|
53
54
|
if req.exception is not None:
|
|
54
55
|
payload["exception"] = {
|
|
55
56
|
"type": str(type(req.exception)),
|
|
56
|
-
"message":
|
|
57
|
+
"message": "".join(
|
|
58
|
+
traceback.format_exception(
|
|
59
|
+
type(req.exception), req.exception, req.exception.__traceback__
|
|
60
|
+
)
|
|
61
|
+
),
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
return payload
|
|
@@ -119,6 +119,7 @@ async function get_request(request_id) {
|
|
|
119
119
|
|
|
120
120
|
// the full stack is not present in request summary
|
|
121
121
|
global.requests[request_id].initiator_id = data.initiator_id;
|
|
122
|
+
global.requests[request_id].exception = data.exception;
|
|
122
123
|
|
|
123
124
|
global.requests[request_id].to_refresh = true;
|
|
124
125
|
|
|
@@ -363,8 +363,8 @@
|
|
|
363
363
|
-- no exception --
|
|
364
364
|
{{/exception}}
|
|
365
365
|
{{#exception}}
|
|
366
|
-
<span>{{exception.type}}</span>
|
|
367
|
-
<pre>{{exception.message}}</pre>
|
|
366
|
+
<span class="header-cookie-value">{{exception.type}}</span>
|
|
367
|
+
<pre class="previewcode">{{exception.message}}</pre>
|
|
368
368
|
{{/exception}}
|
|
369
369
|
</script>
|
|
370
370
|
</div>
|
|
@@ -36,7 +36,7 @@ def test_run_console_from_pyhttpdbg_entry_point_default(
|
|
|
36
36
|
def test_run_console(httpbin, httpdbg_host, httpdbg_port):
|
|
37
37
|
with httpdbg_srv(httpdbg_host, httpdbg_port) as records:
|
|
38
38
|
with httprecord(records):
|
|
39
|
-
new_console = run_console(test_mode=True)
|
|
39
|
+
new_console = run_console(records, test_mode=True)
|
|
40
40
|
new_console.push("import requests")
|
|
41
41
|
new_console.push(f"requests.get('{httpbin.url}/get')")
|
|
42
42
|
with pytest.raises(SystemExit):
|
|
@@ -48,3 +48,31 @@ def test_run_console(httpbin, httpdbg_host, httpdbg_port):
|
|
|
48
48
|
|
|
49
49
|
assert len(reqs) == 1
|
|
50
50
|
assert reqs[list(reqs.keys())[0]]["url"] == httpbin.url + "/get"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.mark.group
|
|
54
|
+
def test_run_console_group(httpbin):
|
|
55
|
+
|
|
56
|
+
with httprecord() as records:
|
|
57
|
+
new_console = run_console(records, test_mode=True)
|
|
58
|
+
new_console.push("import requests")
|
|
59
|
+
new_console.push(f"requests.get('{httpbin.url}/get')")
|
|
60
|
+
new_console.push("if True:")
|
|
61
|
+
new_console.push(f" requests.post('{httpbin.url}/post')")
|
|
62
|
+
new_console.push("")
|
|
63
|
+
with pytest.raises(SystemExit):
|
|
64
|
+
new_console.push("exit()")
|
|
65
|
+
|
|
66
|
+
assert len(records) == 2
|
|
67
|
+
assert (
|
|
68
|
+
records.groups[records[0].group_id].label
|
|
69
|
+
== f"requests.get('{httpbin.url}/get')"
|
|
70
|
+
)
|
|
71
|
+
assert records.groups[records[0].group_id].full_label.endswith(
|
|
72
|
+
f">>> requests.get('{httpbin.url}/get') <===="
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
assert records.groups[records[1].group_id].label == "(block)"
|
|
76
|
+
assert records.groups[records[1].group_id].full_label.endswith(
|
|
77
|
+
f">>> if True:\n requests.post('{httpbin.url}/post')"
|
|
78
|
+
)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import code
|
|
3
|
-
from typing import Union
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def console_exit():
|
|
7
|
-
raise SystemExit
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def run_console(test_mode: bool = False) -> Union[code.InteractiveConsole, None]:
|
|
11
|
-
try:
|
|
12
|
-
vars = globals()
|
|
13
|
-
vars.update(locals())
|
|
14
|
-
|
|
15
|
-
try:
|
|
16
|
-
# adds history and autocompletion capabilities
|
|
17
|
-
import readline
|
|
18
|
-
import rlcompleter
|
|
19
|
-
|
|
20
|
-
readline.set_completer(rlcompleter.Completer(vars).complete)
|
|
21
|
-
readline.parse_and_bind("tab: complete")
|
|
22
|
-
except ImportError: # pragma: no cover
|
|
23
|
-
# readline is not available on Windows
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
vars.update({"exit": console_exit})
|
|
27
|
-
|
|
28
|
-
new_console = code.InteractiveConsole(vars)
|
|
29
|
-
if not test_mode:
|
|
30
|
-
new_console.interact() # pragma: no cover
|
|
31
|
-
else:
|
|
32
|
-
new_console.push("print('test_mode is on')")
|
|
33
|
-
return new_console
|
|
34
|
-
except SystemExit: # pragma: no cover
|
|
35
|
-
pass
|
|
36
|
-
|
|
37
|
-
return None
|
|
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.29.0 → httpdbg-0.29.2}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg
RENAMED
|
File without changes
|
{httpdbg-0.29.0 → httpdbg-0.29.2}/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
|
{httpdbg-0.29.0 → httpdbg-0.29.2}/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
|