示例#1
0
        /// <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);
        }