[Foundation] Add CookieContainer support in NSUrlSessionHandler.#7654
Conversation
There are two important things to look at this: 1. That we do set the cookies that are present in the CookieContainer in the request. That is, we need to set Cookie headers for all of them. 2. That if we receive a Set-Cookie from the server, the CookieContainer gets correctly updated else we will have issues since we do not respect the data sent from the server side. Tests show both that we are setting the Cookie header and that we honour the Set-Cookie header. Fixes: dotnet#5665
|
Build failure Test results1 tests failed, 86 tests passed.Failed tests
|
chamons
left a comment
There was a problem hiding this comment.
Love the test. I think you left in debug spam.
| { | ||
| var uri = new Uri (url.AbsoluteString); | ||
| if (sessionHandler.cookieContainer != null && cookies.Length > 0) | ||
| lock (sessionHandler.inflightRequestsLock) { // esure we lock when writing to the collection |
| if (cookies != null && cookies.Count > 0) { | ||
| foreach (var cookie in cookies) { | ||
| Console.WriteLine ($"Adding cookie: {cookie.ToString ()} "); | ||
| request.Headers.TryAddWithoutValidation (Cookie, cookie.ToString ()); // as per docs: Returns a string representation of this Cookie object that is suitable for including in a HTTP Cookie: request header. |
There was a problem hiding this comment.
Not sure the standard allows having multiple Cookie headers.
I think the recommendation is to "join" all cookies into a single Cookie header using the ; character.
https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request
There was a problem hiding this comment.
We might want to use GetCookieHeader instead of GetCookies.
It looks that this is the approach that AndroidClientHandler.cs takes.
There was a problem hiding this comment.
It is a very good point. And I won't have to deal with the specific Header details!
| } | ||
| } | ||
|
|
||
| public CookieContainer CookieContainer { |
There was a problem hiding this comment.
AndroidClientHandler.cs also has a UseCookies property inherited from HttpClientHandler. Interestingly enough, NSUrlSessionHandler inherits from HttpMessageHandler instead :-?
I'd say the property is useful since it allows you to opt-out from this feature.
There was a problem hiding this comment.
I can implement such a property BUT we should do it in a diff PR. The issue is that we also have to deal with the fact that iOS has its own 'CookieContainer' so if we set the property, we have to make sure that we do not use the native CookieContainer or the managed one. I'd like to keep the PR small since this code is complicated. Added an issue that I'll fix once we land this: #7659
1. Remove poor mans debugger CWL. 2. Fix manuel typos. 3. Get the cookies header directly from the cookie container. Less looping and easier code.
| Assert.IsNull (ex, "Exception"); | ||
| Assert.IsNotNull (managedCookieResult, "Managed cookies result"); | ||
| Assert.IsNotNull (nativeCookieResult, "Native cookies result"); | ||
| Assert.AreEqual (managedCookieResult, nativeCookieResult, "Cookies"); |
There was a problem hiding this comment.
My two cents - we should have an assertion on the generated NSUrlRequest that verifies the cookie header (name and value). This could be done by injecting the underlying NSUrlSession and capturing the parameter passed to CreateDataTask
Not sure if the current structure of the code allows this verification.
There was a problem hiding this comment.
Or better yet - this test might be a better candidate for an integration test that uses some sort of test server - either in process (e.g. https://github.com/WireMock-Net/WireMock.Net) or a live server (e.g. https://httpbin.org/get)
There was a problem hiding this comment.
The test is ensuring that the same cookies are sent when using the managed handler and the unmanaged. The request from httpbin.org returns a dictionary of cookies + values. So if they are equal, we should be fine.
| Assert.IsNotNull (nativeCookieResult, "Native cookies result"); | ||
| var cookiesFromServer = cookieContainer.GetCookies (new Uri (url)); | ||
| Assert.AreEqual (1, cookiesFromServer.Count, "Cookies received from server."); | ||
| } |
There was a problem hiding this comment.
It would worth checking the name and the value of the actual cookie as well.
There was a problem hiding this comment.
Valid point. Merge and will update the test :)
|
Build failure |
|
Build failure Test results1 tests failed, 86 tests passed.Failed tests
|
|
Known issue: https://github.com/xamarin/maccore/issues/581 |
There are two important things to look at this:
the request. That is, we need to set Cookie headers for all of them.
gets correctly updated else we will have issues since we do not respect
the data sent from the server side.
Tests show both that we are setting the Cookie header and that we honour
the Set-Cookie header.
Fixes: #5665