コード例 #1
0
ファイル: TemplateMatcher.cs プロジェクト: chyftom/Routing
        private bool MatchComplexSegment(TemplateSegment routeSegment,
                                         string requestSegment,
                                         IDictionary <string, object> defaults,
                                         RouteValueDictionary values)
        {
            Contract.Assert(routeSegment != null);
            Contract.Assert(routeSegment.Parts.Count > 1);

            // Find last literal segment and get its last index in the string
            var lastIndex = requestSegment.Length;
            var indexOfLastSegmentUsed = routeSegment.Parts.Count - 1;

            TemplatePart parameterNeedsValue = null; // Keeps track of a parameter segment that is pending a value
            TemplatePart lastLiteral         = null; // Keeps track of the left-most literal we've encountered

            while (indexOfLastSegmentUsed >= 0)
            {
                var newLastIndex = lastIndex;

                var part = routeSegment.Parts[indexOfLastSegmentUsed];
                if (part.IsParameter)
                {
                    // Hold on to the parameter so that we can fill it in when we locate the next literal
                    parameterNeedsValue = part;
                }
                else
                {
                    Contract.Assert(part.IsLiteral);
                    lastLiteral = part;

                    var startIndex = lastIndex - 1;
                    // If we have a pending parameter subsegment, we must leave at least one character for that
                    if (parameterNeedsValue != null)
                    {
                        startIndex--;
                    }

                    if (startIndex < 0)
                    {
                        return(false);
                    }

                    var indexOfLiteral = requestSegment.LastIndexOf(part.Text,
                                                                    startIndex,
                                                                    StringComparison.OrdinalIgnoreCase);
                    if (indexOfLiteral == -1)
                    {
                        // If we couldn't find this literal index, this segment cannot match
                        return(false);
                    }

                    // If the first subsegment is a literal, it must match at the right-most extent of the request URI.
                    // Without this check if your route had "/Foo/" we'd match the request URI "/somethingFoo/".
                    // This check is related to the check we do at the very end of this function.
                    if (indexOfLastSegmentUsed == (routeSegment.Parts.Count - 1))
                    {
                        if ((indexOfLiteral + part.Text.Length) != requestSegment.Length)
                        {
                            return(false);
                        }
                    }

                    newLastIndex = indexOfLiteral;
                }

                if ((parameterNeedsValue != null) &&
                    (((lastLiteral != null) && (part.IsLiteral)) || (indexOfLastSegmentUsed == 0)))
                {
                    // If we have a pending parameter that needs a value, grab that value

                    int parameterStartIndex;
                    int parameterTextLength;

                    if (lastLiteral == null)
                    {
                        if (indexOfLastSegmentUsed == 0)
                        {
                            parameterStartIndex = 0;
                        }
                        else
                        {
                            parameterStartIndex = newLastIndex;
                            Contract.Assert(false, "indexOfLastSegementUsed should always be 0 from the check above");
                        }
                        parameterTextLength = lastIndex;
                    }
                    else
                    {
                        // If we're getting a value for a parameter that is somewhere in the middle of the segment
                        if ((indexOfLastSegmentUsed == 0) && (part.IsParameter))
                        {
                            parameterStartIndex = 0;
                            parameterTextLength = lastIndex;
                        }
                        else
                        {
                            parameterStartIndex = newLastIndex + lastLiteral.Text.Length;
                            parameterTextLength = lastIndex - parameterStartIndex;
                        }
                    }

                    var parameterValueString = requestSegment.Substring(parameterStartIndex, parameterTextLength);

                    if (string.IsNullOrEmpty(parameterValueString))
                    {
                        // If we're here that means we have a segment that contains multiple sub-segments.
                        // For these segments all parameters must have non-empty values. If the parameter
                        // has an empty value it's not a match.
                        return(false);
                    }
                    else
                    {
                        // If there's a value in the segment for this parameter, use the subsegment value
                        values.Add(parameterNeedsValue.Name, parameterValueString);
                    }

                    parameterNeedsValue = null;
                    lastLiteral         = null;
                }

                lastIndex = newLastIndex;
                indexOfLastSegmentUsed--;
            }

            // If the last subsegment is a parameter, it's OK that we didn't parse all the way to the left extent of
            // the string since the parameter will have consumed all the remaining text anyway. If the last subsegment
            // is a literal then we *must* have consumed the entire text in that literal. Otherwise we end up matching
            // the route "Foo" to the request URI "somethingFoo". Thus we have to check that we parsed the *entire*
            // request URI in order for it to be a match.
            // This check is related to the check we do earlier in this function for LiteralSubsegments.
            return((lastIndex == 0) || routeSegment.Parts[0].IsParameter);
        }
コード例 #2
0
        private static bool ParseLiteral(TemplateParserContext context, TemplateSegment segment)
        {
            context.Mark();

            string encoded;

            while (true)
            {
                if (context.Current == Separator)
                {
                    encoded = context.Capture();
                    context.Back();
                    break;
                }
                else if (context.Current == OpenBrace)
                {
                    if (!context.Next())
                    {
                        // This is a dangling open-brace, which is not allowed
                        context.Error = Resources.TemplateRoute_MismatchedParameter;
                        return(false);
                    }

                    if (context.Current == OpenBrace)
                    {
                        // This is an 'escaped' brace in a literal, like "{{foo" - keep going.
                    }
                    else
                    {
                        // We've just seen the start of a parameter, so back up and return
                        context.Back();
                        encoded = context.Capture();
                        context.Back();
                        break;
                    }
                }
                else if (context.Current == CloseBrace)
                {
                    if (!context.Next())
                    {
                        // This is a dangling close-brace, which is not allowed
                        context.Error = Resources.TemplateRoute_MismatchedParameter;
                        return(false);
                    }

                    if (context.Current == CloseBrace)
                    {
                        // This is an 'escaped' brace in a literal, like "{{foo" - keep going.
                    }
                    else
                    {
                        // This is an unbalanced close-brace, which is not allowed
                        context.Error = Resources.TemplateRoute_MismatchedParameter;
                        return(false);
                    }
                }

                if (!context.Next())
                {
                    encoded = context.Capture();
                    break;
                }
            }

            var decoded = encoded.Replace("}}", "}").Replace("{{", "}");

            if (IsValidLiteral(context, decoded))
            {
                segment.Parts.Add(TemplatePart.CreateLiteral(decoded));
                return(true);
            }
            else
            {
                return(false);
            }
        }