/// <summary> /// Adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239). /// </summary> public static TransformBuilderContext AddForwarded(this TransformBuilderContext context, bool useHost = true, bool useProto = true, NodeFormat forFormat = NodeFormat.Random, NodeFormat byFormat = NodeFormat.Random, ForwardedTransformActions action = ForwardedTransformActions.Set) { context.UseDefaultForwarders = false; if (action == ForwardedTransformActions.Off) { return(context); } if (byFormat != NodeFormat.None || forFormat != NodeFormat.None || useHost || useProto) { var random = context.Services.GetRequiredService <IRandomFactory>(); context.RequestTransforms.Add(new RequestHeaderForwardedTransform(random, forFormat, byFormat, useHost, useProto, action)); // Remove the X-Forwarded headers when an Forwarded transform is enabled TransformHelpers.RemoveAllXForwardedHeaders(context, ForwardedTransformFactory.DefaultXForwardedPrefix); } return(context); }
public bool Build(TransformBuilderContext context, IReadOnlyDictionary <string, string> transformValues) { if (transformValues.TryGetValue(XForwardedKey, out var headerValue)) { var xExpected = 1; var defaultXAction = Enum.Parse <ForwardedTransformActions>(headerValue); var prefix = DefaultXForwardedPrefix; if (transformValues.TryGetValue(HeaderPrefixKey, out var prefixValue)) { xExpected++; prefix = prefixValue; } var xForAction = defaultXAction; if (transformValues.TryGetValue(ForKey, out headerValue)) { xExpected++; xForAction = Enum.Parse <ForwardedTransformActions>(headerValue); } var xPrefixAction = defaultXAction; if (transformValues.TryGetValue(PrefixKey, out headerValue)) { xExpected++; xPrefixAction = Enum.Parse <ForwardedTransformActions>(headerValue); } var xHostAction = defaultXAction; if (transformValues.TryGetValue(HostKey, out headerValue)) { xExpected++; xHostAction = Enum.Parse <ForwardedTransformActions>(headerValue); } var xProtoAction = defaultXAction; if (transformValues.TryGetValue(ProtoKey, out headerValue)) { xExpected++; xProtoAction = Enum.Parse <ForwardedTransformActions>(headerValue);; } TransformHelpers.CheckTooManyParameters(transformValues, xExpected); context.AddXForwardedFor(prefix + ForKey, xForAction); context.AddXForwardedPrefix(prefix + PrefixKey, xPrefixAction); context.AddXForwardedHost(prefix + HostKey, xHostAction); context.AddXForwardedProto(prefix + ProtoKey, xProtoAction); if (xForAction != ForwardedTransformActions.Off || xPrefixAction != ForwardedTransformActions.Off || xHostAction != ForwardedTransformActions.Off || xProtoAction != ForwardedTransformActions.Off) { // Remove the Forwarded header when an X-Forwarded transform is enabled TransformHelpers.RemoveForwardedHeader(context); } } 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 Forwarded: {token}. Expected 'for', 'host', 'proto', or 'by'"); } } var expected = 1; var headerAction = ForwardedTransformActions.Set; if (transformValues.TryGetValue(ActionKey, out headerValue)) { expected++; headerAction = Enum.Parse <ForwardedTransformActions>(headerValue); } 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 (headerAction != ForwardedTransformActions.Off && (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, headerAction)); // Remove the X-Forwarded headers when an Forwarded transform is enabled TransformHelpers.RemoveAllXForwardedHeaders(context, DefaultXForwardedPrefix); } } else if (transformValues.TryGetValue(ClientCertKey, out var clientCertHeader)) { TransformHelpers.CheckTooManyParameters(transformValues, expected: 1); context.AddClientCertHeader(clientCertHeader); } else { return(false); } return(true); }