in Libraries/src/Amazon.Lambda.AspNetCoreServer/ApplicationLoadBalancerFunction.cs [57:144]
protected override void MarshallRequest(InvokeFeatures features, ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
// Call consumers customize method in case they want to change how API Gateway's request
// was marshalled into ASP.NET Core request.
PostMarshallHttpAuthenticationFeature(features, lambdaRequest, lambdaContext);
// Request coming from Application Load Balancer will always send the headers X-Amzn-Trace-Id, X-Forwarded-For, X-Forwarded-Port, and X-Forwarded-Proto.
// So this will only happen when writing tests with incomplete sample requests.
if (lambdaRequest.Headers == null && lambdaRequest.MultiValueHeaders == null)
{
throw new Exception("Unable to determine header mode, single or multi value, because both Headers and MultiValueHeaders are null.");
}
if (lambdaRequest.RequestContext?.Elb?.TargetGroupArn == null)
{
_logger.LogWarning($"Request does not contain ELB information but is derived from {nameof(ApplicationLoadBalancerFunction)}.");
}
// Look to see if the request is using mutli value headers or not. This is important when
// marshalling the response to know whether to fill in the the Headers or MultiValueHeaders collection.
// Since a Lambda function compute environment is only one processing one event at a time it is safe to store
// this as a member variable.
this._multiHeaderValuesEnabled = lambdaRequest.MultiValueHeaders != null;
{
var requestFeatures = (IHttpRequestFeature)features;
requestFeatures.Scheme = GetSingleHeaderValue(lambdaRequest, "x-forwarded-proto");
requestFeatures.Method = lambdaRequest.HttpMethod;
var rawPath = lambdaRequest.Path;
var rawQueryString = Utilities.CreateQueryStringParameters(
lambdaRequest.QueryStringParameters, lambdaRequest.MultiValueQueryStringParameters, false);
requestFeatures.RawTarget = rawPath + rawQueryString;
requestFeatures.QueryString = rawQueryString;
requestFeatures.Path = Utilities.DecodeResourcePath(rawPath);
Utilities.SetHeadersCollection(requestFeatures.Headers, lambdaRequest.Headers, lambdaRequest.MultiValueHeaders);
if (!string.IsNullOrEmpty(lambdaRequest.Body))
{
requestFeatures.Body = Utilities.ConvertLambdaRequestBodyToAspNetCoreBody(lambdaRequest.Body, lambdaRequest.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);
}
var userAgent = GetSingleHeaderValue(lambdaRequest, "user-agent");
if (userAgent != null && userAgent.StartsWith("ELB-HealthChecker/", StringComparison.OrdinalIgnoreCase))
{
requestFeatures.Scheme = "https";
requestFeatures.Headers["host"] = "localhost";
requestFeatures.Headers["x-forwarded-port"] = "443";
requestFeatures.Headers["x-forwarded-for"] = "127.0.0.1";
}
// Call consumers customize method in case they want to change how API Gateway's request
// was marshalled into ASP.NET Core request.
PostMarshallRequestFeature(requestFeatures, lambdaRequest, lambdaContext);
}
{
// set up connection features
var connectionFeatures = (IHttpConnectionFeature)features;
var remoteIpAddressStr = GetSingleHeaderValue(lambdaRequest, "x-forwarded-for");
if (!string.IsNullOrEmpty(remoteIpAddressStr) &&
IPAddress.TryParse(remoteIpAddressStr, out var remoteIpAddress))
{
connectionFeatures.RemoteIpAddress = remoteIpAddress;
}
var remotePort = GetSingleHeaderValue(lambdaRequest, "x-forwarded-port");
if (!string.IsNullOrEmpty(remotePort))
{
connectionFeatures.RemotePort = int.Parse(remotePort, 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, lambdaRequest, lambdaContext);
}
}