protected override void MarshallRequest()

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);
            }
        }