Skip to content

Commit

Permalink
Fixes #380, added case correction for query string parameters in case…
Browse files Browse the repository at this point in the history
… a user-entered query string contains keys that are not the same case as those that are configured in either preservedRouteParameters or route values.
  • Loading branch information
NightOwl888 committed Jan 30, 2015
1 parent 498feab commit b868191
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Collections.Specialized;

namespace MvcSiteMapProvider.Collections.Specialized
{
/// <summary>
/// Provides extension methods for the <see cref="T:System.Collections.Specialized.NameValueCollection"/>.
/// </summary>
public static class NameValueCollectionExtensions
{
public static void AddWithCaseCorrection(this NameValueCollection nameValueCollection, string key, string value, IEnumerable<string> correctCaseKeyset)
{
var loweredKey = key.ToLowerInvariant();
foreach (var item in correctCaseKeyset)
{
if (item.ToLowerInvariant().Equals(loweredKey))
{
// Add item with corrected case key
nameValueCollection.Add(item, value);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
<Compile Include="Collections\LockableList.cs" />
<Compile Include="Collections\CacheableDictionary.cs" />
<Compile Include="Collections\CacheableList.cs" />
<Compile Include="Collections\Specialized\NameValueCollectionExtensions.cs" />
<Compile Include="Collections\Specialized\ReservedKeyException.cs" />
<Compile Include="Collections\Specialized\SourceMetadataDictionary.cs" />
<Compile Include="CompositeSiteMapNodeProvider.cs" />
Expand Down
46 changes: 44 additions & 2 deletions src/MvcSiteMapProvider/MvcSiteMapProvider/SiteMapNode.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
Expand Down Expand Up @@ -620,7 +621,7 @@ protected virtual void PreserveRouteParameters()
{
var requestContext = this.mvcContextFactory.CreateRequestContext();
var routeDataValues = requestContext.RouteData.Values;
var queryStringValues = requestContext.HttpContext.Request.QueryString;
var queryStringValues = this.GetCaseCorrectedQueryString(requestContext.HttpContext);

foreach (var item in this.PreservedRouteParameters)
{
Expand All @@ -642,6 +643,47 @@ protected virtual void PreserveRouteParameters()
}
}

/// <summary>
/// Gets a <see cref="T:System.Collections.Specialized.NameValueCollection"/> containing the query string
/// key value pairs for the passed in HTTP context. The casing of the keys corrected to be the same as the values that are
/// configured either in the <see cref="P:RouteValues"/> dictionary or the <see cref="P:PreservedRouteParameters"/> collection.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <returns>A <see cref="T:System.Collections.Specialized.NameValueCollection"/> containing the case-corrected
/// key value pairs of the query string.</returns>
protected virtual NameValueCollection GetCaseCorrectedQueryString(HttpContextBase httpContext)
{
var queryStringValues = httpContext.Request.QueryString;
// Note: we must use the configured route values, rather than the RouteValue property to avoid an
// infinite loop.
var caseInsensitiveRouteKeys = new HashSet<string>(this.routeValues.Keys, StringComparer.InvariantCultureIgnoreCase);
var caseInsensitivePreservedRouteParameters = new HashSet<string>(this.PreservedRouteParameters, StringComparer.InvariantCultureIgnoreCase);
var result = new NameValueCollection();

foreach (var key in queryStringValues.AllKeys)
{
// A malformed URL could have a null key
if (key != null)
{
if (caseInsensitivePreservedRouteParameters.Contains(key))
{
result.AddWithCaseCorrection(key, queryStringValues[key], caseInsensitivePreservedRouteParameters);
}
else if (caseInsensitiveRouteKeys.Contains(key))
{
result.AddWithCaseCorrection(key, queryStringValues[key], caseInsensitiveRouteKeys);
}
else
{
// If the value is not configured, add it to the dictionary with the original case.
result.Add(key, queryStringValues[key]);
}
}
}

return result;
}

/// <summary>
/// Flag to ensure the route values are only preserved from the current request a single time.
/// </summary>
Expand Down Expand Up @@ -718,7 +760,7 @@ protected virtual IDictionary<string, object> MergeRouteValuesAndNamedQueryStrin
var result = new Dictionary<string, object>(routeValues);

// Add any query string values from the current context
var queryStringValues = httpContext.Request.QueryString;
var queryStringValues = this.GetCaseCorrectedQueryString(httpContext);

// QueryString collection might contain nullable keys
foreach (var key in queryStringValues.AllKeys)
Expand Down

0 comments on commit b868191

Please sign in to comment.