<commit_before>// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Internal.Routing;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;

namespace Microsoft.AspNet.Mvc.Routing
{
    /// <summary>
    /// An <see cref="IRouter"/> implementation for attribute routing.
    /// </summary>
    public class InnerAttributeRoute : IRouter
    {
        private readonly IRouter _next;
        private readonly LinkGenerationDecisionTree _linkGenerationTree;
        private readonly AttributeRouteMatchingEntry[] _matchingEntries;
        private readonly IDictionary<string, AttributeRouteLinkGenerationEntry> _namedEntries;

        private ILogger _logger;
        private ILogger _constraintLogger;

        /// <summary>
        /// Creates a new <see cref="InnerAttributeRoute"/>.
        /// </summary>
        /// <param name="next">The next router. Invoked when a route entry matches.</param>
        /// <param name="entries">The set of route entries.</param>
        public InnerAttributeRoute(
            [NotNull] IRouter next,
            [NotNull] IEnumerable<AttributeRouteMatchingEntry> matchingEntries,
            [NotNull] IEnumerable<AttributeRouteLinkGenerationEntry> linkGenerationEntries,
            [NotNull] ILogger logger,
            [NotNull] ILogger constraintLogger,
            int version)
        {
            _next = next;
            _logger = logger;
            _constraintLogger = constraintLogger;

            Version = version;

            // Order all the entries by order, then precedence, and then finally by template in order to provide
            // a stable routing and link generation order for templates with same order and precedence.
            // We use ordinal comparison for the templates because we only care about them being exactly equal and
            // we don't want to make any equivalence between templates based on the culture of the machine.

            _matchingEntries = matchingEntries
                .OrderBy(o => o.Order)
                .ThenBy(e => e.Precedence)
                .ThenBy(e => e.RouteTemplate, StringComparer.Ordinal)
                .ToArray();

            var namedEntries = new Dictionary<string, AttributeRouteLinkGenerationEntry>(
                StringComparer.OrdinalIgnoreCase);

            foreach (var entry in linkGenerationEntries)
            {
                // Skip unnamed entries
                if (entry.Name == null)
                {
                    continue;
                }

                // We only need to keep one AttributeRouteLinkGenerationEntry per route template
                // so in case two entries have the same name and the same template we only keep
                // the first entry.
                AttributeRouteLinkGenerationEntry namedEntry = null;
                if (namedEntries.TryGetValue(entry.Name, out namedEntry) &&
                    !namedEntry.TemplateText.Equals(entry.TemplateText, StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException(
                        Resources.FormatAttributeRoute_DifferentLinkGenerationEntries_SameName(entry.Name),
                        nameof(linkGenerationEntries));
                }
                else if (namedEntry == null)
                {
                    namedEntries.Add(entry.Name, entry);
                }
            }

            _namedEntries = namedEntries;

            // The decision tree will take care of ordering for these entries.
            _linkGenerationTree = new LinkGenerationDecisionTree(linkGenerationEntries.ToArray());
        }

        /// <summary>
        /// Gets the version of this route. This corresponds to the value of
        /// <see cref="ActionDescriptorsCollection.Version"/> when this route was created.
        /// </summary>
        public int Version { get; }

        /// <inheritdoc />
        public async Task RouteAsync([NotNull] RouteContext context)
        {
            foreach(var matchingEntry in _matchingEntries)
            {
                var requestPath = context.HttpContext.Request.Path.Value;

                if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
                {
                    requestPath = requestPath.Substring(1);
                }

                var values = matchingEntry.TemplateMatcher.Match(requestPath);
                if (values == null)
                {
                    // If we got back a null value set, that means the URI did not match
                    continue;
                }

                var oldRouteData = context.RouteData;

                var newRouteData = new RouteData(oldRouteData);
                newRouteData.Routers.Add(matchingEntry.Target);
                MergeValues(newRouteData.Values, values);

                if (!RouteConstraintMatcher.Match(
                    matchingEntry.Constraints,
                    newRouteData.Values,
                    context.HttpContext,
                    this,
                    RouteDirection.IncomingRequest,
                    _constraintLogger))
                {
                    continue;
                }

                _logger.LogInformation(
                    "Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.",
                    matchingEntry.RouteName,
                    matchingEntry.RouteTemplate);

                try
                {<commit_msg>Fix #2996 - Make InnerAttribute logs Verbose<commit_after>// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Internal.Routing;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Logging;

namespace Microsoft.AspNet.Mvc.Routing
{
    /// <summary>
    /// An <see cref="IRouter"/> implementation for attribute routing.
    /// </summary>
    public class InnerAttributeRoute : IRouter
    {
        private readonly IRouter _next;
        private readonly LinkGenerationDecisionTree _linkGenerationTree;
        private readonly AttributeRouteMatchingEntry[] _matchingEntries;
        private readonly IDictionary<string, AttributeRouteLinkGenerationEntry> _namedEntries;

        private ILogger _logger;
        private ILogger _constraintLogger;

        /// <summary>
        /// Creates a new <see cref="InnerAttributeRoute"/>.
        /// </summary>
        /// <param name="next">The next router. Invoked when a route entry matches.</param>
        /// <param name="entries">The set of route entries.</param>
        public InnerAttributeRoute(
            [NotNull] IRouter next,
            [NotNull] IEnumerable<AttributeRouteMatchingEntry> matchingEntries,
            [NotNull] IEnumerable<AttributeRouteLinkGenerationEntry> linkGenerationEntries,
            [NotNull] ILogger logger,
            [NotNull] ILogger constraintLogger,
            int version)
        {
            _next = next;
            _logger = logger;
            _constraintLogger = constraintLogger;

            Version = version;

            // Order all the entries by order, then precedence, and then finally by template in order to provide
            // a stable routing and link generation order for templates with same order and precedence.
            // We use ordinal comparison for the templates because we only care about them being exactly equal and
            // we don't want to make any equivalence between templates based on the culture of the machine.

            _matchingEntries = matchingEntries
                .OrderBy(o => o.Order)
                .ThenBy(e => e.Precedence)
                .ThenBy(e => e.RouteTemplate, StringComparer.Ordinal)
                .ToArray();

            var namedEntries = new Dictionary<string, AttributeRouteLinkGenerationEntry>(
                StringComparer.OrdinalIgnoreCase);

            foreach (var entry in linkGenerationEntries)
            {
                // Skip unnamed entries
                if (entry.Name == null)
                {
                    continue;
                }

                // We only need to keep one AttributeRouteLinkGenerationEntry per route template
                // so in case two entries have the same name and the same template we only keep
                // the first entry.
                AttributeRouteLinkGenerationEntry namedEntry = null;
                if (namedEntries.TryGetValue(entry.Name, out namedEntry) &&
                    !namedEntry.TemplateText.Equals(entry.TemplateText, StringComparison.OrdinalIgnoreCase))
                {
                    throw new ArgumentException(
                        Resources.FormatAttributeRoute_DifferentLinkGenerationEntries_SameName(entry.Name),
                        nameof(linkGenerationEntries));
                }
                else if (namedEntry == null)
                {
                    namedEntries.Add(entry.Name, entry);
                }
            }

            _namedEntries = namedEntries;

            // The decision tree will take care of ordering for these entries.
            _linkGenerationTree = new LinkGenerationDecisionTree(linkGenerationEntries.ToArray());
        }

        /// <summary>
        /// Gets the version of this route. This corresponds to the value of
        /// <see cref="ActionDescriptorsCollection.Version"/> when this route was created.
        /// </summary>
        public int Version { get; }

        /// <inheritdoc />
        public async Task RouteAsync([NotNull] RouteContext context)
        {
            foreach(var matchingEntry in _matchingEntries)
            {
                var requestPath = context.HttpContext.Request.Path.Value;

                if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
                {
                    requestPath = requestPath.Substring(1);
                }

                var values = matchingEntry.TemplateMatcher.Match(requestPath);
                if (values == null)
                {
                    // If we got back a null value set, that means the URI did not match
                    continue;
                }

                var oldRouteData = context.RouteData;

                var newRouteData = new RouteData(oldRouteData);
                newRouteData.Routers.Add(matchingEntry.Target);
                MergeValues(newRouteData.Values, values);

                if (!RouteConstraintMatcher.Match(
                    matchingEntry.Constraints,
                    newRouteData.Values,
                    context.HttpContext,
                    this,
                    RouteDirection.IncomingRequest,
                    _constraintLogger))
                {
                    continue;
                }

                _logger.LogVerbose(
                    "Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.",
                    matchingEntry.RouteName,
                    matchingEntry.RouteTemplate);

                try
                {
{'fraction_non_alphanumeric': 0.0732519422863485, 'fraction_numerical': 0.0010245026893195594, 'mean_word_length': 1.7771455666192508, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3631319', 'n_tokens_mistral': 2675, 'n_tokens_neox': 2525, 'n_words': 783}