in samcli/local/apigw/local_apigw_service.py [0:0]
def _request_handler(self, **kwargs):
"""
We handle all requests to the host:port. The general flow of handling a request is as follows
* Fetch request from the Flask Global state. This is where Flask places the request and is per thread so
multiple requests are still handled correctly
* Find the Lambda function to invoke by doing a look up based on the request.endpoint and method
* If we don't find the function, we will throw a 502 (just like the 404 and 405 responses we get
from Flask.
* Since we found a Lambda function to invoke, we construct the Lambda Event from the request
* Then Invoke the Lambda function (docker container)
* We then transform the response or errors we get from the Invoke and return the data back to
the caller
Parameters
----------
kwargs dict
Keyword Args that are passed to the function from Flask. This happens when we have path parameters
Returns
-------
Response object
"""
route = self._get_current_route(request)
cors_headers = Cors.cors_to_headers(self.api.cors)
# payloadFormatVersion can only support 2 values: "1.0" and "2.0"
# so we want to do strict validation to make sure it has proper value if provided
# https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
if route.payload_format_version not in [None, "1.0", "2.0"]:
raise PayloadFormatVersionValidateException(
f'{route.payload_format_version} is not a valid value. PayloadFormatVersion must be "1.0" or "2.0"'
)
method, endpoint = self.get_request_methods_endpoints(request)
if method == "OPTIONS" and self.api.cors:
headers = Headers(cors_headers)
return self.service_response("", headers, 200)
try:
# TODO: Rewrite the logic below to use version 2.0 when an invalid value is provided
# the Lambda Event 2.0 is only used for the HTTP API gateway with defined payload format version equal 2.0
# or none, as the default value to be used is 2.0
# https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations.html#apis-apiid-integrations-prop-createintegrationinput-payloadformatversion
if route.event_type == Route.HTTP and route.payload_format_version in [None, "2.0"]:
apigw_endpoint = PathConverter.convert_path_to_api_gateway(endpoint)
route_key = self._v2_route_key(method, apigw_endpoint, route.is_default_route)
event = self._construct_v_2_0_event_http(
request,
self.port,
self.api.binary_media_types,
self.api.stage_name,
self.api.stage_variables,
route_key,
)
elif route.event_type == Route.API:
# The OperationName is only sent to the Lambda Function from API Gateway V1(Rest API).
event = self._construct_v_1_0_event(
request,
self.port,
self.api.binary_media_types,
self.api.stage_name,
self.api.stage_variables,
route.operation_name,
)
else:
# For Http Apis with payload version 1.0, API Gateway never sends the OperationName.
event = self._construct_v_1_0_event(
request,
self.port,
self.api.binary_media_types,
self.api.stage_name,
self.api.stage_variables,
None,
)
except UnicodeDecodeError:
return ServiceErrorResponses.lambda_failure_response()
stdout_stream = io.BytesIO()
stdout_stream_writer = StreamWriter(stdout_stream, auto_flush=True)
try:
self.lambda_runner.invoke(route.function_name, event, stdout=stdout_stream_writer, stderr=self.stderr)
except FunctionNotFound:
return ServiceErrorResponses.lambda_not_found_response()
lambda_response, lambda_logs, _ = LambdaOutputParser.get_lambda_output(stdout_stream)
if self.stderr and lambda_logs:
# Write the logs to stderr if available.
self.stderr.write(lambda_logs)
try:
if route.event_type == Route.HTTP and (
not route.payload_format_version or route.payload_format_version == "2.0"
):
(status_code, headers, body) = self._parse_v2_payload_format_lambda_output(
lambda_response, self.api.binary_media_types, request
)
else:
(status_code, headers, body) = self._parse_v1_payload_format_lambda_output(
lambda_response, self.api.binary_media_types, request, route.event_type
)
except LambdaResponseParseException as ex:
LOG.error("Invalid lambda response received: %s", ex)
return ServiceErrorResponses.lambda_failure_response()
return self.service_response(body, headers, status_code)