firegex 3.2.0__tar.gz → 3.2.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.
- {firegex-3.2.0/firegex.egg-info → firegex-3.2.2}/PKG-INFO +2 -2
- firegex-3.2.2/firegex/__init__.py +5 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/__init__.py +3 -1
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/internals/data.py +1 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/models/http.py +86 -55
- {firegex-3.2.0 → firegex-3.2.2/firegex.egg-info}/PKG-INFO +2 -2
- {firegex-3.2.0 → firegex-3.2.2}/setup.py +1 -1
- firegex-3.2.0/firegex/__init__.py +0 -5
- {firegex-3.2.0 → firegex-3.2.2}/MANIFEST.in +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/README.md +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/fgex +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/__main__.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/cli.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/internals/__init__.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/internals/exceptions.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/internals/models.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/models/__init__.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/models/tcp.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex/nfproxy/proxysim/__init__.py +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex.egg-info/SOURCES.txt +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex.egg-info/dependency_links.txt +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex.egg-info/requires.txt +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/firegex.egg-info/top_level.txt +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/requirements.txt +0 -0
- {firegex-3.2.0 → firegex-3.2.2}/setup.cfg +0 -0
|
@@ -25,7 +25,9 @@ def pyfilter(func):
|
|
|
25
25
|
|
|
26
26
|
def get_pyfilters():
|
|
27
27
|
"""Returns the list of functions marked with @pyfilter."""
|
|
28
|
-
|
|
28
|
+
if hasattr(pyfilter, "registry"):
|
|
29
|
+
return list(pyfilter.registry)
|
|
30
|
+
return []
|
|
29
31
|
|
|
30
32
|
def clear_pyfilter_registry():
|
|
31
33
|
"""Clears the pyfilter registry."""
|
|
@@ -106,6 +106,7 @@ class DataStreamCtx:
|
|
|
106
106
|
self.__data = glob["__firegex_pyfilter_ctx"]
|
|
107
107
|
self.filter_glob = glob
|
|
108
108
|
self.current_pkt = RawPacket._fetch_packet(self) if init_pkt else None
|
|
109
|
+
self.call_mem = {} #A memory space valid only for the current packet handler
|
|
109
110
|
|
|
110
111
|
@property
|
|
111
112
|
def filter_call_info(self) -> list[FilterHandler]:
|
|
@@ -5,12 +5,12 @@ from firegex.nfproxy.internals.exceptions import StreamFullDrop, StreamFullRejec
|
|
|
5
5
|
from firegex.nfproxy.internals.models import FullStreamAction, ExceptionAction
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from collections import deque
|
|
8
|
-
from typing import Type
|
|
9
8
|
from zstd import ZSTD_uncompress
|
|
10
9
|
import gzip
|
|
11
10
|
import io
|
|
12
11
|
import zlib
|
|
13
12
|
import brotli
|
|
13
|
+
import traceback
|
|
14
14
|
from websockets.frames import Frame
|
|
15
15
|
from websockets.extensions.permessage_deflate import PerMessageDeflate
|
|
16
16
|
from pyllhttp import PAUSED_H2_UPGRADE, PAUSED_UPGRADE
|
|
@@ -260,7 +260,9 @@ class InternalCallbackHandler():
|
|
|
260
260
|
while True:
|
|
261
261
|
try:
|
|
262
262
|
new_frame, self.buffers._ws_packet_stream = self._parse_websocket_frame(self.buffers._ws_packet_stream)
|
|
263
|
-
except Exception
|
|
263
|
+
except Exception:
|
|
264
|
+
print("[WARNING] Websocket parsing failed, passing data to stream...", flush=True)
|
|
265
|
+
traceback.print_exc()
|
|
264
266
|
self._ws_raised_error = True
|
|
265
267
|
self.msg.stream += self.buffers._ws_packet_stream
|
|
266
268
|
self.buffers._ws_packet_stream = b""
|
|
@@ -287,9 +289,11 @@ class InternalCallbackHandler():
|
|
|
287
289
|
return ext_ws
|
|
288
290
|
|
|
289
291
|
def _parse_websocket_frame(self, data: bytes) -> tuple[Frame|None, bytes]:
|
|
290
|
-
# mask = is_input
|
|
291
292
|
if self._ws_extentions is None:
|
|
292
|
-
|
|
293
|
+
if self._is_input():
|
|
294
|
+
self._ws_extentions = [] # Fallback to no options
|
|
295
|
+
else:
|
|
296
|
+
self._ws_extentions = self._parse_websocket_ext() # Extentions used are choosen by the server response
|
|
293
297
|
read_buffering = bytearray()
|
|
294
298
|
def read_exact(n: int):
|
|
295
299
|
nonlocal read_buffering
|
|
@@ -450,70 +454,89 @@ class InternalBasicHttpMetaClass:
|
|
|
450
454
|
return self._message.lheaders.get(header.lower(), default)
|
|
451
455
|
|
|
452
456
|
@staticmethod
|
|
453
|
-
def
|
|
457
|
+
def _before_fetch_callable_checks(internal_data: DataStreamCtx) -> bool:
|
|
454
458
|
raise NotImplementedError()
|
|
455
459
|
|
|
456
460
|
@staticmethod
|
|
457
|
-
def
|
|
458
|
-
|
|
461
|
+
def _parser_class() -> str:
|
|
462
|
+
raise NotImplementedError()
|
|
459
463
|
|
|
460
464
|
@classmethod
|
|
461
465
|
def _fetch_packet(cls, internal_data: DataStreamCtx):
|
|
462
466
|
if internal_data.current_pkt is None or internal_data.current_pkt.is_tcp is False:
|
|
463
467
|
raise NotReadyToRun()
|
|
464
468
|
|
|
465
|
-
ParserType =
|
|
469
|
+
ParserType = InternalHttpRequest if internal_data.current_pkt.is_input else InternalHttpResponse
|
|
470
|
+
parser_key = f"{cls._parser_class()}_{'in' if internal_data.current_pkt.is_input else 'out'}"
|
|
466
471
|
|
|
467
|
-
parser = internal_data.data_handler_context.get(
|
|
472
|
+
parser = internal_data.data_handler_context.get(parser_key, None)
|
|
468
473
|
if parser is None or parser.raised_error:
|
|
469
474
|
parser: InternalHttpRequest|InternalHttpResponse = ParserType()
|
|
470
|
-
internal_data.data_handler_context[
|
|
475
|
+
internal_data.data_handler_context[parser_key] = parser
|
|
476
|
+
|
|
477
|
+
if not internal_data.call_mem.get(cls._parser_class(), False): #Need to parse HTTP
|
|
478
|
+
internal_data.call_mem[cls._parser_class()] = True
|
|
479
|
+
|
|
480
|
+
#Setting websocket options if needed to the client parser
|
|
481
|
+
if internal_data.current_pkt.is_input:
|
|
482
|
+
ext_opt = internal_data.data_handler_context.get(f"{cls._parser_class()}_ws_options_client")
|
|
483
|
+
if ext_opt is not None and parser._ws_extentions != ext_opt:
|
|
484
|
+
parser._ws_extentions = ext_opt
|
|
485
|
+
|
|
486
|
+
# Memory size managment
|
|
487
|
+
if parser.total_size+len(internal_data.current_pkt.data) > internal_data.stream_max_size:
|
|
488
|
+
match internal_data.full_stream_action:
|
|
489
|
+
case FullStreamAction.FLUSH:
|
|
490
|
+
# Deleting parser and re-creating it
|
|
491
|
+
parser.messages.clear()
|
|
492
|
+
parser.msg.total_size -= len(parser.msg.stream)
|
|
493
|
+
parser.msg.stream = b""
|
|
494
|
+
parser.msg.total_size -= len(parser.msg.body)
|
|
495
|
+
parser.msg.body = b""
|
|
496
|
+
print("[WARNING] Flushing stream", flush=True)
|
|
497
|
+
if parser.total_size+len(internal_data.current_pkt.data) > internal_data.stream_max_size:
|
|
498
|
+
parser.reset_data()
|
|
499
|
+
case FullStreamAction.REJECT:
|
|
500
|
+
raise StreamFullReject()
|
|
501
|
+
case FullStreamAction.DROP:
|
|
502
|
+
raise StreamFullDrop()
|
|
503
|
+
case FullStreamAction.ACCEPT:
|
|
504
|
+
raise NotReadyToRun()
|
|
471
505
|
|
|
506
|
+
internal_data.call_mem["headers_were_set"] = parser.msg.headers_complete #This information is usefull for building the real object
|
|
507
|
+
|
|
508
|
+
try:
|
|
509
|
+
parser.parse_data(internal_data.current_pkt.data)
|
|
510
|
+
except Exception as e:
|
|
511
|
+
traceback.print_exc()
|
|
512
|
+
match internal_data.invalid_encoding_action:
|
|
513
|
+
case ExceptionAction.REJECT:
|
|
514
|
+
raise RejectConnection()
|
|
515
|
+
case ExceptionAction.DROP:
|
|
516
|
+
raise DropPacket()
|
|
517
|
+
case ExceptionAction.NOACTION:
|
|
518
|
+
raise e
|
|
519
|
+
case ExceptionAction.ACCEPT:
|
|
520
|
+
raise NotReadyToRun()
|
|
521
|
+
|
|
522
|
+
if parser.should_upgrade and not internal_data.current_pkt.is_input:
|
|
523
|
+
#Creating ws_option for the client
|
|
524
|
+
if not internal_data.data_handler_context.get(f"{cls._parser_class()}_ws_options_client"):
|
|
525
|
+
ext = parser._parse_websocket_ext()
|
|
526
|
+
internal_data.data_handler_context[f"{cls._parser_class()}_ws_options_client"] = ext
|
|
527
|
+
|
|
528
|
+
#Once the parsers has been triggered, we can return the object if needed
|
|
472
529
|
if not cls._before_fetch_callable_checks(internal_data):
|
|
473
530
|
raise NotReadyToRun()
|
|
474
531
|
|
|
475
|
-
# Memory size managment
|
|
476
|
-
if parser.total_size+len(internal_data.current_pkt.data) > internal_data.stream_max_size:
|
|
477
|
-
match internal_data.full_stream_action:
|
|
478
|
-
case FullStreamAction.FLUSH:
|
|
479
|
-
# Deleting parser and re-creating it
|
|
480
|
-
parser.messages.clear()
|
|
481
|
-
parser.msg.total_size -= len(parser.msg.stream)
|
|
482
|
-
parser.msg.stream = b""
|
|
483
|
-
parser.msg.total_size -= len(parser.msg.body)
|
|
484
|
-
parser.msg.body = b""
|
|
485
|
-
print("[WARNING] Flushing stream", flush=True)
|
|
486
|
-
if parser.total_size+len(internal_data.current_pkt.data) > internal_data.stream_max_size:
|
|
487
|
-
parser.reset_data()
|
|
488
|
-
case FullStreamAction.REJECT:
|
|
489
|
-
raise StreamFullReject()
|
|
490
|
-
case FullStreamAction.DROP:
|
|
491
|
-
raise StreamFullDrop()
|
|
492
|
-
case FullStreamAction.ACCEPT:
|
|
493
|
-
raise NotReadyToRun()
|
|
494
|
-
|
|
495
|
-
headers_were_set = parser.msg.headers_complete
|
|
496
|
-
try:
|
|
497
|
-
parser.parse_data(internal_data.current_pkt.data)
|
|
498
|
-
except Exception as e:
|
|
499
|
-
match internal_data.invalid_encoding_action:
|
|
500
|
-
case ExceptionAction.REJECT:
|
|
501
|
-
raise RejectConnection()
|
|
502
|
-
case ExceptionAction.DROP:
|
|
503
|
-
raise DropPacket()
|
|
504
|
-
case ExceptionAction.NOACTION:
|
|
505
|
-
raise e
|
|
506
|
-
case ExceptionAction.ACCEPT:
|
|
507
|
-
raise NotReadyToRun()
|
|
508
|
-
|
|
509
532
|
messages_tosend:list[InternalHTTPMessage] = []
|
|
510
533
|
for i in range(len(parser.messages)):
|
|
511
534
|
messages_tosend.append(parser.pop_message())
|
|
512
535
|
|
|
513
536
|
if len(messages_tosend) > 0:
|
|
514
|
-
headers_were_set = False # New messages completed so the current message headers were not set in this case
|
|
537
|
+
internal_data.call_mem["headers_were_set"] = False # New messages completed so the current message headers were not set in this case
|
|
515
538
|
|
|
516
|
-
if not headers_were_set and parser.msg.headers_complete:
|
|
539
|
+
if not internal_data.call_mem["headers_were_set"] and parser.msg.headers_complete:
|
|
517
540
|
messages_tosend.append(parser.msg) # Also the current message needs to be sent due to complete headers
|
|
518
541
|
|
|
519
542
|
if parser._packet_to_stream():
|
|
@@ -533,10 +556,6 @@ class HttpRequest(InternalBasicHttpMetaClass):
|
|
|
533
556
|
HTTP Request handler
|
|
534
557
|
This data handler will be called twice, first with the headers complete, and second with the body complete
|
|
535
558
|
"""
|
|
536
|
-
|
|
537
|
-
@staticmethod
|
|
538
|
-
def _associated_parser_class() -> Type[InternalHttpRequest]:
|
|
539
|
-
return InternalHttpRequest
|
|
540
559
|
|
|
541
560
|
@staticmethod
|
|
542
561
|
def _before_fetch_callable_checks(internal_data: DataStreamCtx):
|
|
@@ -546,6 +565,10 @@ class HttpRequest(InternalBasicHttpMetaClass):
|
|
|
546
565
|
def method(self) -> bytes:
|
|
547
566
|
"""Method of the request"""
|
|
548
567
|
return self._parser.msg.method
|
|
568
|
+
|
|
569
|
+
@staticmethod
|
|
570
|
+
def _parser_class() -> str:
|
|
571
|
+
return "full_http"
|
|
549
572
|
|
|
550
573
|
def __repr__(self):
|
|
551
574
|
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}>"
|
|
@@ -556,10 +579,6 @@ class HttpResponse(InternalBasicHttpMetaClass):
|
|
|
556
579
|
This data handler will be called twice, first with the headers complete, and second with the body complete
|
|
557
580
|
"""
|
|
558
581
|
|
|
559
|
-
@staticmethod
|
|
560
|
-
def _associated_parser_class() -> Type[InternalHttpResponse]:
|
|
561
|
-
return InternalHttpResponse
|
|
562
|
-
|
|
563
582
|
@staticmethod
|
|
564
583
|
def _before_fetch_callable_checks(internal_data: DataStreamCtx):
|
|
565
584
|
return not internal_data.current_pkt.is_input
|
|
@@ -568,6 +587,10 @@ class HttpResponse(InternalBasicHttpMetaClass):
|
|
|
568
587
|
def status_code(self) -> int:
|
|
569
588
|
"""Status code of the response"""
|
|
570
589
|
return self._parser.msg.status
|
|
590
|
+
|
|
591
|
+
@staticmethod
|
|
592
|
+
def _parser_class() -> str:
|
|
593
|
+
return "full_http"
|
|
571
594
|
|
|
572
595
|
def __repr__(self):
|
|
573
596
|
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}>"
|
|
@@ -580,6 +603,10 @@ class HttpRequestHeader(HttpRequest):
|
|
|
580
603
|
|
|
581
604
|
def _contructor_hook(self):
|
|
582
605
|
self._parser.save_body = False
|
|
606
|
+
|
|
607
|
+
@staticmethod
|
|
608
|
+
def _parser_class() -> str:
|
|
609
|
+
return "header_http"
|
|
583
610
|
|
|
584
611
|
class HttpResponseHeader(HttpResponse):
|
|
585
612
|
"""
|
|
@@ -588,4 +615,8 @@ class HttpResponseHeader(HttpResponse):
|
|
|
588
615
|
"""
|
|
589
616
|
|
|
590
617
|
def _contructor_hook(self):
|
|
591
|
-
self._parser.save_body = False
|
|
618
|
+
self._parser.save_body = False
|
|
619
|
+
|
|
620
|
+
@staticmethod
|
|
621
|
+
def _parser_class() -> str:
|
|
622
|
+
return "header_http"
|
|
@@ -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.2.
|
|
9
|
+
VERSION = "3.2.2"
|
|
10
10
|
|
|
11
11
|
setuptools.setup(
|
|
12
12
|
name="firegex",
|
|
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
|