diff --git a/src/Nancy.Hosting.Wcf.Tests/NancyWcfGenericServiceFixture.cs b/src/Nancy.Hosting.Wcf.Tests/NancyWcfGenericServiceFixture.cs index 4902b04bbf..fd0b2650ba 100644 --- a/src/Nancy.Hosting.Wcf.Tests/NancyWcfGenericServiceFixture.cs +++ b/src/Nancy.Hosting.Wcf.Tests/NancyWcfGenericServiceFixture.cs @@ -207,7 +207,7 @@ public void Should_not_have_content_type_header_for_not_modified_responses() } }; - A.CallTo(() => fakeEngine.HandleRequest(A.Ignored, A>.Ignored, A.Ignored)) + A.CallTo(() => fakeEngine.HandleRequest(A.Ignored, A>.Ignored, A.Ignored)) .Returns(TaskHelpers.GetCompletedTask(context)); A.CallTo(() => fakeBootstrapper.GetEngine()).Returns(fakeEngine); diff --git a/src/Nancy.Testing.Tests/BrowserFixture.cs b/src/Nancy.Testing.Tests/BrowserFixture.cs index f74e95cd88..b99e672e79 100644 --- a/src/Nancy.Testing.Tests/BrowserFixture.cs +++ b/src/Nancy.Testing.Tests/BrowserFixture.cs @@ -432,7 +432,7 @@ public void Should_add_forms_authentication_cookie_to_the_request() }); var cookie = response.Cookies.Single(c => c.Name == FormsAuthentication.FormsAuthenticationCookieName); - var cookieValue = HttpUtility.UrlDecode(cookie.Value); + var cookieValue = cookie.Value; //Then cookieValue.ShouldEqual(cookieContents); diff --git a/src/Nancy.Tests.Functional/Modules/CookieModule.cs b/src/Nancy.Tests.Functional/Modules/CookieModule.cs new file mode 100644 index 0000000000..7ccd4e550b --- /dev/null +++ b/src/Nancy.Tests.Functional/Modules/CookieModule.cs @@ -0,0 +1,36 @@ +using System; + +namespace Nancy.Tests.Functional.Modules +{ + using Nancy.Cookies; + + public class CookieModule : NancyModule + { + public CookieModule() + { + Get["/setcookie"] = _ => + { + const string value = "HakLqr1OEdi+kQ/s92Rzz9hV1w/vzGZKqWeMQRHRJlwhbbgP87UELJZlYDfbVVLo"; + + var cookie = new NancyCookie("testcookie", value); + + var response = new Response(); + response.WithCookie(cookie); + response.StatusCode = HttpStatusCode.OK; + + return response; + }; + + Get["/getcookie"] = _ => + { + const string value = "HakLqr1OEdi+kQ/s92Rzz9hV1w/vzGZKqWeMQRHRJlwhbbgP87UELJZlYDfbVVLo"; + + var cookie = Context.Request.Cookies["testcookie"]; + + return String.Equals(cookie, value) ? + HttpStatusCode.OK : + HttpStatusCode.InternalServerError; + }; + } + } +} diff --git a/src/Nancy.Tests.Functional/Nancy.Tests.Functional.csproj b/src/Nancy.Tests.Functional/Nancy.Tests.Functional.csproj index 65a90be37f..159d59703f 100644 --- a/src/Nancy.Tests.Functional/Nancy.Tests.Functional.csproj +++ b/src/Nancy.Tests.Functional/Nancy.Tests.Functional.csproj @@ -84,6 +84,7 @@ Properties\SharedAssemblyInfo.cs + @@ -95,6 +96,7 @@ + diff --git a/src/Nancy.Tests.Functional/Tests/CookieFixture.cs b/src/Nancy.Tests.Functional/Tests/CookieFixture.cs new file mode 100644 index 0000000000..0b4864d7e4 --- /dev/null +++ b/src/Nancy.Tests.Functional/Tests/CookieFixture.cs @@ -0,0 +1,23 @@ +namespace Nancy.Tests.Functional.Tests +{ + using Modules; + + using Testing; + using Xunit; + + public class CookieFixture + { + [Fact] + public void Cookie_should_decode_value_correctly() + { + // Given + var browser = new Browser(with => with.Module()); + + // When + var result = browser.Get("/setcookie").Then.Get("/getcookie"); + + // Then + Assert.Equal(HttpStatusCode.OK, result.StatusCode); + } + } +} \ No newline at end of file diff --git a/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs b/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs index e32162a13c..ee203f54d4 100644 --- a/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs +++ b/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs @@ -8,6 +8,7 @@ using Nancy.Cryptography; using Nancy.Culture; using Nancy.Diagnostics; + using Nancy.Helpers; using Nancy.Localization; using Nancy.ModelBinding; using Nancy.Responses.Negotiation; @@ -127,7 +128,7 @@ public void Should_return_main_page_with_valid_auth_cookie() // When var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password")); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("password"))); }); // Then should see our fake provider and not the default testing provider diff --git a/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs b/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs index c94540d61e..ea3b622c51 100644 --- a/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs +++ b/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs @@ -5,6 +5,7 @@ using Nancy.Cookies; using Nancy.Cryptography; using Nancy.Diagnostics; + using Nancy.Helpers; using Nancy.Testing; using Xunit; @@ -108,7 +109,7 @@ public void Should_return_main_page_with_valid_auth_cookie() // When var result = browser.Get(diagsConfig.Path, with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password")); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("password"))); }); // Then @@ -133,7 +134,7 @@ public void Should_return_login_page_with_expired_auth_cookie() // When var result = browser.Get(diagsConfig.Path, with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password", DateTime.Now.AddMinutes(-10))); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("password", DateTime.Now.AddMinutes(-10)))); }); // Then @@ -158,7 +159,7 @@ public void Should_return_login_page_with_auth_cookie_with_incorrect_password() // When var result = browser.Get(diagsConfig.Path, with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("wrongPassword")); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("wrongPassword"))); }); // Then @@ -236,7 +237,7 @@ public void Should_use_rolling_expiry_for_auth_cookie() // When var result = browser.Get(diagsConfig.Path, with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password", expiryDate)); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("password", expiryDate))); }); // Then @@ -263,12 +264,12 @@ public void Should_return_diagnostic_example() // When querying the list of interactive providers var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with => { - with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password")); + with.Cookie(DiagsCookieName, HttpUtility.UrlEncode(this.GetSessionCookieValue("password"))); }); // Then we should see the fake testing provider and not the Nancy provided testing example result.Body.AsString().ShouldNotContain("Fake testing provider"); - result.Body.AsString().Contains("Testing Diagnostic Provider"); + result.Body.AsString().ShouldContain("Testing Diagnostic Provider"); } private string GetSessionCookieValue(string password, DateTime? expiry = null) diff --git a/src/Nancy.Tests/Unit/RequestFixture.cs b/src/Nancy.Tests/Unit/RequestFixture.cs index 38d5086919..0c632a4422 100644 --- a/src/Nancy.Tests/Unit/RequestFixture.cs +++ b/src/Nancy.Tests/Unit/RequestFixture.cs @@ -6,6 +6,7 @@ namespace Nancy.Tests.Unit using System.Linq; using System.Text; using FakeItEasy; + using Nancy.Helpers; using Nancy.IO; using Xunit; using Xunit.Extensions; @@ -542,7 +543,7 @@ public void Should_split_cookie_in_two_parts_only() var cookieData = "Y+M3rcC/7ssXvHTx9pwCbwQVV4g=sp0hUZVApYgGbKZIU4bvXbBCVl9fhSEssEXSGdrt4jVag6PO1oed8lSd+EJD1nzWx4OTTCTZKjYRWeHE97QVND4jJIl+DuKRgJnSl3hWI5gdgGjcxqCSTvMOMGmW3NHLVyKpajGD8tq1DXhXMyXHjTzrCAYl8TGzwyJJGx/gd7VMJeRbAy9JdHOxEUlCKUnPneWN6q+/ITFryAa5hAdfcjXmh4Fgym75whKOMkWO+yM2icdsciX0ShcvnEQ/bXcTHTya6d7dJVfZl7qQ8AgIQv8ucQHxD3NxIvHNPBwms2ClaPds0HG5N+7pu7eMSFZjUHpDrrCnFvYN+JDiG3GMpf98LuCCvxemvipJo2MUkY4J1LvaDFoWA5tIxAfItZJkSIW2d8JPDwFk8OHJy8zhyn8AjD2JFqWaUZr4y9KZOtgI0V0Qlq0mS3mDSlLn29xapgoPHBvykwQjR6TwF2pBLpStsfZa/tXbEv2mc3VO3CnErIA1lEfKNqn9C/Dw6hqW"; var headers = new Dictionary>(); var cookies = new List(); - cookies.Add(string.Format("{0}={1}", cookieName, cookieData)); + cookies.Add(string.Format("{0}={1}", cookieName, HttpUtility.UrlEncode(cookieData))); headers.Add("cookie", cookies); var newUrl = new Url { diff --git a/src/Nancy.Tests/Unit/Sessions/CookieBasedSessionsFixture.cs b/src/Nancy.Tests/Unit/Sessions/CookieBasedSessionsFixture.cs index 1b1a7b1b2b..478164c74e 100644 --- a/src/Nancy.Tests/Unit/Sessions/CookieBasedSessionsFixture.cs +++ b/src/Nancy.Tests/Unit/Sessions/CookieBasedSessionsFixture.cs @@ -82,7 +82,7 @@ public void Should_save_the_session_cookie() response.Cookies.Count.ShouldEqual(1); var cookie = response.Cookies.First(); cookie.Name.ShouldEqual(this.cookieStore.CookieName); - cookie.Value.ShouldEqual("encrypted=key1=val1;key2=val2;"); + cookie.Value.ShouldEqual("encrypted%3dkey1%3dval1%3bkey2%3dval2%3b"); cookie.Expires.ShouldBeNull(); cookie.Path.ShouldBeNull(); cookie.Domain.ShouldBeNull(); @@ -111,7 +111,7 @@ public void Should_saves_url_safe_keys_and_values() cookieStore.Save(session, response); - response.Cookies.First().Value.ShouldEqual("encryptedkey+1=val%3d1;"); + response.Cookies.First().Value.ShouldEqual("encryptedkey%2b1%3dval%253d1%3b"); } [Fact] @@ -169,8 +169,8 @@ public void Should_load_a_multi_valued_session() [Fact] public void Should_load_properly_decode_the_url_safe_session() { - var request = CreateRequest("encryptedkey+1=val%3d1;"); - A.CallTo(() => this.fakeEncryptionProvider.Decrypt("encryptedkey+1=val%3d1;")).Returns("key+1=val%3d1;"); + var request = CreateRequest(HttpUtility.UrlEncode("encryptedkey+1=val%3D1;")); + A.CallTo(() => this.fakeEncryptionProvider.Decrypt("encryptedkey+1=val%3D1;")).Returns("key+1=val%3D1;"); var session = cookieStore.Load(request); @@ -308,7 +308,7 @@ public void Should_be_able_to_load_an_object_previously_saved_to_session() session["testObject"] = payload; store.Save(session, response); var request = new Request("GET", "/", "http"); - request.Cookies.Add(Helpers.HttpUtility.UrlEncode(response.Cookies.First().Name), Helpers.HttpUtility.UrlEncode(response.Cookies.First().Value)); + request.Cookies.Add(response.Cookies.First().Name, response.Cookies.First().Value); var result = store.Load(request); diff --git a/src/Nancy/Request.cs b/src/Nancy/Request.cs index 8e9ae2c169..b6b9332773 100644 --- a/src/Nancy/Request.cs +++ b/src/Nancy/Request.cs @@ -11,6 +11,7 @@ namespace Nancy using IO; using Nancy.Extensions; + using Nancy.Helpers; using Session; /// @@ -192,7 +193,7 @@ private IDictionary GetCookieData() } else { - cookieValue = parts[1]; + cookieValue = HttpUtility.UrlDecode(parts[1]); } cookieDictionary[cookieName] = cookieValue; diff --git a/src/Nancy/Session/CookieBasedSessions.cs b/src/Nancy/Session/CookieBasedSessions.cs index cafeb47129..72d1d28c12 100644 --- a/src/Nancy/Session/CookieBasedSessions.cs +++ b/src/Nancy/Session/CookieBasedSessions.cs @@ -148,7 +148,7 @@ public void Save(ISession session, Response response) var cryptographyConfiguration = this.currentConfiguration.CryptographyConfiguration; var encryptedData = cryptographyConfiguration.EncryptionProvider.Encrypt(sb.ToString()); var hmacBytes = cryptographyConfiguration.HmacProvider.GenerateHmac(encryptedData); - var cookieData = String.Format("{0}{1}", Convert.ToBase64String(hmacBytes), encryptedData); + var cookieData = HttpUtility.UrlEncode(String.Format("{0}{1}", Convert.ToBase64String(hmacBytes), encryptedData)); var cookie = new NancyCookie(this.currentConfiguration.CookieName, cookieData, true) {