firegex 3.1.0__tar.gz → 3.2.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.
- {firegex-3.1.0/firegex.egg-info → firegex-3.2.0}/PKG-INFO +4 -1
- firegex-3.2.0/firegex/__init__.py +5 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/internals/__init__.py +6 -2
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/models/http.py +193 -24
- {firegex-3.1.0 → firegex-3.2.0/firegex.egg-info}/PKG-INFO +4 -1
- {firegex-3.1.0 → firegex-3.2.0}/firegex.egg-info/requires.txt +3 -0
- firegex-3.2.0/requirements.txt +9 -0
- {firegex-3.1.0 → firegex-3.2.0}/setup.py +1 -1
- firegex-3.1.0/firegex/__init__.py +0 -5
- firegex-3.1.0/requirements.txt +0 -6
- {firegex-3.1.0 → firegex-3.2.0}/MANIFEST.in +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/README.md +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/fgex +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/__main__.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/cli.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/__init__.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/internals/data.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/internals/exceptions.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/internals/models.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/models/__init__.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/models/tcp.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex/nfproxy/proxysim/__init__.py +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex.egg-info/SOURCES.txt +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex.egg-info/dependency_links.txt +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/firegex.egg-info/top_level.txt +0 -0
- {firegex-3.1.0 → firegex-3.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: firegex
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Firegex client
|
|
5
5
|
Home-page: https://github.com/pwnzer0tt1/firegex
|
|
6
6
|
Author: Pwnzer0tt1
|
|
@@ -13,8 +13,11 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
Requires-Dist: typer==0.15.2
|
|
14
14
|
Requires-Dist: pydantic>=2
|
|
15
15
|
Requires-Dist: typing-extensions>=4.7.1
|
|
16
|
+
Requires-Dist: zstd
|
|
17
|
+
Requires-Dist: brotli
|
|
16
18
|
Requires-Dist: watchfiles
|
|
17
19
|
Requires-Dist: fgex
|
|
20
|
+
Requires-Dist: websockets
|
|
18
21
|
Requires-Dist: pyllhttp
|
|
19
22
|
Dynamic: author
|
|
20
23
|
Dynamic: author-email
|
|
@@ -121,8 +121,7 @@ def handle_packet(glob: dict) -> None:
|
|
|
121
121
|
new_params = params.copy()
|
|
122
122
|
for ele in params[i]:
|
|
123
123
|
new_params[i] = ele
|
|
124
|
-
|
|
125
|
-
yield ele
|
|
124
|
+
yield from try_to_call(new_params)
|
|
126
125
|
is_base_call = False
|
|
127
126
|
break
|
|
128
127
|
if is_base_call:
|
|
@@ -166,4 +165,9 @@ def compile(glob:dict) -> None:
|
|
|
166
165
|
internal_data.invalid_encoding_action = glob["FGEX_INVALID_ENCODING_ACTION"]
|
|
167
166
|
|
|
168
167
|
PacketHandlerResult(glob).reset_result()
|
|
168
|
+
|
|
169
|
+
def fake_exit(*_a, **_k):
|
|
170
|
+
print("WARNING: This function should not be called", flush=True)
|
|
171
|
+
|
|
172
|
+
glob["exit"] = fake_exit
|
|
169
173
|
|
|
@@ -6,6 +6,14 @@ from firegex.nfproxy.internals.models import FullStreamAction, ExceptionAction
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from collections import deque
|
|
8
8
|
from typing import Type
|
|
9
|
+
from zstd import ZSTD_uncompress
|
|
10
|
+
import gzip
|
|
11
|
+
import io
|
|
12
|
+
import zlib
|
|
13
|
+
import brotli
|
|
14
|
+
from websockets.frames import Frame
|
|
15
|
+
from websockets.extensions.permessage_deflate import PerMessageDeflate
|
|
16
|
+
from pyllhttp import PAUSED_H2_UPGRADE, PAUSED_UPGRADE
|
|
9
17
|
|
|
10
18
|
@dataclass
|
|
11
19
|
class InternalHTTPMessage:
|
|
@@ -14,6 +22,7 @@ class InternalHTTPMessage:
|
|
|
14
22
|
headers: dict[str, str] = field(default_factory=dict)
|
|
15
23
|
lheaders: dict[str, str] = field(default_factory=dict) # lowercase copy of the headers
|
|
16
24
|
body: bytes|None = field(default=None)
|
|
25
|
+
body_decoded: bool = field(default=False)
|
|
17
26
|
headers_complete: bool = field(default=False)
|
|
18
27
|
message_complete: bool = field(default=False)
|
|
19
28
|
status: str|None = field(default=None)
|
|
@@ -27,16 +36,21 @@ class InternalHTTPMessage:
|
|
|
27
36
|
method: str = field(default=str)
|
|
28
37
|
content_length: int = field(default=0)
|
|
29
38
|
stream: bytes = field(default_factory=bytes)
|
|
39
|
+
ws_stream: list[Frame] = field(default_factory=list) # Decoded websocket stream
|
|
40
|
+
upgrading_to_h2: bool = field(default=False)
|
|
41
|
+
upgrading_to_ws: bool = field(default=False)
|
|
30
42
|
|
|
31
43
|
@dataclass
|
|
32
44
|
class InternalHttpBuffer:
|
|
33
45
|
"""Internal class to handle HTTP messages"""
|
|
34
46
|
_url_buffer: bytes = field(default_factory=bytes)
|
|
35
|
-
|
|
47
|
+
_raw_header_fields: dict[str, str|list[str]] = field(default_factory=dict)
|
|
48
|
+
_header_fields: dict[str, str] = field(default_factory=dict)
|
|
36
49
|
_body_buffer: bytes = field(default_factory=bytes)
|
|
37
50
|
_status_buffer: bytes = field(default_factory=bytes)
|
|
38
51
|
_current_header_field: bytes = field(default_factory=bytes)
|
|
39
52
|
_current_header_value: bytes = field(default_factory=bytes)
|
|
53
|
+
_ws_packet_stream: bytes = field(default_factory=bytes)
|
|
40
54
|
|
|
41
55
|
class InternalCallbackHandler():
|
|
42
56
|
|
|
@@ -46,6 +60,8 @@ class InternalCallbackHandler():
|
|
|
46
60
|
raised_error = False
|
|
47
61
|
has_begun = False
|
|
48
62
|
messages: deque[InternalHTTPMessage] = deque()
|
|
63
|
+
_ws_extentions = None
|
|
64
|
+
_ws_raised_error = False
|
|
49
65
|
|
|
50
66
|
def reset_data(self):
|
|
51
67
|
self.msg = InternalHTTPMessage()
|
|
@@ -86,14 +102,31 @@ class InternalCallbackHandler():
|
|
|
86
102
|
|
|
87
103
|
def on_header_value_complete(self):
|
|
88
104
|
if self.buffers._current_header_field:
|
|
89
|
-
self.buffers.
|
|
105
|
+
k, v = self.buffers._current_header_field.decode(errors="ignore"), self.buffers._current_header_value.decode(errors="ignore")
|
|
106
|
+
old_value = self.buffers._raw_header_fields.get(k, None)
|
|
107
|
+
|
|
108
|
+
# raw headers are stored as thay were, considering to check changes between headers encoding
|
|
109
|
+
if isinstance(old_value, list):
|
|
110
|
+
old_value.append(v)
|
|
111
|
+
elif isinstance(old_value, str):
|
|
112
|
+
self.buffers._raw_header_fields[k] = [old_value, v]
|
|
113
|
+
else:
|
|
114
|
+
self.buffers._raw_header_fields[k] = v
|
|
115
|
+
|
|
116
|
+
# Decoding headers normally
|
|
117
|
+
kl = k.lower()
|
|
118
|
+
if kl in self.buffers._header_fields:
|
|
119
|
+
self.buffers._header_fields[kl] += f", {v}" # Should be considered as a single list separated by commas as said in the RFC
|
|
120
|
+
else:
|
|
121
|
+
self.buffers._header_fields[kl] = v
|
|
122
|
+
|
|
90
123
|
self.buffers._current_header_field = b""
|
|
91
124
|
self.buffers._current_header_value = b""
|
|
92
125
|
|
|
93
126
|
def on_headers_complete(self):
|
|
94
|
-
self.msg.headers = self.buffers.
|
|
95
|
-
self.msg.lheaders =
|
|
96
|
-
self.buffers.
|
|
127
|
+
self.msg.headers = self.buffers._raw_header_fields
|
|
128
|
+
self.msg.lheaders = self.buffers._header_fields
|
|
129
|
+
self.buffers._raw_header_fields = {}
|
|
97
130
|
self.buffers._current_header_field = b""
|
|
98
131
|
self.buffers._current_header_value = b""
|
|
99
132
|
self.msg.headers_complete = True
|
|
@@ -113,15 +146,56 @@ class InternalCallbackHandler():
|
|
|
113
146
|
|
|
114
147
|
def on_message_complete(self):
|
|
115
148
|
self.msg.body = self.buffers._body_buffer
|
|
149
|
+
self.msg.should_upgrade = self.should_upgrade
|
|
116
150
|
self.buffers._body_buffer = b""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
151
|
+
encodings = [ele.strip() for ele in self.content_encoding.lower().split(",")]
|
|
152
|
+
decode_success = True
|
|
153
|
+
decoding_body = self.msg.body
|
|
154
|
+
for enc in reversed(encodings):
|
|
155
|
+
if not enc:
|
|
156
|
+
continue
|
|
157
|
+
if enc == "deflate":
|
|
158
|
+
try:
|
|
159
|
+
decompress = zlib.decompressobj(-zlib.MAX_WBITS)
|
|
160
|
+
decoding_body = decompress.decompress(decoding_body)
|
|
161
|
+
decoding_body += decompress.flush()
|
|
162
|
+
except Exception as e:
|
|
163
|
+
print(f"Error decompressing deflate: {e}: skipping", flush=True)
|
|
164
|
+
decode_success = False
|
|
165
|
+
break
|
|
166
|
+
elif enc == "br":
|
|
167
|
+
try:
|
|
168
|
+
decoding_body = brotli.decompress(decoding_body)
|
|
169
|
+
except Exception as e:
|
|
170
|
+
print(f"Error decompressing brotli: {e}: skipping", flush=True)
|
|
171
|
+
decode_success = False
|
|
172
|
+
break
|
|
173
|
+
elif enc == "gzip" or enc == "x-gzip": #https://datatracker.ietf.org/doc/html/rfc2616#section-3.5
|
|
174
|
+
try:
|
|
175
|
+
if "gzip" in self.content_encoding.lower():
|
|
176
|
+
with gzip.GzipFile(fileobj=io.BytesIO(decoding_body)) as f:
|
|
177
|
+
decoding_body = f.read()
|
|
178
|
+
except Exception as e:
|
|
179
|
+
print(f"Error decompressing gzip: {e}: skipping", flush=True)
|
|
180
|
+
decode_success = False
|
|
181
|
+
break
|
|
182
|
+
elif enc == "zstd":
|
|
183
|
+
try:
|
|
184
|
+
decoding_body = ZSTD_uncompress(decoding_body)
|
|
185
|
+
except Exception as e:
|
|
186
|
+
print(f"Error decompressing zstd: {e}: skipping", flush=True)
|
|
187
|
+
decode_success = False
|
|
188
|
+
break
|
|
189
|
+
elif enc == "identity":
|
|
190
|
+
pass # No need to do anything https://datatracker.ietf.org/doc/html/rfc2616#section-3.5 (it's possible to be found also if it should't be used)
|
|
191
|
+
else:
|
|
192
|
+
decode_success = False
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
if decode_success:
|
|
196
|
+
self.msg.body = decoding_body
|
|
197
|
+
self.msg.body_decoded = True
|
|
198
|
+
|
|
125
199
|
self.msg.message_complete = True
|
|
126
200
|
self.has_begun = False
|
|
127
201
|
if not self._packet_to_stream():
|
|
@@ -170,20 +244,90 @@ class InternalCallbackHandler():
|
|
|
170
244
|
def content_length_parsed(self) -> int:
|
|
171
245
|
return self.content_length
|
|
172
246
|
|
|
247
|
+
def _is_input(self) -> bool:
|
|
248
|
+
raise NotImplementedError()
|
|
249
|
+
|
|
173
250
|
def _packet_to_stream(self):
|
|
174
251
|
return self.should_upgrade and self.save_body
|
|
175
252
|
|
|
253
|
+
def _stream_parser(self, data: bytes):
|
|
254
|
+
if self.msg.upgrading_to_ws:
|
|
255
|
+
if self._ws_raised_error:
|
|
256
|
+
self.msg.stream += data
|
|
257
|
+
self.msg.total_size += len(data)
|
|
258
|
+
return
|
|
259
|
+
self.buffers._ws_packet_stream += data
|
|
260
|
+
while True:
|
|
261
|
+
try:
|
|
262
|
+
new_frame, self.buffers._ws_packet_stream = self._parse_websocket_frame(self.buffers._ws_packet_stream)
|
|
263
|
+
except Exception as e:
|
|
264
|
+
self._ws_raised_error = True
|
|
265
|
+
self.msg.stream += self.buffers._ws_packet_stream
|
|
266
|
+
self.buffers._ws_packet_stream = b""
|
|
267
|
+
self.msg.total_size += len(data)
|
|
268
|
+
return
|
|
269
|
+
if new_frame is None:
|
|
270
|
+
break
|
|
271
|
+
self.msg.ws_stream.append(new_frame)
|
|
272
|
+
self.msg.total_size += len(new_frame.data)
|
|
273
|
+
if self.msg.upgrading_to_h2:
|
|
274
|
+
self.msg.total_size += len(data)
|
|
275
|
+
self.msg.stream += data
|
|
276
|
+
|
|
277
|
+
def _parse_websocket_ext(self):
|
|
278
|
+
ext_ws = []
|
|
279
|
+
req_ext = []
|
|
280
|
+
for ele in self.msg.lheaders.get("sec-websocket-extensions", "").split(","):
|
|
281
|
+
for xt in ele.split(";"):
|
|
282
|
+
req_ext.append(xt.strip().lower())
|
|
283
|
+
|
|
284
|
+
for ele in req_ext:
|
|
285
|
+
if ele == "permessage-deflate":
|
|
286
|
+
ext_ws.append(PerMessageDeflate(False, False, 15, 15))
|
|
287
|
+
return ext_ws
|
|
288
|
+
|
|
289
|
+
def _parse_websocket_frame(self, data: bytes) -> tuple[Frame|None, bytes]:
|
|
290
|
+
# mask = is_input
|
|
291
|
+
if self._ws_extentions is None:
|
|
292
|
+
self._ws_extentions = self._parse_websocket_ext()
|
|
293
|
+
read_buffering = bytearray()
|
|
294
|
+
def read_exact(n: int):
|
|
295
|
+
nonlocal read_buffering
|
|
296
|
+
buffer = bytearray(read_buffering)
|
|
297
|
+
while len(buffer) < n:
|
|
298
|
+
data = yield
|
|
299
|
+
if data is None:
|
|
300
|
+
raise RuntimeError("Should not send None to this generator")
|
|
301
|
+
buffer.extend(data)
|
|
302
|
+
new_data = bytes(buffer[:n])
|
|
303
|
+
read_buffering = buffer[n:]
|
|
304
|
+
return new_data
|
|
305
|
+
|
|
306
|
+
parsing = Frame.parse(read_exact, extensions=self._ws_extentions, mask=self._is_input())
|
|
307
|
+
parsing.send(None)
|
|
308
|
+
try:
|
|
309
|
+
parsing.send(bytearray(data))
|
|
310
|
+
except StopIteration as e:
|
|
311
|
+
return e.value, read_buffering
|
|
312
|
+
|
|
313
|
+
return None, read_buffering
|
|
314
|
+
|
|
176
315
|
def parse_data(self, data: bytes):
|
|
177
316
|
if self._packet_to_stream(): # This is a websocket upgrade!
|
|
178
|
-
self.
|
|
179
|
-
self.msg.total_size += len(data)
|
|
180
|
-
self.msg.stream += data #buffering stream
|
|
317
|
+
self._stream_parser(data)
|
|
181
318
|
else:
|
|
182
319
|
try:
|
|
183
|
-
self.execute(data)
|
|
320
|
+
reason, consumed = self.execute(data)
|
|
321
|
+
if reason == PAUSED_UPGRADE:
|
|
322
|
+
self.msg.upgrading_to_ws = True
|
|
323
|
+
self.msg.message_complete = True
|
|
324
|
+
self._stream_parser(data[consumed:])
|
|
325
|
+
elif reason == PAUSED_H2_UPGRADE:
|
|
326
|
+
self.msg.upgrading_to_h2 = True
|
|
327
|
+
self.msg.message_complete = True
|
|
328
|
+
self._stream_parser(data[consumed:])
|
|
184
329
|
except Exception as e:
|
|
185
330
|
self.raised_error = True
|
|
186
|
-
print(f"Error parsing HTTP packet: {e} with data {data}", flush=True)
|
|
187
331
|
raise e
|
|
188
332
|
|
|
189
333
|
def pop_message(self):
|
|
@@ -197,18 +341,23 @@ class InternalHttpRequest(InternalCallbackHandler, pyllhttp.Request):
|
|
|
197
341
|
def __init__(self):
|
|
198
342
|
super(InternalCallbackHandler, self).__init__()
|
|
199
343
|
super(pyllhttp.Request, self).__init__()
|
|
344
|
+
|
|
345
|
+
def _is_input(self):
|
|
346
|
+
return True
|
|
200
347
|
|
|
201
348
|
class InternalHttpResponse(InternalCallbackHandler, pyllhttp.Response):
|
|
202
349
|
def __init__(self):
|
|
203
350
|
super(InternalCallbackHandler, self).__init__()
|
|
204
351
|
super(pyllhttp.Response, self).__init__()
|
|
352
|
+
|
|
353
|
+
def _is_input(self):
|
|
354
|
+
return False
|
|
205
355
|
|
|
206
356
|
class InternalBasicHttpMetaClass:
|
|
207
357
|
"""Internal class to handle HTTP requests and responses"""
|
|
208
358
|
|
|
209
359
|
def __init__(self, parser: InternalHttpRequest|InternalHttpResponse, msg: InternalHTTPMessage):
|
|
210
360
|
self._parser = parser
|
|
211
|
-
self.stream = b""
|
|
212
361
|
self.raised_error = False
|
|
213
362
|
self._message: InternalHTTPMessage|None = msg
|
|
214
363
|
self._contructor_hook()
|
|
@@ -269,12 +418,32 @@ class InternalBasicHttpMetaClass:
|
|
|
269
418
|
@property
|
|
270
419
|
def should_upgrade(self) -> bool:
|
|
271
420
|
"""If the message should upgrade"""
|
|
272
|
-
return self.
|
|
421
|
+
return self._parser.should_upgrade
|
|
273
422
|
|
|
274
423
|
@property
|
|
275
424
|
def content_length(self) -> int|None:
|
|
276
425
|
"""Content length of the message"""
|
|
277
426
|
return self._message.content_length
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def upgrading_to_h2(self) -> bool:
|
|
430
|
+
"""If the message is upgrading to HTTP/2"""
|
|
431
|
+
return self._message.upgrading_to_h2
|
|
432
|
+
|
|
433
|
+
@property
|
|
434
|
+
def upgrading_to_ws(self) -> bool:
|
|
435
|
+
"""If the message is upgrading to Websocket"""
|
|
436
|
+
return self._message.upgrading_to_ws
|
|
437
|
+
|
|
438
|
+
@property
|
|
439
|
+
def ws_stream(self) -> list[Frame]:
|
|
440
|
+
"""Websocket stream"""
|
|
441
|
+
return self._message.ws_stream
|
|
442
|
+
|
|
443
|
+
@property
|
|
444
|
+
def stream(self) -> bytes:
|
|
445
|
+
"""Stream of the message"""
|
|
446
|
+
return self._message.stream
|
|
278
447
|
|
|
279
448
|
def get_header(self, header: str, default=None) -> str:
|
|
280
449
|
"""Get a header from the message without caring about the case"""
|
|
@@ -347,8 +516,8 @@ class InternalBasicHttpMetaClass:
|
|
|
347
516
|
if not headers_were_set and parser.msg.headers_complete:
|
|
348
517
|
messages_tosend.append(parser.msg) # Also the current message needs to be sent due to complete headers
|
|
349
518
|
|
|
350
|
-
if
|
|
351
|
-
messages_tosend.append(parser.msg) # Also the current message needs to beacase a
|
|
519
|
+
if parser._packet_to_stream():
|
|
520
|
+
messages_tosend.append(parser.msg) # Also the current message needs to beacase a stream is going on
|
|
352
521
|
|
|
353
522
|
messages_to_call = len(messages_tosend)
|
|
354
523
|
|
|
@@ -379,7 +548,7 @@ class HttpRequest(InternalBasicHttpMetaClass):
|
|
|
379
548
|
return self._parser.msg.method
|
|
380
549
|
|
|
381
550
|
def __repr__(self):
|
|
382
|
-
return f"<HttpRequest method={self.method} url={self.url} headers={self.headers} body={self.body} http_version={self.http_version} keep_alive={self.keep_alive} should_upgrade={self.should_upgrade} headers_complete={self.headers_complete} message_complete={self.message_complete} content_length={self.content_length} stream={self.stream}>"
|
|
551
|
+
return f"<HttpRequest method={self.method} url={self.url} headers={self.headers} body=[{0 if not self.body else len(self.body)} bytes] http_version={self.http_version} keep_alive={self.keep_alive} should_upgrade={self.should_upgrade} headers_complete={self.headers_complete} message_complete={self.message_complete} content_length={self.content_length} stream={self.stream} ws_stream={self.ws_stream}>"
|
|
383
552
|
|
|
384
553
|
class HttpResponse(InternalBasicHttpMetaClass):
|
|
385
554
|
"""
|
|
@@ -401,7 +570,7 @@ class HttpResponse(InternalBasicHttpMetaClass):
|
|
|
401
570
|
return self._parser.msg.status
|
|
402
571
|
|
|
403
572
|
def __repr__(self):
|
|
404
|
-
return f"<HttpResponse status_code={self.status_code} url={self.url} headers={self.headers} body={self.body} http_version={self.http_version} keep_alive={self.keep_alive} should_upgrade={self.should_upgrade} headers_complete={self.headers_complete} message_complete={self.message_complete} content_length={self.content_length} stream={self.stream}>"
|
|
573
|
+
return f"<HttpResponse status_code={self.status_code} url={self.url} headers={self.headers} body=[{0 if not self.body else len(self.body)} bytes] http_version={self.http_version} keep_alive={self.keep_alive} should_upgrade={self.should_upgrade} headers_complete={self.headers_complete} message_complete={self.message_complete} content_length={self.content_length} stream={self.stream} ws_stream={self.ws_stream}>"
|
|
405
574
|
|
|
406
575
|
class HttpRequestHeader(HttpRequest):
|
|
407
576
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: firegex
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Firegex client
|
|
5
5
|
Home-page: https://github.com/pwnzer0tt1/firegex
|
|
6
6
|
Author: Pwnzer0tt1
|
|
@@ -13,8 +13,11 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
Requires-Dist: typer==0.15.2
|
|
14
14
|
Requires-Dist: pydantic>=2
|
|
15
15
|
Requires-Dist: typing-extensions>=4.7.1
|
|
16
|
+
Requires-Dist: zstd
|
|
17
|
+
Requires-Dist: brotli
|
|
16
18
|
Requires-Dist: watchfiles
|
|
17
19
|
Requires-Dist: fgex
|
|
20
|
+
Requires-Dist: websockets
|
|
18
21
|
Requires-Dist: pyllhttp
|
|
19
22
|
Dynamic: author
|
|
20
23
|
Dynamic: author-email
|
|
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
6
6
|
with open('requirements.txt', 'r', encoding='utf-8') as f:
|
|
7
7
|
required = [ele.strip() for ele in f.read().splitlines() if not ele.strip().startswith("#") and ele.strip() != ""]
|
|
8
8
|
|
|
9
|
-
VERSION = "3.
|
|
9
|
+
VERSION = "3.2.0"
|
|
10
10
|
|
|
11
11
|
setuptools.setup(
|
|
12
12
|
name="firegex",
|
firegex-3.1.0/requirements.txt
DELETED
|
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
|