protected override void MarshallRequest()

in Libraries/src/Amazon.Lambda.AspNetCoreServer/APIGatewayProxyFunction.cs [115:274]


        protected override void MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest 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.Claims != null && authorizer.Claims.Count != 0)
                    {
                        var identity = new ClaimsIdentity(authorizer.Claims.Select(
                            entry => new Claim(entry.Key, entry.Value.ToString())), "AuthorizerIdentity");

                        _logger.LogDebug(
                            $"Configuring HttpContext.User with {authorizer.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.Where(x => x.Value != null && !string.Equals(x.Key, "claims", StringComparison.OrdinalIgnoreCase))
                                .Select(entry => new Claim(entry.Key, entry.Value.ToString())), "AuthorizerIdentity");

                        _logger.LogDebug(
                            $"Configuring HttpContext.User with {authorizer.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 requestFeatures = (IHttpRequestFeature)features;
                requestFeatures.Scheme = "https";
                requestFeatures.Method = apiGatewayRequest.HttpMethod;

                string path = null;

                // Replaces {proxy+} in path, if exists
                if (apiGatewayRequest.PathParameters != null && apiGatewayRequest.PathParameters.TryGetValue("proxy", out var proxy) &&
                    !string.IsNullOrEmpty(apiGatewayRequest.Resource))
                {
                    var proxyPath = proxy;
                    path = apiGatewayRequest.Resource.Replace("{proxy+}", proxyPath);

                    // Adds all the rest of non greedy parameters in apiGateway.Resource to the path
                    foreach (var pathParameter in apiGatewayRequest.PathParameters.Where(pp => pp.Key != "proxy"))
                    {
                        path = path.Replace($"{{{pathParameter.Key}}}", pathParameter.Value);
                    }
                }
 
                if (string.IsNullOrEmpty(path))
                {
                    path = apiGatewayRequest.Path;
                }

                if (!path.StartsWith("/"))
                {
                    path = "/" + path;
                }

                var rawQueryString = Utilities.CreateQueryStringParameters(
                    apiGatewayRequest.QueryStringParameters, apiGatewayRequest.MultiValueQueryStringParameters, true);

                requestFeatures.RawTarget = apiGatewayRequest.Path + rawQueryString;
                requestFeatures.QueryString = rawQueryString;
                requestFeatures.Path = path;

                requestFeatures.PathBase = string.Empty;
                if (!string.IsNullOrEmpty(apiGatewayRequest?.RequestContext?.Path))
                {
                    // This is to cover the case where the request coming in is https://myapigatewayid.execute-api.us-west-2.amazonaws.com/Prod where
                    // Prod is the stage name and there is no ending '/'. Path will be set to '/' so to make sure we detect the correct base path
                    // append '/' on the end to make the later EndsWith and substring work correctly.
                    var requestContextPath = apiGatewayRequest.RequestContext.Path;
                    if (path.EndsWith("/") && !requestContextPath.EndsWith("/"))
                    {
                        requestContextPath += "/";
                    }
                    else if (!path.EndsWith("/") && requestContextPath.EndsWith("/"))
                    {
                        // Handle a trailing slash in the request path: e.g. https://myapigatewayid.execute-api.us-west-2.amazonaws.com/Prod/foo/
                        requestFeatures.Path = path += "/";
                    }

                    if (requestContextPath.EndsWith(path))
                    {
                        requestFeatures.PathBase = requestContextPath.Substring(0,
                            requestContextPath.Length - requestFeatures.Path.Length);
                    }
                }

                requestFeatures.Path = Utilities.DecodeResourcePath(requestFeatures.Path);

                Utilities.SetHeadersCollection(requestFeatures.Headers, apiGatewayRequest.Headers, apiGatewayRequest.MultiValueHeaders);

                if (!requestFeatures.Headers.ContainsKey("Host"))
                {
                    var apiId = apiGatewayRequest?.RequestContext?.ApiId ?? "";
                    var stage = apiGatewayRequest?.RequestContext?.Stage ?? "";

                    requestFeatures.Headers["Host"] = $"apigateway-{apiId}-{stage}";
                }


                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?.Identity?.SourceIp) &&
                    IPAddress.TryParse(apiGatewayRequest.RequestContext.Identity.SourceIp, out var remoteIpAddress))
                {
                    connectionFeatures.RemoteIpAddress = remoteIpAddress;
                }

                if (apiGatewayRequest?.Headers?.TryGetValue("X-Forwarded-Port", out var forwardedPort) == true)
                {
                    connectionFeatures.RemotePort = int.Parse(forwardedPort, 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?.Identity?.ClientCert?.ClientCertPem;
                if (clientCertPem != null)
                {
                    tlsConnectionFeature.ClientCertificate = Utilities.GetX509Certificate2FromPem(clientCertPem);
                }
                PostMarshallTlsConnectionFeature(tlsConnectionFeature, apiGatewayRequest, lambdaContext);
            }
        }