Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GroutClientBasePlugin and example GroutClientPlugin #1488

Merged
merged 4 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions proxy/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ def _env_threadless_compliant() -> bool:

# 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'
Expand Down
33 changes: 33 additions & 0 deletions proxy/plugin/grout_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
"""

Check warning on line 2 in proxy/plugin/grout_client.py

View check run for this annotation

Codecov / codecov/patch

proxy/plugin/grout_client.py#L2

Added line #L2 was not covered by tests
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

Check warning on line 15 in proxy/plugin/grout_client.py

View check run for this annotation

Codecov / codecov/patch

proxy/plugin/grout_client.py#L13-L15

Added lines #L13 - L15 were not covered by tests


class GroutClientPlugin(GroutClientBasePlugin):

def resolve_route(

Check warning on line 20 in proxy/plugin/grout_client.py

View check run for this annotation

Codecov / codecov/patch

proxy/plugin/grout_client.py#L20

Added line #L20 was not covered by tests
self,
route: str,
request: HttpParser,
origin: HostPort,
server: HostPort,
) -> str:
print(request, origin, server, '->', route)
print(request.header(b'host'), request.path)

Check warning on line 28 in proxy/plugin/grout_client.py

View check run for this annotation

Codecov / codecov/patch

proxy/plugin/grout_client.py#L27-L28

Added lines #L27 - L28 were not covered by tests
# 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'

Check warning on line 33 in proxy/plugin/grout_client.py

View check run for this annotation

Codecov / codecov/patch

proxy/plugin/grout_client.py#L33

Added line #L33 was not covered by tests
28 changes: 28 additions & 0 deletions proxy/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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
Expand All @@ -28,6 +29,7 @@
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
Expand All @@ -44,6 +46,7 @@
DEFAULT_SSH_LISTENER_KLASS,
)
from .core.event.metrics import MetricsEventSubscriber
from .http.parser.parser import HttpParser


if TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -509,3 +512,28 @@ def _parse() -> Tuple[str, int]:
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