stoobly-agent 1.9.12__py3-none-any.whl → 1.10.1__py3-none-any.whl
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.
- stoobly_agent/__init__.py +1 -1
- stoobly_agent/app/api/__init__.py +4 -20
- stoobly_agent/app/api/application_http_request_handler.py +5 -2
- stoobly_agent/app/api/configs_controller.py +3 -3
- stoobly_agent/app/cli/decorators/exec.py +1 -1
- stoobly_agent/app/cli/helpers/handle_config_update_service.py +4 -0
- stoobly_agent/app/cli/intercept_cli.py +40 -7
- stoobly_agent/app/cli/scaffold/app_command.py +4 -0
- stoobly_agent/app/cli/scaffold/app_config.py +21 -3
- stoobly_agent/app/cli/scaffold/app_create_command.py +109 -2
- stoobly_agent/app/cli/scaffold/constants.py +14 -3
- stoobly_agent/app/cli/scaffold/docker/constants.py +4 -6
- stoobly_agent/app/cli/scaffold/docker/service/build_decorator.py +2 -2
- stoobly_agent/app/cli/scaffold/docker/service/builder.py +36 -10
- stoobly_agent/app/cli/scaffold/docker/workflow/builder.py +0 -27
- stoobly_agent/app/cli/scaffold/docker/workflow/command_decorator.py +25 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/decorators_factory.py +7 -2
- stoobly_agent/app/cli/scaffold/docker/workflow/detached_decorator.py +42 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/local_decorator.py +26 -0
- stoobly_agent/app/cli/scaffold/docker/workflow/mock_decorator.py +9 -10
- stoobly_agent/app/cli/scaffold/docker/workflow/reverse_proxy_decorator.py +5 -8
- stoobly_agent/app/cli/scaffold/service_config.py +133 -34
- stoobly_agent/app/cli/scaffold/service_create_command.py +11 -2
- stoobly_agent/app/cli/scaffold/service_dependency.py +51 -0
- stoobly_agent/app/cli/scaffold/service_docker_compose.py +3 -3
- stoobly_agent/app/cli/scaffold/service_workflow_validate_command.py +10 -7
- stoobly_agent/app/cli/scaffold/templates/app/.Dockerfile.context +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/build/.docker-compose.base.yml +2 -2
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/bin/configure +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/build/mock/docker-compose.yml +16 -6
- stoobly_agent/app/cli/scaffold/templates/app/build/record/bin/configure +26 -1
- stoobly_agent/app/cli/scaffold/templates/app/build/record/docker-compose.yml +16 -6
- stoobly_agent/app/cli/scaffold/templates/app/build/test/bin/configure +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/build/test/docker-compose.yml +16 -6
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/.docker-compose.base.yml +2 -2
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/bin/configure +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/mock/docker-compose.yml +16 -10
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/bin/configure +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/record/docker-compose.yml +16 -10
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/bin/configure +1 -1
- stoobly_agent/app/cli/scaffold/templates/app/entrypoint/test/docker-compose.yml +16 -10
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/.docker-compose.base.yml +2 -1
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/mock/.docker-compose.mock.yml +6 -3
- stoobly_agent/app/cli/scaffold/templates/app/stoobly-ui/record/.docker-compose.record.yml +6 -4
- stoobly_agent/app/cli/scaffold/templates/build/workflows/record/.configure +21 -1
- stoobly_agent/app/cli/scaffold/templates/constants.py +4 -0
- stoobly_agent/app/cli/scaffold/templates/plugins/cypress/test/.Dockerfile.cypress +22 -0
- stoobly_agent/app/cli/scaffold/templates/plugins/cypress/test/.docker-compose.test.yml +19 -0
- stoobly_agent/app/cli/scaffold/templates/plugins/playwright/test/.Dockerfile.playwright +33 -0
- stoobly_agent/app/cli/scaffold/templates/plugins/playwright/test/.docker-compose.test.yml +18 -0
- stoobly_agent/app/cli/scaffold/templates/plugins/playwright/test/.entrypoint.sh +11 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/bin/configure +2 -10
- stoobly_agent/app/cli/scaffold/templates/workflow/mock/docker-compose.yml +17 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/record/bin/configure +19 -45
- stoobly_agent/app/cli/scaffold/templates/workflow/record/docker-compose.yml +17 -0
- stoobly_agent/app/cli/scaffold/templates/workflow/test/bin/configure +2 -10
- stoobly_agent/app/cli/scaffold/templates/workflow/test/docker-compose.yml +17 -0
- stoobly_agent/app/cli/scaffold/workflow_create_command.py +0 -1
- stoobly_agent/app/cli/scaffold/workflow_run_command.py +1 -1
- stoobly_agent/app/cli/scaffold_cli.py +85 -96
- stoobly_agent/app/proxy/handle_record_service.py +12 -3
- stoobly_agent/app/proxy/handle_replay_service.py +14 -2
- stoobly_agent/app/proxy/intercept_settings.py +12 -8
- stoobly_agent/app/proxy/record/upload_request_service.py +5 -8
- stoobly_agent/app/proxy/replay/replay_request_service.py +3 -0
- stoobly_agent/app/proxy/run.py +3 -28
- stoobly_agent/app/proxy/utils/allowed_request_service.py +3 -2
- stoobly_agent/app/proxy/utils/minimize_headers.py +47 -0
- stoobly_agent/app/proxy/utils/publish_change_service.py +22 -24
- stoobly_agent/app/proxy/utils/strategy.py +16 -0
- stoobly_agent/app/settings/__init__.py +15 -6
- stoobly_agent/app/settings/data_rules.py +25 -1
- stoobly_agent/app/settings/intercept_settings.py +5 -2
- stoobly_agent/app/settings/types/__init__.py +0 -1
- stoobly_agent/app/settings/ui_settings.py +5 -5
- stoobly_agent/cli.py +41 -16
- stoobly_agent/config/constants/custom_headers.py +1 -0
- stoobly_agent/config/constants/env_vars.py +4 -3
- stoobly_agent/config/constants/record_strategy.py +6 -0
- stoobly_agent/config/data_dir.py +1 -0
- stoobly_agent/config/settings.yml.sample +2 -3
- stoobly_agent/lib/logger.py +15 -5
- stoobly_agent/public/index.html +1 -1
- stoobly_agent/public/main-es2015.5a9aa16433404c3f423a.js +1 -0
- stoobly_agent/public/main-es5.5a9aa16433404c3f423a.js +1 -0
- stoobly_agent/test/app/cli/intercept/intercept_configure_test.py +231 -1
- stoobly_agent/test/app/cli/scaffold/cli_invoker.py +3 -2
- stoobly_agent/test/app/cli/scaffold/cli_test.py +3 -3
- stoobly_agent/test/app/cli/scaffold/e2e_test.py +11 -11
- stoobly_agent/test/app/models/schemas/.stoobly/db/VERSION +1 -1
- stoobly_agent/test/app/proxy/utils/minimize_headers_test.py +342 -0
- {stoobly_agent-1.9.12.dist-info → stoobly_agent-1.10.1.dist-info}/METADATA +2 -1
- {stoobly_agent-1.9.12.dist-info → stoobly_agent-1.10.1.dist-info}/RECORD +96 -80
- stoobly_agent/public/main-es2015.089b46f303768fbe864f.js +0 -1
- stoobly_agent/public/main-es5.089b46f303768fbe864f.js +0 -1
- {stoobly_agent-1.9.12.dist-info → stoobly_agent-1.10.1.dist-info}/LICENSE +0 -0
- {stoobly_agent-1.9.12.dist-info → stoobly_agent-1.10.1.dist-info}/WHEEL +0 -0
- {stoobly_agent-1.9.12.dist-info → stoobly_agent-1.10.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,342 @@
|
|
1
|
+
import copy
|
2
|
+
import time
|
3
|
+
|
4
|
+
from mitmproxy.http import HTTPFlow as MitmproxyHTTPFlow
|
5
|
+
from mitmproxy.http import Request, Response, Headers
|
6
|
+
from stoobly_agent.app.proxy.utils.minimize_headers import (
|
7
|
+
minimize_headers,
|
8
|
+
minimize_request_headers,
|
9
|
+
minimize_response_headers,
|
10
|
+
REQUEST_HEADERS_ALLOWLIST,
|
11
|
+
RESPONSE_HEADERS_ALLOWLIST,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
class TestMinimizeHeaders():
|
16
|
+
|
17
|
+
def test_minimize_request_headers(self):
|
18
|
+
headers_stub = [
|
19
|
+
# Essential headers (should be preserved)
|
20
|
+
(b"Host", b"api.example.com"),
|
21
|
+
(b"User-Agent", b"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"),
|
22
|
+
(b"Accept", b"application/json, text/plain, */*"),
|
23
|
+
(b"Accept-Language", b"en-US,en;q=0.9"),
|
24
|
+
(b"Accept-Encoding", b"gzip, deflate, br"),
|
25
|
+
(b"Content-Type", b"application/json"),
|
26
|
+
(b"Content-Length", b"42"),
|
27
|
+
(b"Origin", b"https://example.com"),
|
28
|
+
(b"Referer", b"https://example.com/page"),
|
29
|
+
|
30
|
+
# Headers that should be removed
|
31
|
+
(b"Cookie", b"session=abc123; user=john"),
|
32
|
+
(b"Authorization", b"Bearer token123"),
|
33
|
+
(b"X-Request-ID", b"req-uuid-123"),
|
34
|
+
(b"X-Forwarded-For", b"192.168.1.1"),
|
35
|
+
(b"X-Custom-Header", b"custom-value"),
|
36
|
+
(b"Sec-Fetch-Mode", b"cors"),
|
37
|
+
(b"Sec-Fetch-Dest", b"empty"),
|
38
|
+
(b"DNT", b"1"),
|
39
|
+
]
|
40
|
+
headers = Headers(headers_stub)
|
41
|
+
|
42
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
43
|
+
flow_stub.request = Request(
|
44
|
+
host="api.example.com",
|
45
|
+
port=443,
|
46
|
+
method="POST",
|
47
|
+
scheme="https",
|
48
|
+
authority="api.example.com",
|
49
|
+
path="/api/v1/data",
|
50
|
+
http_version="HTTP/1.1",
|
51
|
+
headers=headers,
|
52
|
+
content=b'{"data": "test"}',
|
53
|
+
trailers=None,
|
54
|
+
timestamp_start=time.time(),
|
55
|
+
timestamp_end=time.time() + 1,
|
56
|
+
)
|
57
|
+
|
58
|
+
old_headers = copy.deepcopy(flow_stub.request.headers)
|
59
|
+
|
60
|
+
minimize_request_headers(flow_stub)
|
61
|
+
|
62
|
+
new_headers = flow_stub.request.headers
|
63
|
+
|
64
|
+
# Non-essential headers should be removed
|
65
|
+
assert old_headers != new_headers
|
66
|
+
assert "Cookie" in old_headers
|
67
|
+
assert "Cookie" not in new_headers
|
68
|
+
assert "Authorization" not in new_headers
|
69
|
+
assert "X-Request-ID" not in new_headers
|
70
|
+
assert "X-Forwarded-For" not in new_headers
|
71
|
+
assert "X-Custom-Header" not in new_headers
|
72
|
+
assert "Sec-Fetch-Mode" not in new_headers
|
73
|
+
assert "Sec-Fetch-Dest" not in new_headers
|
74
|
+
assert "DNT" not in new_headers
|
75
|
+
|
76
|
+
# Essential headers should remain
|
77
|
+
assert "Host" in new_headers
|
78
|
+
assert "User-Agent" in new_headers
|
79
|
+
assert "Accept" in new_headers
|
80
|
+
assert "Accept-Language" in new_headers
|
81
|
+
assert "Accept-Encoding" in new_headers
|
82
|
+
assert "Content-Type" in new_headers
|
83
|
+
assert "Content-Length" in new_headers
|
84
|
+
assert "Origin" in new_headers
|
85
|
+
assert "Referer" in new_headers
|
86
|
+
|
87
|
+
def test_minimize_response_headers(self):
|
88
|
+
headers_stub = [
|
89
|
+
# Essential headers (should be preserved)
|
90
|
+
(b"Content-Type", b"application/json"),
|
91
|
+
(b"Content-Length", b"1234"),
|
92
|
+
(b"Date", b"Wed, 21 Oct 2015 07:28:00 GMT"),
|
93
|
+
(b"Server", b"nginx/1.18.0"),
|
94
|
+
(b"Transfer-Encoding", b"chunked"),
|
95
|
+
|
96
|
+
# Headers that should be removed
|
97
|
+
(b"Set-Cookie", b"session=new; HttpOnly; Secure"),
|
98
|
+
(b"X-Powered-By", b"Express"),
|
99
|
+
(b"X-Request-ID", b"resp-uuid-456"),
|
100
|
+
(b"Access-Control-Allow-Origin", b"*"),
|
101
|
+
(b"Vary", b"Accept-Encoding"),
|
102
|
+
(b"ETag", b'"abc123"'),
|
103
|
+
(b"Last-Modified", b"Tue, 20 Oct 2015 07:28:00 GMT"),
|
104
|
+
]
|
105
|
+
headers = Headers(headers_stub)
|
106
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
107
|
+
flow_stub.response = Response(
|
108
|
+
http_version="HTTP/1.1",
|
109
|
+
status_code=200,
|
110
|
+
reason="OK",
|
111
|
+
headers=headers,
|
112
|
+
content=b"{}",
|
113
|
+
trailers=None,
|
114
|
+
timestamp_start=time.time(),
|
115
|
+
timestamp_end=time.time() + 1,
|
116
|
+
)
|
117
|
+
old_headers = copy.deepcopy(flow_stub.response.headers)
|
118
|
+
|
119
|
+
minimize_response_headers(flow_stub)
|
120
|
+
|
121
|
+
new_headers = flow_stub.response.headers
|
122
|
+
# Non-essential headers should be removed
|
123
|
+
assert old_headers != new_headers
|
124
|
+
assert "Set-Cookie" in old_headers
|
125
|
+
assert "Set-Cookie" not in new_headers
|
126
|
+
assert "X-Powered-By" not in new_headers
|
127
|
+
assert "X-Request-ID" not in new_headers
|
128
|
+
assert "Access-Control-Allow-Origin" not in new_headers
|
129
|
+
assert "Vary" not in new_headers
|
130
|
+
assert "ETag" not in new_headers
|
131
|
+
assert "Last-Modified" not in new_headers
|
132
|
+
|
133
|
+
# Essential headers should remain
|
134
|
+
assert "Content-Type" in new_headers
|
135
|
+
assert "Content-Length" in new_headers
|
136
|
+
assert "Date" in new_headers
|
137
|
+
assert "Server" in new_headers
|
138
|
+
assert "Transfer-Encoding" in new_headers
|
139
|
+
|
140
|
+
# Verify exact header count (Content-Type, Content-Length, Date, Server, Transfer-Encoding)
|
141
|
+
assert len(new_headers) == 5
|
142
|
+
|
143
|
+
def test_minimize_headers(self):
|
144
|
+
req_headers = Headers([
|
145
|
+
(b"Host", b"example.com"),
|
146
|
+
(b"X-Remove-Me", b"bye")
|
147
|
+
])
|
148
|
+
res_headers = Headers([
|
149
|
+
(b"Content-Type", b"text/html"),
|
150
|
+
(b"X-Remove-Me", b"bye")
|
151
|
+
])
|
152
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
153
|
+
flow_stub.request = Request(
|
154
|
+
host="example.com",
|
155
|
+
port=80,
|
156
|
+
method="GET",
|
157
|
+
scheme="http",
|
158
|
+
authority="example.com",
|
159
|
+
path="/",
|
160
|
+
http_version="HTTP/1.1",
|
161
|
+
headers=req_headers,
|
162
|
+
content=None,
|
163
|
+
trailers=None,
|
164
|
+
timestamp_start=time.time(),
|
165
|
+
timestamp_end=time.time() + 1,
|
166
|
+
)
|
167
|
+
flow_stub.response = Response(
|
168
|
+
http_version="HTTP/1.1",
|
169
|
+
status_code=200,
|
170
|
+
reason="OK",
|
171
|
+
headers=res_headers,
|
172
|
+
content=b"<html></html>",
|
173
|
+
trailers=None,
|
174
|
+
timestamp_start=time.time(),
|
175
|
+
timestamp_end=time.time() + 1,
|
176
|
+
)
|
177
|
+
old_req_headers = copy.deepcopy(flow_stub.request.headers)
|
178
|
+
old_res_headers = copy.deepcopy(flow_stub.response.headers)
|
179
|
+
|
180
|
+
minimize_headers(flow_stub)
|
181
|
+
|
182
|
+
# Verify changes occurred
|
183
|
+
assert old_req_headers != flow_stub.request.headers
|
184
|
+
assert old_res_headers != flow_stub.response.headers
|
185
|
+
|
186
|
+
# Verify specific header removal and retention
|
187
|
+
assert "X-Remove-Me" not in flow_stub.request.headers
|
188
|
+
assert "X-Remove-Me" not in flow_stub.response.headers
|
189
|
+
assert "Host" in flow_stub.request.headers
|
190
|
+
assert "Content-Type" in flow_stub.response.headers
|
191
|
+
|
192
|
+
# Verify header counts
|
193
|
+
assert len(flow_stub.request.headers) == 1
|
194
|
+
assert len(flow_stub.response.headers) == 1
|
195
|
+
|
196
|
+
def test_empty_headers(self):
|
197
|
+
"""Test minimize functions with empty headers"""
|
198
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
199
|
+
flow_stub.request = Request(
|
200
|
+
host="example.com",
|
201
|
+
port=80,
|
202
|
+
method="GET",
|
203
|
+
scheme="http",
|
204
|
+
authority="example.com",
|
205
|
+
path="/",
|
206
|
+
http_version="HTTP/1.1",
|
207
|
+
headers=Headers(),
|
208
|
+
content=None,
|
209
|
+
trailers=None,
|
210
|
+
timestamp_start=time.time(),
|
211
|
+
timestamp_end=time.time() + 1,
|
212
|
+
)
|
213
|
+
flow_stub.response = Response(
|
214
|
+
http_version="HTTP/1.1",
|
215
|
+
status_code=200,
|
216
|
+
reason="OK",
|
217
|
+
headers=Headers(),
|
218
|
+
content=b"",
|
219
|
+
trailers=None,
|
220
|
+
timestamp_start=time.time(),
|
221
|
+
timestamp_end=time.time() + 1,
|
222
|
+
)
|
223
|
+
|
224
|
+
# Should not raise any errors
|
225
|
+
minimize_headers(flow_stub)
|
226
|
+
assert len(flow_stub.request.headers) == 0
|
227
|
+
assert len(flow_stub.response.headers) == 0
|
228
|
+
|
229
|
+
def test_case_sensitivity(self):
|
230
|
+
"""Test that header matching is case-insensitive"""
|
231
|
+
headers_stub = [
|
232
|
+
(b"host", b"example.com"), # lowercase
|
233
|
+
(b"USER-AGENT", b"test-agent"), # uppercase
|
234
|
+
(b"Content-Type", b"application/json"), # mixed case
|
235
|
+
(b"x-remove-me", b"bye"), # should be removed
|
236
|
+
]
|
237
|
+
headers = Headers(headers_stub)
|
238
|
+
|
239
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
240
|
+
flow_stub.request = Request(
|
241
|
+
host="example.com",
|
242
|
+
port=80,
|
243
|
+
method="POST",
|
244
|
+
scheme="http",
|
245
|
+
authority="example.com",
|
246
|
+
path="/",
|
247
|
+
http_version="HTTP/1.1",
|
248
|
+
headers=headers,
|
249
|
+
content=b'{"test": "data"}',
|
250
|
+
trailers=None,
|
251
|
+
timestamp_start=time.time(),
|
252
|
+
timestamp_end=time.time() + 1,
|
253
|
+
)
|
254
|
+
|
255
|
+
minimize_request_headers(flow_stub)
|
256
|
+
|
257
|
+
# Case-insensitive matching should preserve these headers
|
258
|
+
assert "host" in flow_stub.request.headers
|
259
|
+
assert "USER-AGENT" in flow_stub.request.headers
|
260
|
+
assert "Content-Type" in flow_stub.request.headers
|
261
|
+
|
262
|
+
# Non-allowed header should be removed regardless of case
|
263
|
+
assert "x-remove-me" not in flow_stub.request.headers
|
264
|
+
|
265
|
+
def test_minimize_headers_no_response(self):
|
266
|
+
"""Test minimize_headers when response is None"""
|
267
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
268
|
+
flow_stub.request = Request(
|
269
|
+
host="example.com",
|
270
|
+
port=80,
|
271
|
+
method="GET",
|
272
|
+
scheme="http",
|
273
|
+
authority="example.com",
|
274
|
+
path="/",
|
275
|
+
http_version="HTTP/1.1",
|
276
|
+
headers=Headers([(b"Host", b"example.com"), (b"X-Remove", b"me")]),
|
277
|
+
content=None,
|
278
|
+
trailers=None,
|
279
|
+
timestamp_start=time.time(),
|
280
|
+
timestamp_end=time.time() + 1,
|
281
|
+
)
|
282
|
+
flow_stub.response = None
|
283
|
+
|
284
|
+
# Should not raise an error when response is None
|
285
|
+
minimize_request_headers(flow_stub)
|
286
|
+
assert "Host" in flow_stub.request.headers
|
287
|
+
assert "X-Remove" not in flow_stub.request.headers
|
288
|
+
|
289
|
+
def test_minimize_headers_no_request(self):
|
290
|
+
"""Test minimize_headers when request is None"""
|
291
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
292
|
+
flow_stub.request = None
|
293
|
+
flow_stub.response = Response(
|
294
|
+
http_version="HTTP/1.1",
|
295
|
+
status_code=200,
|
296
|
+
reason="OK",
|
297
|
+
headers=Headers([(b"Content-Type", b"text/html"), (b"X-Remove", b"me")]),
|
298
|
+
content=b"<html></html>",
|
299
|
+
trailers=None,
|
300
|
+
timestamp_start=time.time(),
|
301
|
+
timestamp_end=time.time() + 1,
|
302
|
+
)
|
303
|
+
|
304
|
+
# Should not raise an error when request is None
|
305
|
+
minimize_response_headers(flow_stub)
|
306
|
+
assert "Content-Type" in flow_stub.response.headers
|
307
|
+
assert "X-Remove" not in flow_stub.response.headers
|
308
|
+
|
309
|
+
def test_header_ordering_preserved(self):
|
310
|
+
"""Test that header ordering is preserved after minimization"""
|
311
|
+
headers_stub = [
|
312
|
+
(b"Host", b"example.com"),
|
313
|
+
(b"User-Agent", b"test-agent"),
|
314
|
+
(b"Accept", b"application/json"),
|
315
|
+
(b"X-Remove-1", b"bye"),
|
316
|
+
(b"Content-Type", b"application/json"),
|
317
|
+
(b"X-Remove-2", b"bye"),
|
318
|
+
]
|
319
|
+
headers = Headers(headers_stub)
|
320
|
+
|
321
|
+
flow_stub = MitmproxyHTTPFlow(client_conn=None, server_conn=None)
|
322
|
+
flow_stub.request = Request(
|
323
|
+
host="example.com",
|
324
|
+
port=80,
|
325
|
+
method="POST",
|
326
|
+
scheme="http",
|
327
|
+
authority="example.com",
|
328
|
+
path="/",
|
329
|
+
http_version="HTTP/1.1",
|
330
|
+
headers=headers,
|
331
|
+
content=b'{"test": "data"}',
|
332
|
+
trailers=None,
|
333
|
+
timestamp_start=time.time(),
|
334
|
+
timestamp_end=time.time() + 1,
|
335
|
+
)
|
336
|
+
|
337
|
+
minimize_request_headers(flow_stub)
|
338
|
+
|
339
|
+
# Check that remaining headers maintain relative order
|
340
|
+
remaining_headers = list(flow_stub.request.headers.keys())
|
341
|
+
expected_order = ["Host", "User-Agent", "Accept", "Content-Type"]
|
342
|
+
assert remaining_headers == expected_order
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: stoobly-agent
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.10.1
|
4
4
|
Summary: Record, mock, and test HTTP(s) requests. CLI agent for Stoobly
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: Matt Le
|
@@ -17,6 +17,7 @@ Requires-Dist: diff-match-patch (>=v20241021,<20241022)
|
|
17
17
|
Requires-Dist: distro (>=1.9.0,<1.10)
|
18
18
|
Requires-Dist: dnspython (>=2.7.0,<2.8)
|
19
19
|
Requires-Dist: docker (>=7.1.0,<8.0)
|
20
|
+
Requires-Dist: filelock (>=3.19.1,<4.0.0)
|
20
21
|
Requires-Dist: httptools (>=0.4.0)
|
21
22
|
Requires-Dist: jmespath (>=1.0.0)
|
22
23
|
Requires-Dist: mergedeep (>=1.3,<1.4)
|