Skip to content
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
11 changes: 8 additions & 3 deletions localstack-core/localstack/services/moto.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,17 @@ def dispatch_to_moto(context: RequestContext) -> Response:
service = context.service
request = context.request

# Werkzeug might have an issue (to be determined where the responsibility lies) with proxied requests where the
# HTTP location is a full URI and not only a path.
# We need to use the full_raw_url as moto does some path decoding (in S3 for example)
full_raw_path = get_full_raw_path(request)
# remove the query string from the full path to do the matching of the request
raw_path_only = full_raw_path.split("?")[0]
# this is where we skip the HTTP roundtrip between the moto server and the boto client
dispatch = get_dispatcher(service.service_name, request.path)
dispatch = get_dispatcher(service.service_name, raw_path_only)
try:
# we use the full_raw_url as moto might do some path decoding (in S3 for example)
raw_url = get_raw_current_url(
request.scheme, request.host, request.root_path, get_full_raw_path(request)
request.scheme, request.host, request.root_path, full_raw_path
)
response = dispatch(request, raw_url, request.headers)
if not response:
Expand Down
31 changes: 30 additions & 1 deletion tests/aws/test_moto.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

import pytest
from moto.core import DEFAULT_ACCOUNT_ID as DEFAULT_MOTO_ACCOUNT_ID
from rolo import Request

import localstack.aws.accounts
from localstack.aws.api import ServiceException, handler
from localstack.aws.api import RequestContext, ServiceException, handler
from localstack.aws.forwarder import NotImplementedAvoidFallbackError
from localstack.aws.spec import load_service
from localstack.constants import AWS_REGION_US_EAST_1
from localstack.services import moto
from localstack.services.moto import MotoFallbackDispatcher
Expand Down Expand Up @@ -229,6 +231,33 @@ def test_call_with_sqs_returns_service_response():
assert create_queue_response["QueueUrl"].endswith(qname)


@markers.aws.only_localstack
def test_call_with_sns_with_full_uri():
# when requests are being forwarded by a Proxy, the HTTP request can contain the full URI and not only the path
# see https://github.com/localstack/localstack/pull/8962
# by using `request.path`, we would use a full URI in the request, as Werkzeug has issue parsing those proxied
# requests
topic_name = f"queue-{short_uid()}"
sns_request = Request(
"POST",
"/",
raw_path="http://localhost:4566/",
body=f"Action=CreateTopic&Name={topic_name}&Version=2010-03-31",
headers={"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"},
)
sns_service = load_service("sns")
context = RequestContext()
context.account = "test"
context.region = "us-west-1"
context.service = sns_service
context.request = sns_request
context.operation = sns_service.operation_model("CreateTopic")

create_topic_response = moto.call_moto(context)

assert create_topic_response["TopicArn"].endswith(topic_name)


class FakeSqsApi:
@handler("ListQueues", expand=False)
def list_queues(self, context, request):
Expand Down