// https://tools.ietf.org/html/rfc7239#section-6
        private void AppendNode(IPAddress ipAddress, int port, NodeFormat format, StringBuilder builder)
        {
            // "It is important to note that an IPv6 address and any nodename with
            // node-port specified MUST be quoted, since ":" is not an allowed
            // character in "token"."
            var addPort = port != 0 && (format == NodeFormat.IpAndPort || format == NodeFormat.UnknownAndPort || format == NodeFormat.RandomAndPort);
            var ipv6    = (format == NodeFormat.Ip || format == NodeFormat.IpAndPort) &&
                          ipAddress != null && ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6;
            var quote = addPort || ipv6;

            if (quote)
            {
                builder.Append("\"");
            }

            switch (format)
            {
            case NodeFormat.Ip:
            case NodeFormat.IpAndPort:
                if (ipAddress != null)
                {
                    if (ipv6)
                    {
                        builder.Append("[");
                    }
                    builder.Append(ipAddress.ToString());
                    if (ipv6)
                    {
                        builder.Append("]");
                    }
                    break;
                }
                // This primarily happens in test environments that don't use real connections.
                goto case NodeFormat.Unknown;

            case NodeFormat.Unknown:
            case NodeFormat.UnknownAndPort:
                builder.Append("unknown");
                break;

            case NodeFormat.Random:
            case NodeFormat.RandomAndPort:
                AppendRandom(builder);
                break;

            default:
                throw new NotImplementedException(format.ToString());
            }

            if (addPort)
            {
                builder.Append(":");
                builder.Append(port);
            }

            if (quote)
            {
                builder.Append("\"");
            }
        }
Exemple #2
0
        /// <summary>
        /// Clones the route and adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239).
        /// </summary>
        public static RouteConfig WithTransformForwarded(this RouteConfig route, bool useHost = true, bool useProto    = true,
                                                         NodeFormat forFormat = NodeFormat.Random, NodeFormat byFormat = NodeFormat.Random, ForwardedTransformActions action = ForwardedTransformActions.Set)
        {
            var headers = new List <string>();

            if (forFormat != NodeFormat.None)
            {
                headers.Add(ForwardedTransformFactory.ForKey);
            }

            if (byFormat != NodeFormat.None)
            {
                headers.Add(ForwardedTransformFactory.ByKey);
            }

            if (useHost)
            {
                headers.Add(ForwardedTransformFactory.HostKey);
            }

            if (useProto)
            {
                headers.Add(ForwardedTransformFactory.ProtoKey);
            }

            return(route.WithTransform(transform =>
            {
                transform[ForwardedTransformFactory.ForwardedKey] = string.Join(',', headers);
                transform[ForwardedTransformFactory.ActionKey] = action.ToString();

                if (forFormat != NodeFormat.None)
                {
                    transform.Add(ForwardedTransformFactory.ForFormatKey, forFormat.ToString());
                }

                if (byFormat != NodeFormat.None)
                {
                    transform.Add(ForwardedTransformFactory.ByFormatKey, byFormat.ToString());
                }
            }));
        }
Exemple #3
0
        /// <summary>
        /// Clones the route and adds the transform which will add the Forwarded header as defined by [RFC 7239](https://tools.ietf.org/html/rfc7239).
        /// </summary>
        public static ProxyRoute WithTransformForwarded(this ProxyRoute proxyRoute, bool useHost = true, bool useProto = true,
                                                        NodeFormat forFormat = NodeFormat.Random, NodeFormat byFormat  = NodeFormat.Random, bool append = true)
        {
            var headers = new List <string>();

            if (forFormat != NodeFormat.None)
            {
                headers.Add(ForwardedTransformFactory.ForKey);
            }

            if (byFormat != NodeFormat.None)
            {
                headers.Add(ForwardedTransformFactory.ByKey);
            }

            if (useHost)
            {
                headers.Add(ForwardedTransformFactory.HostKey);
            }

            if (useProto)
            {
                headers.Add(ForwardedTransformFactory.ProtoKey);
            }

            return(proxyRoute.WithTransform(transform =>
            {
                transform[ForwardedTransformFactory.ForwardedKey] = string.Join(',', headers);
                transform[ForwardedTransformFactory.AppendKey] = append.ToString();

                if (forFormat != NodeFormat.None)
                {
                    transform.Add(ForwardedTransformFactory.ForFormatKey, forFormat.ToString());
                }

                if (byFormat != NodeFormat.None)
                {
                    transform.Add(ForwardedTransformFactory.ByFormatKey, byFormat.ToString());
                }
            }));
        }
Exemple #4
0
        // Given either Twine, JSON or XML input, return an array
        // containing info about the nodes in that file
        public static NodeInfo[] GetNodesFromText(string text, NodeFormat format)
        {
            // All the nodes we found in this file
            var nodes = new List <NodeInfo> ();

            switch (format)
            {
            case NodeFormat.SingleNodeText:
                // If it starts with a comment, treat it as a single-node file
                var nodeInfo = new NodeInfo();
                nodeInfo.title = "Start";
                nodeInfo.body  = text;
                nodes.Add(nodeInfo);
                break;

            case NodeFormat.JSON:
                // Parse it as JSON
                try
                {
                    nodes = JsonConvert.DeserializeObject <List <NodeInfo> >(text);
                }
                catch (JsonReaderException e)
                {
//					dialogue.LogErrorMessage("Error parsing Yarn input: " + e.Message);
                    Debug.Log("Error parsing Yarn input: " + e.Message);
                }

                break;

            case NodeFormat.Text:

                // check for the existence of at least one "---"+newline sentinel, which divides
                // the headers from the body

                // we use a regex to match either \r\n or \n line endings
                if (System.Text.RegularExpressions.Regex.IsMatch(text, "---.?\n") == false)
                {
//					dialogue.LogErrorMessage("Error parsing input: text appears corrupt (no header sentinel)");
                    Debug.Log("Error parsing input: text appears corrupt (no header sentinel)");
                    break;
                }

                var headerRegex = new System.Text.RegularExpressions.Regex("(?<field>.*): *(?<value>.*)");

                var nodeProperties = typeof(NodeInfo).GetProperties();

                int lineNumber = 0;

                using (var reader = new System.IO.StringReader(text))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        // Create a new node
                        NodeInfo node = new NodeInfo();

                        // Read header lines
                        do
                        {
                            lineNumber++;

                            // skip empty lines
                            if (line.Length == 0)
                            {
                                continue;
                            }

                            // Attempt to parse the header
                            var headerMatches = headerRegex.Match(line);

                            if (headerMatches == null)
                            {
//								dialogue.LogErrorMessage(string.Format("Line {0}: Can't parse header '{1}'", lineNumber, line));
                                Debug.Log(string.Format("Line {0}: Can't parse header '{1}'", lineNumber, line));
                                continue;
                            }

                            var field = headerMatches.Groups["field"].Value;
                            var value = headerMatches.Groups["value"].Value;

                            // Attempt to set the appropriate property using this field
                            foreach (var property in nodeProperties)
                            {
                                if (property.Name != field)
                                {
                                    continue;
                                }

                                // skip properties that can't be written to
                                if (property.CanWrite == false)
                                {
                                    continue;
                                }
                                try
                                {
                                    var    propertyType = property.PropertyType;
                                    object convertedValue;
                                    if (propertyType.IsAssignableFrom(typeof(string)))
                                    {
                                        convertedValue = value;
                                    }
                                    else if (propertyType.IsAssignableFrom(typeof(int)))
                                    {
                                        convertedValue = int.Parse(value);
                                    }
                                    else if (propertyType.IsAssignableFrom(typeof(NodeInfo.Position)))
                                    {
                                        var components = value.Split(',');

                                        // we expect 2 components: x and y
                                        if (components.Length != 2)
                                        {
                                            throw new FormatException();
                                        }

                                        var position = new NodeInfo.Position();
                                        position.x = int.Parse(components[0]);
                                        position.y = int.Parse(components[1]);

                                        convertedValue = position;
                                    }
                                    else
                                    {
                                        throw new NotSupportedException();
                                    }
                                    // we need to box this because structs are value types,
                                    // so calling SetValue using 'node' would just modify a copy of 'node'
                                    object box = node;
                                    property.SetValue(box, convertedValue, null);
                                    node = (NodeInfo)box;
                                    break;
                                }
                                catch (FormatException)
                                {
//									dialogue.LogErrorMessage(string.Format("{0}: Error setting '{1}': invalid value '{2}'", lineNumber, field, value));
                                    Debug.Log(string.Format("{0}: Error setting '{1}': invalid value '{2}'", lineNumber, field, value));
                                }
                                catch (NotSupportedException)
                                {
                                    //								dialogue.LogErrorMessage(string.Format("{0}: Error setting '{1}': This property cannot be set", lineNumber, field));
                                    Debug.Log(string.Format("{0}: Error setting '{1}': This property cannot be set", lineNumber, field));
                                }
                            }
                        } while ((line = reader.ReadLine()) != "---");

                        lineNumber++;

                        // We're past the header; read the body

                        var lines = new List <string>();

                        // Read header lines until we hit the end of node sentinel or the end of the file
                        while ((line = reader.ReadLine()) != "===" && line != null)
                        {
                            lineNumber++;
                            lines.Add(line);
                        }
                        // We're done reading the lines! Zip 'em up into a string and
                        // store it in the body
                        node.body = string.Join("\n", lines.ToArray());

                        // And add this node to the list
                        nodes.Add(node);

                        // And now we're ready to move on to the next line!
                    }
                }
                break;

            default:
                throw new InvalidOperationException("Unknown format " + format.ToString());
            }

            // hooray we're done
            return(nodes.ToArray());
        }