Thanks to visit codestin.com
Credit goes to github.com

Skip to content

remove legacy edge proxy and generic proxy #9581

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

Merged
merged 5 commits into from
Nov 9, 2023
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: 0 additions & 1 deletion localstack/aws/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def __init__(self, service_manager: ServiceManager = None) -> None:
handlers.enforce_cors,
handlers.content_decoder,
handlers.serve_localstack_resources, # try to serve internal resources in /_localstack first
handlers.serve_default_listeners, # legacy proxy default listeners
handlers.serve_edge_router_rules,
# start aws handler chain
handlers.parse_pre_signed_url_request,
Expand Down
3 changes: 1 addition & 2 deletions localstack/aws/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
parse_pre_signed_url_request = presigned_url.ParsePreSignedUrlRequest()
# legacy compatibility handlers
serve_edge_router_rules = legacy.EdgeRouterHandler()
serve_default_listeners = legacy.DefaultListenerHandler()
set_close_connection_header = legacy.set_close_connection_header
pop_request_context = legacy.pop_request_context
push_request_context = legacy.push_request_context
pop_request_context = legacy.pop_request_context
16 changes: 8 additions & 8 deletions localstack/aws/handlers/cors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@
from typing import List, Set
from urllib.parse import urlparse

from flask_cors.core import (
ACL_ALLOW_HEADERS,
ACL_CREDENTIALS,
ACL_EXPOSE_HEADERS,
ACL_METHODS,
ACL_ORIGIN,
ACL_REQUEST_HEADERS,
)
from werkzeug.datastructures import Headers

from localstack import config
Expand All @@ -26,6 +18,14 @@

LOG = logging.getLogger(__name__)

# CORS headers
ACL_ALLOW_HEADERS = "Access-Control-Allow-Headers"
ACL_CREDENTIALS = "Access-Control-Allow-Credentials"
ACL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"
ACL_METHODS = "Access-Control-Allow-Methods"
ACL_ORIGIN = "Access-Control-Allow-Origin"
ACL_REQUEST_HEADERS = "Access-Control-Request-Headers"

# header name constants
ACL_REQUEST_PRIVATE_NETWORK = "Access-Control-Request-Private-Network"
ACL_ALLOW_PRIVATE_NETWORK = "Access-Control-Allow-Private-Network"
Expand Down
152 changes: 3 additions & 149 deletions localstack/aws/handlers/legacy.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
""" Handlers for compatibility with legacy edge proxy and the quart http framework."""

import logging
import re
from typing import Mapping

from requests import Response as RequestsResponse

from localstack.constants import HEADER_LOCALSTACK_EDGE_URL, HEADER_LOCALSTACK_REQUEST_URL
from localstack.http import Response
from localstack.http.request import restore_payload
from localstack.services.generic_proxy import ProxyListener, modify_and_forward

from ..accounts import reset_aws_access_key_id, reset_aws_account_id
from ..api import RequestContext
from ..chain import Handler, HandlerChain
from ..chain import HandlerChain
from .routes import RouterHandler

LOG = logging.getLogger(__name__)


def push_request_context(_chain: HandlerChain, context: RequestContext, _response: Response):
# hack for legacy compatibility. various parts of localstack access the global flask/quart/our own request
# context. since we're neither in a flask nor a quart context, we're pushing our own context object into their
# proxy objects, which is terrible, but works because mostly code just accesses "context.request", so we don't
# have to bother pushing a real quart/flask context.
import flask.globals
import quart.globals

from localstack.utils.aws import request_context

context._legacy_flask_cv_request_token = flask.globals._cv_request.set(context)
context._legacy_quart_cv_request_token = quart.globals._cv_request.set(context)
# TODO remove request_context.THREAD_LOCAL and accounts.REQUEST_CTX_TLS
request_context.THREAD_LOCAL.request_context = context.request
# resetting thread local storage to avoid leakage between requests at all cost
reset_aws_access_key_id()
reset_aws_account_id()


def pop_request_context(_chain: HandlerChain, _context: RequestContext, _response: Response):
# hack for legacy compatibility
import flask.globals
import quart.globals

from localstack.utils.aws import request_context

flask.globals._cv_request.reset(_context._legacy_flask_cv_request_token)
quart.globals._cv_request.reset(_context._legacy_quart_cv_request_token)
# TODO remove request_context.THREAD_LOCAL and accounts.REQUEST_CTX_TLS
request_context.THREAD_LOCAL.request_context = None


Expand All @@ -66,129 +46,3 @@ def __init__(self, respond_not_found=False) -> None:
from localstack.services.edge import ROUTER

super().__init__(ROUTER, respond_not_found)


class GenericProxyHandler(Handler):
"""
This handler maps HandlerChain requests to the generic proxy ProxyListener interface `forward_request`.
"""

def __call__(self, chain: HandlerChain, context: RequestContext, response: Response):
request = context.request

# a werkzeug Request consumes form/multipart data from the socket stream, so we need to restore the payload here
data = restore_payload(request)

# TODO: rethink whether this proxy handling is necessary
context.request.headers[HEADER_LOCALSTACK_REQUEST_URL] = context.request.base_url

result = self.forward_request(
context,
method=request.method,
path=request.full_path if request.query_string else request.path,
data=data,
headers=request.headers,
)

if type(result) == int:
chain.respond(status_code=result)
return

if isinstance(result, tuple):
# special case for Kinesis SubscribeToShard
if len(result) == 2:
response.status_code = 200
response.set_response(result[0])
response.headers.update(dict(result[1]))
chain.stop()
return

if isinstance(result, RequestsResponse):
response.status_code = result.status_code
response.set_response(result.content)
# make sure headers are set after the content, so potential content-length headers are overwritten
response.headers.update(dict(result.headers))

# make sure content-length is re-calculated correctly, unless it's a HEAD request
if request.method != "HEAD":
length = response.calculate_content_length()
if length is not None:
response.headers["Content-Length"] = str(length)
chain.stop()
return

raise ValueError("cannot create response for result %s" % result)

def forward_request(
self, context: RequestContext, method: str, path: str, data: bytes, headers: Mapping
):
raise NotImplementedError


class LegacyPluginHandler(GenericProxyHandler):
"""
This adapter exposes Services that are developed as ProxyListener as Handler.
"""

def forward_request(
self, context: RequestContext, method: str, path: str, data: bytes, headers: Mapping
):
from localstack.services.edge import do_forward_request

# TODO: rethink whether this proxy handling is necessary
request = context.request
orig_req_url = request.headers.pop(HEADER_LOCALSTACK_REQUEST_URL, "")
request.headers[HEADER_LOCALSTACK_EDGE_URL] = (
re.sub(r"^([^:]+://[^/]+).*", r"\1", orig_req_url) or request.host_url
)

return do_forward_request(
api=context.service.service_name,
method=method,
path=path,
data=data,
headers=headers,
port=None,
)


class _NoHandlerCalled(Exception):
pass


class _DummyProxyListener(ProxyListener):
def forward_request(self, method, path, data, headers):
raise _NoHandlerCalled


class DefaultListenerHandler(GenericProxyHandler):
"""
Adapter that exposes the ProxyListener.DEFAULT_LISTENERS as a Handler.
"""

def __call__(self, chain: HandlerChain, context: RequestContext, response: Response):
if not ProxyListener.DEFAULT_LISTENERS:
return

try:
super(DefaultListenerHandler, self).__call__(chain, context, response)
except _NoHandlerCalled:
# may be raised by the _DummyProxyListener, which is reached if no other listener is called,
# in which case we don't want to return a result or stop the chain.
return

def forward_request(
self, context: RequestContext, method: str, path: str, data: bytes, headers: Mapping
):
request = context.request

return modify_and_forward(
method=method,
path=path,
data_bytes=data,
headers=headers,
forward_base_url=None,
listeners=[_DummyProxyListener()],
client_address=request.remote_addr,
server_address=request.host,
)
7 changes: 1 addition & 6 deletions localstack/aws/handlers/service_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from ..api import RequestContext
from ..api.core import ServiceOperation
from ..chain import Handler, HandlerChain
from ..proxy import AwsApiListener
from .legacy import LegacyPluginHandler
from .service import ServiceRequestRouter

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -63,10 +61,7 @@ def require_service(self, _: HandlerChain, context: RequestContext, response: Re
if service_operation in request_router.handlers:
return
if isinstance(service_plugin, Service):
if type(service_plugin.listener) == AwsApiListener:
request_router.add_skeleton(service_plugin.listener.skeleton)
else:
request_router.add_handler(service_operation, LegacyPluginHandler())
request_router.add_skeleton(service_plugin.skeleton)
else:
LOG.warning(
f"found plugin for '{service_name}', "
Expand Down
29 changes: 1 addition & 28 deletions localstack/aws/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,14 @@
Adapters and other utilities to use ASF together with the edge proxy.
"""
import logging
from typing import Any

from botocore.model import ServiceModel

from localstack.aws.accounts import (
get_account_id_from_access_key_id,
set_aws_access_key_id,
set_aws_account_id,
)
from localstack.aws.api import RequestContext
from localstack.aws.skeleton import Skeleton
from localstack.aws.spec import load_service
from localstack.constants import TEST_AWS_ACCESS_KEY_ID
from localstack.http import Request, Response
from localstack.http.adapters import ProxyListenerAdapter
from localstack.http import Request
from localstack.utils.aws.aws_stack import extract_access_key_id_from_auth_header
from localstack.utils.aws.request_context import extract_region_from_headers

Expand All @@ -37,23 +30,3 @@ def get_account_id_from_request(request: Request) -> str:
set_aws_account_id(account_id)

return account_id


class AwsApiListener(ProxyListenerAdapter):
service: ServiceModel

def __init__(self, api: str, delegate: Any):
self.service = load_service(api)
self.skeleton = Skeleton(self.service, delegate)

def request(self, request: Request) -> Response:
context = self.create_request_context(request)
return self.skeleton.invoke(context)

def create_request_context(self, request: Request) -> RequestContext:
context = RequestContext()
context.service = self.service
context.request = request
context.region = get_region(request)
context.account_id = get_account_id_from_request(request)
return context
4 changes: 0 additions & 4 deletions localstack/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,6 @@ def in_docker():
# Docker image to use when starting up containers for port checks
PORTS_CHECK_DOCKER_IMAGE = os.environ.get("PORTS_CHECK_DOCKER_IMAGE", "").strip()

# whether to forward edge requests in-memory (instead of via proxy servers listening on backend ports)
# TODO: this will likely become the default and may get removed in the future
FORWARD_EDGE_INMEM = True


def is_trace_logging_enabled():
if LS_LOG:
Expand Down
88 changes: 0 additions & 88 deletions localstack/http/adapters.py

This file was deleted.

Loading