httpdbg 2.4.0__tar.gz → 2.4.1__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.
Files changed (98) hide show
  1. {httpdbg-2.4.0 → httpdbg-2.4.1}/PKG-INFO +1 -1
  2. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/__init__.py +1 -1
  3. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/record.py +20 -0
  4. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/recordhttp1.py +15 -2
  5. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/recordhttp2.py +20 -1
  6. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg.egg-info/PKG-INFO +1 -1
  7. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg.egg-info/SOURCES.txt +1 -0
  8. httpdbg-2.4.1/tests/test_serialization.py +82 -0
  9. {httpdbg-2.4.0 → httpdbg-2.4.1}/LICENSE +0 -0
  10. {httpdbg-2.4.0 → httpdbg-2.4.1}/README.md +0 -0
  11. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/__main__.py +0 -0
  12. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/args.py +0 -0
  13. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/env.py +0 -0
  14. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/exception.py +0 -0
  15. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/export.py +0 -0
  16. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/__init__.py +0 -0
  17. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/aiohttp.py +0 -0
  18. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/all.py +0 -0
  19. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/external.py +0 -0
  20. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/fastapi.py +0 -0
  21. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/flask.py +0 -0
  22. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/generic.py +0 -0
  23. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/h2.py +0 -0
  24. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/http.py +0 -0
  25. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/httpx.py +0 -0
  26. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/pytest.py +0 -0
  27. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/requests.py +0 -0
  28. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/socket.py +0 -0
  29. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/starlette.py +0 -0
  30. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/template_sitecustomize.py +0 -0
  31. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/unittest.py +0 -0
  32. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/urllib3.py +0 -0
  33. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/utils.py +0 -0
  34. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/hooks/uvicorn.py +0 -0
  35. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/http_status_code.py +0 -0
  36. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/initiator.py +0 -0
  37. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/log.py +0 -0
  38. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/mode_console.py +0 -0
  39. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/mode_module.py +0 -0
  40. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/mode_script.py +0 -0
  41. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/preview.py +0 -0
  42. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/records.py +0 -0
  43. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/server.py +0 -0
  44. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/utils.py +0 -0
  45. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/__init__.py +0 -0
  46. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/app.py +0 -0
  47. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/api.js +0 -0
  48. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/column.css +0 -0
  49. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/configuration.css +0 -0
  50. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/configuration.js +0 -0
  51. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/detail.css +0 -0
  52. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/favicon.ico +0 -0
  53. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/filter.js +0 -0
  54. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/chevron-direction-top-outline-icon.svg +0 -0
  55. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/download-install-line-icon.svg +0 -0
  56. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/engine-gears-icon.svg +0 -0
  57. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/eye-blind-icon.svg +0 -0
  58. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/eye-icon.svg +0 -0
  59. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/files-papers-outline-icon.svg +0 -0
  60. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/filter-outline-icon.svg +0 -0
  61. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/lock-line-icon.svg +0 -0
  62. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/lock-open-line-icon.svg +0 -0
  63. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/math-multiplication-icon.svg +0 -0
  64. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/push-pin-green-icon.svg +0 -0
  65. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/question-mark-round-line-icon.svg +0 -0
  66. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/recycle-bin-line-icon.svg +0 -0
  67. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/icons/wait-sandclock-icon.svg +0 -0
  68. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/index.htm +0 -0
  69. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/main.js +0 -0
  70. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/mustache.min.js +0 -0
  71. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/render.js +0 -0
  72. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/style.css +0 -0
  73. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg/webapp/static/table.css +0 -0
  74. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg.egg-info/dependency_links.txt +0 -0
  75. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg.egg-info/entry_points.txt +0 -0
  76. {httpdbg-2.4.0 → httpdbg-2.4.1}/httpdbg.egg-info/top_level.txt +0 -0
  77. {httpdbg-2.4.0 → httpdbg-2.4.1}/pyproject.toml +0 -0
  78. {httpdbg-2.4.0 → httpdbg-2.4.1}/setup.cfg +0 -0
  79. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_api.py +0 -0
  80. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_cli.py +0 -0
  81. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_context_manager.py +0 -0
  82. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_aiohttp.py +0 -0
  83. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_h2.py +0 -0
  84. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_httpx.py +0 -0
  85. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_pytest.py +0 -0
  86. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_requests.py +0 -0
  87. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_unittest.py +0 -0
  88. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_hook_urllib3.py +0 -0
  89. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_initiator.py +0 -0
  90. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_mode_console.py +0 -0
  91. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_mode_module_pytest.py +0 -0
  92. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_mode_script.py +0 -0
  93. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_multiprocess.py +0 -0
  94. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_preview.py +0 -0
  95. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_pyhttpdbg_server.py +0 -0
  96. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_server.py +0 -0
  97. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_server_hook_fastapi.py +0 -0
  98. {httpdbg-2.4.0 → httpdbg-2.4.1}/tests/test_server_hook_flask.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpdbg
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: A very simple tool to debug HTTP(S) client and server requests.
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License-Expression: Apache-2.0
@@ -1,4 +1,4 @@
1
- __version__ = "2.4.0"
1
+ __version__ = "2.4.1"
2
2
 
3
3
  __all__ = ["export_html", "httprecord", "HTTPRecords"]
4
4
 
@@ -238,3 +238,23 @@ class HTTPRecord(ABC):
238
238
  }
239
239
 
240
240
  return json.dumps(payload).encode("utf-8")
241
+
242
+ def __eq__(self, other: object) -> bool:
243
+ if not isinstance(other, HTTPRecord):
244
+ return False
245
+
246
+ return (
247
+ self.url == other.url
248
+ and self.method == other.method
249
+ and self.status_code == other.status_code
250
+ and self.protocol == other.protocol
251
+ and self.tag == other.tag
252
+ and self.initiator_id == other.initiator_id
253
+ and self.group_id == other.group_id
254
+ and self.is_client == other.is_client
255
+ and self.http100 == other.http100
256
+ and type(self.exception) is type(other.exception)
257
+ and str(self.exception) == str(other.exception)
258
+ and self.request == other.request
259
+ and self.response == other.response
260
+ )
@@ -77,6 +77,12 @@ class HTTP1RecordReqResp(HTTPRecordReqResp):
77
77
  self.last_update = datetime.datetime.now(datetime.timezone.utc)
78
78
  self._rawdata = value
79
79
 
80
+ def __eq__(self, other: object) -> bool:
81
+ if not isinstance(other, HTTP1RecordReqResp):
82
+ return False
83
+
84
+ return self.rawdata == other.rawdata and self.last_update == other.last_update
85
+
80
86
 
81
87
  class HTTP1RecordRequest(HTTPRecordRequest, HTTP1RecordReqResp):
82
88
  def __init__(self) -> None:
@@ -211,7 +217,8 @@ class HTTP1Record(HTTPRecord):
211
217
  "sent": base64.b64encode(
212
218
  self.request.rawdata if self.is_client else self.response.rawdata,
213
219
  ).decode("ascii"),
214
- "last_update": self.last_update.isoformat(),
220
+ "last_update_request": self.request.last_update.isoformat(),
221
+ "last_update_response": self.response.last_update.isoformat(),
215
222
  }
216
223
 
217
224
  @staticmethod
@@ -224,6 +231,12 @@ class HTTP1Record(HTTPRecord):
224
231
  data["is_client"],
225
232
  )
226
233
  http1record.id = data["id"]
227
- http1record.receive_data(base64.b64decode(data["received"]))
228
234
  http1record.send_data(base64.b64decode(data["sent"]))
235
+ http1record.receive_data(base64.b64decode(data["received"]))
236
+ http1record.request.last_update = datetime.datetime.fromisoformat(
237
+ data["last_update_request"]
238
+ )
239
+ http1record.response.last_update = datetime.datetime.fromisoformat(
240
+ data["last_update_response"]
241
+ )
229
242
  return http1record
@@ -42,6 +42,16 @@ class HTTP2RecordReqResp(HTTPRecordReqResp):
42
42
  self.get_header("Content-Encoding"),
43
43
  )
44
44
 
45
+ def __eq__(self, other: object) -> bool:
46
+ if not isinstance(other, HTTP2RecordReqResp):
47
+ return False
48
+
49
+ return (
50
+ self.headers == other.headers
51
+ and self.content == other.content
52
+ and self.last_update == other.last_update
53
+ )
54
+
45
55
 
46
56
  class HTTP2RecordRequest(HTTPRecordRequest, HTTP2RecordReqResp):
47
57
 
@@ -129,7 +139,8 @@ class HTTP2Record(HTTPRecord):
129
139
  "headers": [header.to_json() for header in self.response.headers],
130
140
  "content": base64.b64encode(self.response.content).decode("ascii"),
131
141
  },
132
- "last_update": self.last_update.isoformat(),
142
+ "last_update_request": self.request.last_update.isoformat(),
143
+ "last_update_response": self.response.last_update.isoformat(),
133
144
  }
134
145
 
135
146
  @staticmethod
@@ -146,8 +157,16 @@ class HTTP2Record(HTTPRecord):
146
157
  HTTPDBGHeader.from_json(header) for header in data["request"]["headers"]
147
158
  ]
148
159
  http2record.request.content = base64.b64decode(data["request"]["content"])
160
+ http2record.request.last_update = datetime.datetime.fromisoformat(
161
+ data["last_update_request"]
162
+ )
163
+
149
164
  http2record.response._headers = [
150
165
  HTTPDBGHeader.from_json(header) for header in data["response"]["headers"]
151
166
  ]
152
167
  http2record.response.content = base64.b64decode(data["response"]["content"])
168
+ http2record.response.last_update = datetime.datetime.fromisoformat(
169
+ data["last_update_response"]
170
+ )
171
+
153
172
  return http2record
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpdbg
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: A very simple tool to debug HTTP(S) client and server requests.
5
5
  Author-email: cle-b <cle@tictac.pm>
6
6
  License-Expression: Apache-2.0
@@ -91,6 +91,7 @@ tests/test_mode_script.py
91
91
  tests/test_multiprocess.py
92
92
  tests/test_preview.py
93
93
  tests/test_pyhttpdbg_server.py
94
+ tests/test_serialization.py
94
95
  tests/test_server.py
95
96
  tests/test_server_hook_fastapi.py
96
97
  tests/test_server_hook_flask.py
@@ -0,0 +1,82 @@
1
+ import httpx
2
+ import pytest
3
+ import requests
4
+
5
+ from httpdbg.hooks.all import httprecord
6
+ from httpdbg.hooks.recordhttp1 import HTTP1Record
7
+ from httpdbg.hooks.recordhttp2 import HTTP2Record
8
+ from httpdbg.utils import HTTPDBGCookie
9
+ from httpdbg.utils import HTTPDBGHeader
10
+
11
+
12
+ from tests.demo_http2 import http2_httpbin_server
13
+ from tests.utils import get_free_tcp_port
14
+
15
+
16
+ @pytest.fixture(scope="module")
17
+ def httpbin2():
18
+ host = "127.0.0.1"
19
+ port = get_free_tcp_port(host)
20
+ with http2_httpbin_server(host, port) as url:
21
+ yield url
22
+
23
+
24
+ @pytest.mark.serialization
25
+ def test_serialization_http1record(httpbin):
26
+ with httprecord() as records:
27
+ requests.get(
28
+ f"{httpbin.url}/cookies/set/confiture/oignon",
29
+ cookies={"jam": "strawberry"},
30
+ allow_redirects=False,
31
+ )
32
+
33
+ assert len(records) == 1
34
+ http_record = records[0]
35
+ http_record_copy = HTTP1Record.from_json(http_record.to_json())
36
+
37
+ assert HTTPDBGCookie("jam", "strawberry") in http_record_copy.request.cookies
38
+
39
+ assert (
40
+ HTTPDBGCookie(
41
+ "confiture",
42
+ "oignon",
43
+ [
44
+ {"attr": "/", "name": "path"},
45
+ ],
46
+ )
47
+ in http_record_copy.response.cookies
48
+ )
49
+
50
+ assert http_record_copy == http_record
51
+
52
+
53
+ @pytest.mark.serialization
54
+ def test_serialization_http2record(httpbin2):
55
+ with httprecord() as records:
56
+ client = httpx.Client(http2=True, verify=False)
57
+ client.post(f"{httpbin2}/post", content="abc")
58
+
59
+ assert len(records) == 1
60
+ http_record = records[0]
61
+ http_record_copy = HTTP2Record.from_json(http_record.to_json())
62
+
63
+ assert http_record_copy.protocol == "HTTP/2"
64
+
65
+ assert http_record_copy.method.upper() == "POST"
66
+ assert http_record_copy.status_code == 200
67
+
68
+ assert HTTPDBGHeader("content-length", "3") in http_record_copy.request.headers
69
+ assert http_record_copy.request.cookies == []
70
+ assert http_record_copy.request.content == b"abc"
71
+
72
+ assert http_record_copy.last_update == http_record.last_update
73
+
74
+ assert http_record_copy == http_record
75
+
76
+
77
+ @pytest.mark.serialization
78
+ def test_serialization_compatibility():
79
+ http1record = HTTP1Record("a", "b")
80
+ http2record = HTTP2Record("a", "b")
81
+ assert not (http1record == http2record)
82
+ assert not (http2record == http1record)
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