`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:
Abhinav Singh 2024-10-13 15:56:16 +05:30 committed by GitHub
parent c703edac0b
commit 0641864478
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 5 deletions

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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()