`GroutClientBasePlugin` and example `GroutClientPlugin` (#1488)
* `GroutClientBasePlugin` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Silence `S113` false positive * Remove example url --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
c703edac0b
commit
0641864478
1
.flake8
1
.flake8
|
@ -82,6 +82,7 @@ extend-ignore =
|
|||
S101 # FIXME: assertions are thrown away in optimized mode, needs audit
|
||||
S104 # FIXME: bind-all interface listen
|
||||
S105 # FIXME: hardcoded password?
|
||||
S113 # FIXME: Call to httpx without timeout (false positive)
|
||||
S303 # FIXME: insecure hash func
|
||||
S311 # FIXME: `random` needs auditing
|
||||
S404 # FIXME: `subprocess` use needs auditing
|
||||
|
|
|
@ -180,11 +180,12 @@ DEFAULT_METRICS_DIRECTORY_PATH = os.path.join(DEFAULT_DATA_DIRECTORY_PATH, "metr
|
|||
|
||||
# Cor plugins enabled by default or via flags
|
||||
DEFAULT_ABC_PLUGINS = [
|
||||
'HttpProtocolHandlerPlugin',
|
||||
'HttpProxyBasePlugin',
|
||||
'HttpWebServerBasePlugin',
|
||||
'WebSocketTransportBasePlugin',
|
||||
'ReverseProxyBasePlugin',
|
||||
"HttpProtocolHandlerPlugin",
|
||||
"HttpProxyBasePlugin",
|
||||
"HttpWebServerBasePlugin",
|
||||
"WebSocketTransportBasePlugin",
|
||||
"ReverseProxyBasePlugin",
|
||||
"GroutClientBasePlugin",
|
||||
]
|
||||
PLUGIN_DASHBOARD = 'proxy.dashboard.ProxyDashboard'
|
||||
PLUGIN_HTTP_PROXY = 'proxy.http.proxy.HttpProxyPlugin'
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
proxy.py
|
||||
~~~~~~~~
|
||||
⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on
|
||||
Network monitoring, controls & Application development, testing, debugging.
|
||||
|
||||
:copyright: (c) 2013-present by Abhinav Singh and contributors.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
|
||||
from proxy.proxy import GroutClientBasePlugin
|
||||
from proxy.common.types import HostPort
|
||||
from proxy.http.parser.parser import HttpParser
|
||||
|
||||
|
||||
class GroutClientPlugin(GroutClientBasePlugin):
|
||||
|
||||
def resolve_route(
|
||||
self,
|
||||
route: str,
|
||||
request: HttpParser,
|
||||
origin: HostPort,
|
||||
server: HostPort,
|
||||
) -> str:
|
||||
print(request, origin, server, '->', route)
|
||||
print(request.header(b'host'), request.path)
|
||||
# Send to localhost:7001 irrespective of the
|
||||
# original "route" value provided to the grout client
|
||||
# OR any custom host:upstream mapping provided through the
|
||||
# --tunnel-route flags.
|
||||
return 'http://localhost:7001'
|
|
@ -20,6 +20,7 @@ import getpass
|
|||
import logging
|
||||
import argparse
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Type, Tuple, Optional, cast
|
||||
|
||||
from .core.ssh import SshTunnelListener, SshHttpProtocolHandler
|
||||
|
@ -28,6 +29,7 @@ from .core.event import EventManager
|
|||
from .http.codes import httpStatusCodes
|
||||
from .common.flag import FlagParser, flags
|
||||
from .http.client import client
|
||||
from .common.types import HostPort
|
||||
from .common.utils import bytes_
|
||||
from .core.work.fd import RemoteFdExecutor
|
||||
from .http.methods import httpMethods
|
||||
|
@ -44,6 +46,7 @@ from .common.constants import (
|
|||
DEFAULT_SSH_LISTENER_KLASS,
|
||||
)
|
||||
from .core.event.metrics import MetricsEventSubscriber
|
||||
from .http.parser.parser import HttpParser
|
||||
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
|
@ -509,3 +512,28 @@ def grout() -> None: # noqa: C901
|
|||
assert env is not None
|
||||
print('\r' + ' ' * 70 + '\r', end='', flush=True)
|
||||
Plugins.from_bytes(env['m'].encode(), name='client').grout(env=env['e']) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
class GroutClientBasePlugin(ABC):
|
||||
"""Base class for dynamic grout client rules.
|
||||
|
||||
Implementation of this class must be stateless because a new instance is created
|
||||
for every route decision making.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def resolve_route(
|
||||
self,
|
||||
route: str,
|
||||
request: HttpParser,
|
||||
origin: HostPort,
|
||||
server: HostPort,
|
||||
) -> str:
|
||||
"""Returns a valid grout route string.
|
||||
|
||||
You MUST override this method. For a simple pass through,
|
||||
simply return the "route" argument value itself. You can also
|
||||
return a dynamic value based upon "request" and "origin" information.
|
||||
E.g. sending to different upstream services based upon request Host header.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
|
Loading…
Reference in New Issue