in Libraries/src/Amazon.Lambda.AspNetCoreServer/APIGatewayHttpApiV2ProxyFunction.cs [64:199]
protected override void MarshallRequest(InvokeFeatures features, APIGatewayHttpApiV2ProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)
{
{
var authFeatures = (IHttpAuthenticationFeature)features;
var authorizer = apiGatewayRequest?.RequestContext?.Authorizer;
if (authorizer != null)
{
// handling claims output from cognito user pool authorizer
if (authorizer.Jwt?.Claims != null && authorizer.Jwt.Claims.Count != 0)
{
var identity = new ClaimsIdentity(authorizer.Jwt.Claims.Select(
entry => new Claim(entry.Key, entry.Value.ToString())), "AuthorizerIdentity");
_logger.LogDebug(
$"Configuring HttpContext.User with {authorizer.Jwt.Claims.Count} claims coming from API Gateway's Request Context");
authFeatures.User = new ClaimsPrincipal(identity);
}
else
{
// handling claims output from custom lambda authorizer
var identity = new ClaimsIdentity(authorizer.Jwt?.Claims.Select(entry => new Claim(entry.Key, entry.Value)), "AuthorizerIdentity");
_logger.LogDebug(
$"Configuring HttpContext.User with {identity.Claims.Count()} claims coming from API Gateway's Request Context");
authFeatures.User = new ClaimsPrincipal(identity);
}
}
// Call consumers customize method in case they want to change how API Gateway's request
// was marshalled into ASP.NET Core request.
PostMarshallHttpAuthenticationFeature(authFeatures, apiGatewayRequest, lambdaContext);
}
{
var httpInfo = apiGatewayRequest.RequestContext.Http;
var requestFeatures = (IHttpRequestFeature)features;
requestFeatures.Scheme = "https";
requestFeatures.Method = httpInfo.Method;
if (string.IsNullOrWhiteSpace(apiGatewayRequest.RequestContext?.DomainName))
{
_logger.LogWarning($"Request does not contain domain name information but is derived from {nameof(APIGatewayProxyFunction)}.");
}
var rawQueryString = Utilities.CreateQueryStringParametersFromHttpApiV2(apiGatewayRequest.RawQueryString);
requestFeatures.RawTarget = apiGatewayRequest.RawPath + rawQueryString;
requestFeatures.QueryString = rawQueryString;
requestFeatures.Path = Utilities.DecodeResourcePath(httpInfo.Path);
if (!requestFeatures.Path.StartsWith("/"))
{
requestFeatures.Path = "/" + requestFeatures.Path;
}
// If there is a stage name in the resource path strip it out and set the stage name as the base path.
// This is required so that ASP.NET Core will route request based on the resource path without the stage name.
var stageName = apiGatewayRequest.RequestContext.Stage;
if (!string.IsNullOrWhiteSpace(stageName))
{
if (requestFeatures.Path.StartsWith($"/{stageName}"))
{
requestFeatures.Path = requestFeatures.Path.Substring(stageName.Length + 1);
requestFeatures.PathBase = $"/{stageName}";
}
}
// API Gateway HTTP API V2 format supports multiple values for headers by comma separating the values.
if (apiGatewayRequest.Headers != null)
{
foreach(var kvp in apiGatewayRequest.Headers)
{
requestFeatures.Headers[kvp.Key] = new StringValues(kvp.Value?.Split(','));
}
}
if (!requestFeatures.Headers.ContainsKey("Host"))
{
requestFeatures.Headers["Host"] = apiGatewayRequest.RequestContext.DomainName;
}
if (apiGatewayRequest.Cookies != null)
{
// Add Cookies from the event
requestFeatures.Headers["Cookie"] = String.Join("; ", apiGatewayRequest.Cookies);
}
if (!string.IsNullOrEmpty(apiGatewayRequest.Body))
{
requestFeatures.Body = Utilities.ConvertLambdaRequestBodyToAspNetCoreBody(apiGatewayRequest.Body, apiGatewayRequest.IsBase64Encoded);
}
// Make sure the content-length header is set if header was not present.
const string contentLengthHeaderName = "Content-Length";
if (!requestFeatures.Headers.ContainsKey(contentLengthHeaderName))
{
requestFeatures.Headers[contentLengthHeaderName] = requestFeatures.Body == null ? "0" : requestFeatures.Body.Length.ToString(CultureInfo.InvariantCulture);
}
// Call consumers customize method in case they want to change how API Gateway's request
// was marshalled into ASP.NET Core request.
PostMarshallRequestFeature(requestFeatures, apiGatewayRequest, lambdaContext);
}
{
// set up connection features
var connectionFeatures = (IHttpConnectionFeature)features;
if (!string.IsNullOrEmpty(apiGatewayRequest.RequestContext?.Http?.SourceIp) &&
IPAddress.TryParse(apiGatewayRequest.RequestContext.Http.SourceIp, out var remoteIpAddress))
{
connectionFeatures.RemoteIpAddress = remoteIpAddress;
}
if (apiGatewayRequest?.Headers?.TryGetValue("X-Forwarded-Port", out var port) == true)
{
connectionFeatures.RemotePort = int.Parse(port, CultureInfo.InvariantCulture);
}
// Call consumers customize method in case they want to change how API Gateway's request
// was marshalled into ASP.NET Core request.
PostMarshallConnectionFeature(connectionFeatures, apiGatewayRequest, lambdaContext);
}
{
var tlsConnectionFeature = (ITlsConnectionFeature)features;
var clientCertPem = apiGatewayRequest?.RequestContext?.Authentication?.ClientCert?.ClientCertPem;
if (clientCertPem != null)
{
tlsConnectionFeature.ClientCertificate = Utilities.GetX509Certificate2FromPem(clientCertPem);
}
PostMarshallTlsConnectionFeature(tlsConnectionFeature, apiGatewayRequest, lambdaContext);
}
}