diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index ebee151364..39ad21f15c 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -212,6 +212,7 @@
+
diff --git a/src/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs b/src/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs
new file mode 100644
index 0000000000..f13b94a669
--- /dev/null
+++ b/src/Umbraco.Tests/Web/HttpCookieExtensionsTests.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Web;
+
+namespace Umbraco.Tests.Web
+{
+ [TestFixture]
+ public class HttpCookieExtensionsTests
+ {
+ [TestCase("hello=world;cookies=are fun;", "hello", "world", true)]
+ [TestCase("HELlo=world;cookies=are fun", "hello", "world", true)]
+ [TestCase("HELlo= world;cookies=are fun", "hello", "world", true)]
+ [TestCase("HELlo =world;cookies=are fun", "hello", "world", true)]
+ [TestCase("hello = world;cookies=are fun;", "hello", "world", true)]
+ [TestCase("hellos=world;cookies=are fun", "hello", "world", false)]
+ [TestCase("hello=world;cookies?=are fun?", "hello", "world", true)]
+ [TestCase("hel?lo=world;cookies=are fun?", "hel?lo", "world", true)]
+ public void Get_Cookie_Value_From_HttpRequestHeaders(string cookieHeaderVal, string cookieName, string cookieVal, bool matches)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
+ var requestHeaders = request.Headers;
+ requestHeaders.Add("Cookie", cookieHeaderVal);
+
+ var valueFromHeader = requestHeaders.GetCookieValue(cookieName);
+
+ if (matches)
+ {
+ Assert.IsNotNull(valueFromHeader);
+ Assert.AreEqual(cookieVal, valueFromHeader);
+ }
+ else
+ {
+ Assert.IsNull(valueFromHeader);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/HttpCookieExtensions.cs b/src/Umbraco.Web/HttpCookieExtensions.cs
index 7aec1466da..d67e1894fd 100644
--- a/src/Umbraco.Web/HttpCookieExtensions.cs
+++ b/src/Umbraco.Web/HttpCookieExtensions.cs
@@ -16,6 +16,43 @@ namespace Umbraco.Web
///
internal static class HttpCookieExtensions
{
+ ///
+ /// Retrieves an individual cookie from the cookies collection
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Adapted from: https://stackoverflow.com/a/29057304/5018 because there's an issue with .NET WebApi cookie parsing logic
+ /// when using requestHeaders.GetCookies() when an invalid cookie name is present.
+ ///
+ public static string GetCookieValue(this HttpRequestHeaders requestHeaders, string cookieName)
+ {
+ var cookieRequestHeader = requestHeaders
+ .Where(h => h.Key.Equals("Cookie", StringComparison.InvariantCultureIgnoreCase))
+ .ToArray();
+
+ if (cookieRequestHeader.Length == 0)
+ return null;
+
+ var cookiesHeader = cookieRequestHeader[0];
+
+ var cookiesHeaderValue = cookiesHeader.Value.FirstOrDefault();
+ if (cookiesHeaderValue == null)
+ return null;
+
+ var cookieCollection = cookiesHeaderValue.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var cookieNameValue in cookieCollection)
+ {
+ var parts = cookieNameValue.Split(new[] {'='}, StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length != 2) continue;
+ if (parts[0].Trim().InvariantEquals(cookieName))
+ return parts[1].Trim();
+ }
+
+ return null;
+ }
+
///
/// Removes the cookie from the request and the response if it exists
///
diff --git a/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs b/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
index 0f2a7ac442..b83b4114a3 100644
--- a/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
+++ b/src/Umbraco.Web/WebApi/Filters/AngularAntiForgeryHelper.cs
@@ -107,41 +107,13 @@ namespace Umbraco.Web.WebApi.Filters
///
public static bool ValidateHeaders(HttpRequestHeaders requestHeaders, out string failedReason)
{
- var cookieToken = GetCookie(requestHeaders, CsrfValidationCookieName);
+ var cookieToken = requestHeaders.GetCookieValue(CsrfValidationCookieName);
return ValidateHeaders(
requestHeaders.ToDictionary(x => x.Key, x => x.Value).ToArray(),
cookieToken == null ? null : cookieToken,
out failedReason);
}
-
- ///
- /// Retrieves an individual cookie from the cookies collection
- /// Adapted from: https://stackoverflow.com/a/29057304/5018
- ///
- ///
- ///
- ///
- private static string GetCookie(HttpRequestHeaders requestHeaders, string cookieName)
- {
- var cookieRequestHeader = requestHeaders.Where(h => h.Key.Equals("Cookie", StringComparison.InvariantCultureIgnoreCase)).ToArray();
- if (cookieRequestHeader.Any() == false)
- return null;
-
- var cookiesHeader = cookieRequestHeader.FirstOrDefault();
- if (cookiesHeader.Value == null)
- return null;
-
- var cookiesHeaderValue = cookiesHeader.Value.FirstOrDefault();
- if (cookiesHeaderValue == null)
- return null;
-
- var cookieCollection = cookiesHeaderValue.Split(';');
- var cookiePair = cookieCollection.FirstOrDefault(c => c.Trim().StartsWith(cookieName, StringComparison.InvariantCultureIgnoreCase));
- if (cookiePair == null)
- return null;
-
- return cookiePair.Trim().Substring(cookieName.Length + 1);
- }
+
}
}
\ No newline at end of file