private static StructuredTransformer CreateTransformer(TransformBuilderContext context) { // RequestHeaderOriginalHostKey defaults to false, and CopyRequestHeaders defaults to true. // If RequestHeaderOriginalHostKey was not specified then we need to make sure the transform gets // added anyways to remove the original host. If CopyRequestHeaders is false then we can omit the // transform. if (context.CopyRequestHeaders.GetValueOrDefault(true) && !context.RequestTransforms.Any(item => item is RequestHeaderOriginalHostTransform)) { context.AddOriginalHost(false); } // Add default forwarders only if they haven't already been added or disabled. if (context.UseDefaultForwarders.GetValueOrDefault(true)) { context.AddXForwarded(); } return(new StructuredTransformer( context.CopyRequestHeaders, context.CopyResponseHeaders, context.CopyResponseTrailers, context.RequestTransforms, context.ResponseTransforms, context.ResponseTrailersTransforms)); }
public bool Build(TransformBuilderContext context, IReadOnlyDictionary <string, string> transformValues) { if (transformValues.TryGetValue(XForwardedKey, out var xforwardedHeaders)) { var expected = 1; var append = true; if (transformValues.TryGetValue(AppendKey, out var appendValue)) { expected++; append = bool.Parse(appendValue); } var prefix = "X-Forwarded-"; if (transformValues.TryGetValue(PrefixForwardedKey, out var prefixValue)) { expected++; prefix = prefixValue; } TransformHelpers.CheckTooManyParameters(transformValues, expected); // for, host, proto, Prefix var tokens = xforwardedHeaders.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); bool useFor, useHost, useProto, usePrefix; useFor = useHost = useProto = usePrefix = false; foreach (var token in tokens) { if (string.Equals(token, ForKey, StringComparison.OrdinalIgnoreCase)) { useFor = true; } else if (string.Equals(token, HostKey, StringComparison.OrdinalIgnoreCase)) { useHost = true; } else if (string.Equals(token, ProtoKey, StringComparison.OrdinalIgnoreCase)) { useProto = true; } else if (string.Equals(token, PrefixKey, StringComparison.OrdinalIgnoreCase)) { usePrefix = true; } else { throw new ArgumentException($"Unexpected value for X-Forwarded: {token}. Expected 'for', 'host', 'proto', or 'Prefix'"); } } context.AddXForwarded(prefix, useFor, useHost, useProto, usePrefix, append); } else if (transformValues.TryGetValue(ForwardedKey, out var forwardedHeader)) { var useHost = false; var useProto = false; var useFor = false; var useBy = false; var forFormat = NodeFormat.None; var byFormat = NodeFormat.None; // for, host, proto, Prefix var tokens = forwardedHeader.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (var token in tokens) { if (string.Equals(token, ForKey, StringComparison.OrdinalIgnoreCase)) { useFor = true; forFormat = NodeFormat.Random; // RFC Default } else if (string.Equals(token, ByKey, StringComparison.OrdinalIgnoreCase)) { useBy = true; byFormat = NodeFormat.Random; // RFC Default } else if (string.Equals(token, HostKey, StringComparison.OrdinalIgnoreCase)) { useHost = true; } else if (string.Equals(token, ProtoKey, StringComparison.OrdinalIgnoreCase)) { useProto = true; } else { throw new ArgumentException($"Unexpected value for X-Forwarded: {token}. Expected 'for', 'host', 'proto', or 'by'"); } } var expected = 1; var append = true; if (transformValues.TryGetValue(AppendKey, out var appendValue)) { expected++; append = bool.Parse(appendValue); } if (useFor && transformValues.TryGetValue(ForFormatKey, out var forFormatString)) { expected++; forFormat = Enum.Parse <NodeFormat>(forFormatString, ignoreCase: true); } if (useBy && transformValues.TryGetValue(ByFormatKey, out var byFormatString)) { expected++; byFormat = Enum.Parse <NodeFormat>(byFormatString, ignoreCase: true); } TransformHelpers.CheckTooManyParameters(transformValues, expected); context.UseDefaultForwarders = false; if (useBy || useFor || useHost || useProto) { // Not using the extension to avoid resolving the random factory each time. context.RequestTransforms.Add(new RequestHeaderForwardedTransform(_randomFactory, forFormat, byFormat, useHost, useProto, append)); } } else if (transformValues.TryGetValue(ClientCertKey, out var clientCertHeader)) { TransformHelpers.CheckTooManyParameters(transformValues, expected: 1); context.AddClientCertHeader(clientCertHeader); } else { return(false); } return(true); }
// This is separate from Build for testing purposes. internal StructuredTransformer BuildInternal(ProxyRoute route, Cluster cluster) { var rawTransforms = route.Transforms; var context = new TransformBuilderContext { Services = _services, Route = route, Cluster = cluster, }; if (rawTransforms?.Count > 0) { foreach (var rawTransform in rawTransforms) { var handled = false; foreach (var factory in _factories) { if (factory.Build(context, rawTransform)) { handled = true; break; } } if (!handled) { throw new ArgumentException($"Unknown transform: {string.Join(';', rawTransform.Keys)}"); } } } // Let the app add any more transforms it wants. foreach (var transformProvider in _providers) { transformProvider.Apply(context); } // Suppress the host by default if (context.CopyRequestHeaders.GetValueOrDefault(true) && !context.UseOriginalHost.GetValueOrDefault()) { // Headers were automatically copied, remove the Host header afterwards. context.RequestTransforms.Add(new RequestHeaderValueTransform(HeaderNames.Host, string.Empty, append: false)); } else if (!context.CopyRequestHeaders.GetValueOrDefault(true) && context.UseOriginalHost.GetValueOrDefault()) { // Headers were not copied, copy the Host manually. context.RequestTransforms.Add(RequestCopyHostTransform.Instance); } // Add default forwarders only if they haven't already been added or disabled. if (context.UseDefaultForwarders.GetValueOrDefault(true)) { context.AddXForwarded(); } return(new StructuredTransformer( context.CopyRequestHeaders, context.CopyResponseHeaders, context.CopyResponseTrailers, context.RequestTransforms, context.ResponseTransforms, context.ResponseTrailersTransforms)); }
// This is separate from Build for testing purposes. internal StructuredTransformer BuildInternal(ProxyRoute route, Cluster cluster) { var rawTransforms = route.Transforms; var context = new TransformBuilderContext { Services = _services, Route = route, Cluster = cluster, }; if (rawTransforms?.Count > 0) { foreach (var rawTransform in rawTransforms) { var handled = false; foreach (var factory in _factories) { if (factory.Build(context, rawTransform)) { handled = true; break; } } if (!handled) { throw new ArgumentException($"Unknown transform: {string.Join(';', rawTransform.Keys)}"); } } } // Let the app add any more transforms it wants. foreach (var transformProvider in _providers) { transformProvider.Apply(context); } // RequestHeaderOriginalHostKey defaults to false, and CopyRequestHeaders defaults to true. // If RequestHeaderOriginalHostKey was not specified then we need to make sure the transform gets // added anyways to remove the original host. If CopyRequestHeaders is false then we can omit the // transform. if (context.CopyRequestHeaders.GetValueOrDefault(true) && !context.RequestTransforms.Any(item => item is RequestHeaderOriginalHostTransform)) { context.AddOriginalHost(false); } // Add default forwarders only if they haven't already been added or disabled. if (context.UseDefaultForwarders.GetValueOrDefault(true)) { context.AddXForwarded(); } return(new StructuredTransformer( context.CopyRequestHeaders, context.CopyResponseHeaders, context.CopyResponseTrailers, context.RequestTransforms, context.ResponseTransforms, context.ResponseTrailersTransforms)); }