Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent Cookies between Android and iOS in .NET MAUI #760

Open
aaron-yb opened this issue Aug 23, 2023 · 8 comments
Open

Inconsistent Cookies between Android and iOS in .NET MAUI #760

aaron-yb opened this issue Aug 23, 2023 · 8 comments

Comments

@aaron-yb
Copy link

I have been debugging a package that implements Flurl. (Original issue here: bgmulinari/B1SLayer#49). Have tried adjusting iOS info.plist file with NSAppTransportSecurity values.

On .NET Maui Android the following code will return session cookies:

`
private async Task FlurlLoginAsync()
{
var loginResponse = await _serviceLayerUrl
.AppendPathSegment("Login")
.WithCookies(out var cookieJar)
.PostJsonAsync(new { CompanyDB = _companyDB, UserName = _username, Password = _password })
.ReceiveString();

    Console.WriteLine("Cookies received:");
    cookieJar.ToList().ForEach(cookie => Console.WriteLine($"{cookie.Name}: {cookie.Value}"));
}

`

However when running the same from iOS, there are never any cookies. Debug output looks as following:

On iOS / Mac I get the following output:

2023-08-23 14:56:09.536898+0100 SLTest[10595:1499318] Request URL: https://url:50000/b1s/v1/Login
2023-08-23 14:56:09.537186+0100 SLTest[10595:1499318] HTTP Method: POST
2023-08-23 14:56:09.537798+0100 SLTest[10595:1499318] Response Status Code: OK
2023-08-23 14:56:09.537904+0100 SLTest[10595:1499318] Request Headers:
2023-08-23 14:56:09.538140+0100 SLTest[10595:1499318] Response Headers:
2023-08-23 14:56:09.538552+0100 SLTest[10595:1499318] Server: Apache
2023-08-23 14:56:09.538721+0100 SLTest[10595:1499318] Vary: Accept-Encoding
2023-08-23 14:56:09.540703+0100 SLTest[10595:1499318] Date: Wed, 23 Aug 2023 13:56:06 GMT
2023-08-23 14:56:09.540808+0100 SLTest[10595:1499318] Keep-Alive: timeout=5, max=100
2023-08-23 14:56:09.540898+0100 SLTest[10595:1499318] Connection: Keep-Alive
2023-08-23 14:56:09.542724+0100 SLTest[10595:1499318] Request Body:
{
"odata.metadata" : "https://url:50000/b1s/v1/$metadata#B1Sessions/@Element",
"SessionId" : "ce6f595c-41bc-11ee-c000-000c2980395a-14548-6632",
"Version" : "1000210",
"SessionTimeout" : 30
}
2023-08-23 14:56:09.558334+0100 SLTest[10595:1498480] Cookies received:

On Android I get the following:

[DOTNET] Request URL: https://url:50000/b1s/v1/Login
[DOTNET] HTTP Method: POST
[DOTNET] Response Status Code: OK
[DOTNET] Request Headers:
[DOTNET] Response Headers:
[DOTNET] Connection: Keep-Alive
[DOTNET] Date: Wed, 23 Aug 2023 14:02:19 GMT
[DOTNET] Keep-Alive: timeout=5, max=100
[DOTNET] Server: Apache
[DOTNET] Set-Cookie: B1SESSION=ac58e080-41bd-11ee-c000-000c2980395a-14752-8204;HttpOnly;;Secure;SameSite=None, ROUTEID=.node8; path=/;Secure;SameSite=None
[DOTNET] Vary: Accept-Encoding
[DOTNET] X-Android-Received-Millis: 1692799340723
[DOTNET] X-Android-Response-Source: NETWORK 200
[DOTNET] X-Android-Selected-Protocol: http/1.1
[DOTNET] X-Android-Sent-Millis: 1692799338028
[DOTNET] Request Body:
[DOTNET] {
[DOTNET] "odata.metadata" : "https://url:50000/b1s/v1/$metadata#B1Sessions/@Element",
[DOTNET] "SessionId" : "ac58e080-41bd-11ee-c000-000c2980395a-14752-8204",
[DOTNET] "Version" : "1000210",
[DOTNET] "SessionTimeout" : 30
[DOTNET] }
[DOTNET] Cookies received:
[DOTNET] ROUTEID: .node8
[DOTNET] B1SESSION: ac58e080-41bd-11ee-c000-000c2980395a-14752-8204
[DOTNET] Request URL: https://url:50000/b1s/v1/Login
[DOTNET] HTTP Method: POST
[DOTNET] Response Status Code: OK
[DOTNET] Request Headers:
[DOTNET] Response Headers:
[DOTNET] Connection: Keep-Alive
[DOTNET] Date: Wed, 23 Aug 2023 14:02:19 GMT
[DOTNET] Keep-Alive: timeout=5, max=100
[DOTNET] Server: Apache
[DOTNET] Set-Cookie: B1SESSION=ac567d90-41bd-11ee-c000-000c2980395a-8440-7940;HttpOnly;;Secure;SameSite=None, ROUTEID=.node7; path=/;Secure;SameSite=None
[DOTNET] Vary: Accept-Encoding
[DOTNET] X-Android-Received-Millis: 1692799340837
[DOTNET] X-Android-Response-Source: NETWORK 200
[DOTNET] X-Android-Selected-Protocol: http/1.1
[DOTNET] X-Android-Sent-Millis: 1692799338028
[DOTNET] Request Body:
[DOTNET] {
[DOTNET] "odata.metadata" : "https://url:50000/b1s/v1/$metadata#B1Sessions/@Element",
[DOTNET] "SessionId" : "ac567d90-41bd-11ee-c000-000c2980395a-8440-7940",
[DOTNET] "Version" : "1000210",
[DOTNET] "SessionTimeout" : 30
[DOTNET] }
[DOTNET] Cookies received:
[DOTNET] ROUTEID: .node7
[DOTNET] B1SESSION: ac567d90-41bd-11ee-c000-000c2980395a-8440-7940

@aaron-yb aaron-yb added the bug label Aug 23, 2023
@bgmulinari
Copy link

As tested here by @aaron-yb, when using just the native HttpClient, the Set-Cookie header is present in the response, but not present when performing the same request using Flurl.

This results in an empty CookieJar when calling WithCookies with an output parameter.

@tmenier
Copy link
Owner

tmenier commented Aug 31, 2023

Hmm. I'm not set up with MAUI at the moment, but @aaron-yb if you could help me troubleshoot this I would appreciate it. Please try running this on iOS, based on your code sample above:

var handler = new HttpClientHandler();
handler.UserCookies = false;
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
var httpCli = new HttpClient(handler);
var flurlCli = new FlurlClient(httpCli);

var flurlResp = await flurlCli
  .Request(_serviceLayerUrl)
  .AppendPathSegment("Login")
  .WithCookies(out var cookieJar)
  .PostJsonAsync(new { CompanyDB = _companyDB, UserName = _username, Password = _password });
  
// what's in cookieJar?
// what's in flurlResp.Cookies?
// what's in flurlResp.Headers?

For the comments at the bottom, you could either output that info to the console or just add a breakpoint and let me know what you're seeing. I think this will be helpful in getting to the bottom of the problem. Thanks!

@aaron-yb
Copy link
Author

aaron-yb commented Sep 29, 2023

Hi @tmenier , apologies for the delay in getting back to you.

I get the following output on iOS:

2023-09-29 15:54:05.473476+0100 SLTest[5435:417741] cookieJar:
2023-09-29 15:54:05.473875+0100 SLTest[5435:417741] flurlResp.Cookies:
2023-09-29 15:54:05.473998+0100 SLTest[5435:417741] flurlResp.Headers
2023-09-29 15:54:05.477067+0100 SLTest[5435:417741] Server: Apache
2023-09-29 15:54:05.477190+0100 SLTest[5435:417741] Vary: Accept-Encoding
2023-09-29 15:54:05.477312+0100 SLTest[5435:417741] Date: Fri, 29 Sep 2023 14:54:00 GMT
2023-09-29 15:54:05.477409+0100 SLTest[5435:417741] Keep-Alive: timeout=5, max=100
2023-09-29 15:54:05.477496+0100 SLTest[5435:417741] Connection: Keep-Alive
2023-09-29 15:54:05.477588+0100 SLTest[5435:417741] Content-Type: application/json; odata=minimalmetadata; charset=utf-8
2023-09-29 15:54:05.477670+0100 SLTest[5435:417741] Content-Encoding: gzip
2023-09-29 15:54:05.477745+0100 SLTest[5435:417741] Content-Length: 181
2023-09-29 15:54:05.477818+0100 SLTest[5435:417741] Keep-Alive: timeout=5, max=100

and the following on Android:

[DOTNET] cookieJar:
[DOTNET] ROUTEID: .node6
[DOTNET] B1SESSION: ba7e3f4c-5ed8-11ee-c000-000c2980395a-8972-7672
[DOTNET] flurlResp.Cookies:
[DOTNET] B1SESSION: ba7e3f4c-5ed8-11ee-c000-000c2980395a-8972-7672
[DOTNET] ROUTEID: .node6
[DOTNET] flurlResp.Headers
[DOTNET] Connection: Keep-Alive
[DOTNET] Date: Fri, 29 Sep 2023 14:59:02 GMT
[DOTNET] Keep-Alive: timeout=5, max=100
[DOTNET] Server: Apache
[DOTNET] Set-Cookie: B1SESSION=ba7e3f4c-5ed8-11ee-c000-000c2980395a-8972-7672;HttpOnly;;Secure;SameSite=None
[DOTNET] Set-Cookie: ROUTEID=.node6; path=/;Secure;SameSite=None
[DOTNET] Transfer-Encoding: chunked
[DOTNET] Vary: Accept-Encoding
[DOTNET] X-Android-Received-Millis: 1695999546241
[DOTNET] X-Android-Response-Source: NETWORK 200
[DOTNET] X-Android-Selected-Protocol: http/1.1
[DOTNET] X-Android-Sent-Millis: 1695999542335
[DOTNET] Content-Type: application/json; odata=minimalmetadata; charset=utf-8

@tmenier
Copy link
Owner

tmenier commented Sep 29, 2023

Interesting. Normally, when HttpClientHandler.UseCookies is true (the default), Set-Cookie headers are intercepted by the handler and never come through in HttpRequestMessage.Headers. Flurl needs to see those headers in order for CookieJar to work, so it sets that value to false. But apparently those Set-Cookie headers still aren't coming through.

However, what I just noticed looking back at this snippet from @bgmulinari, UseCookies is never turned off, yet apparently those headers are coming through.

It's as though UseCookies is behaving exactly the opposite on iOS as on other platforms!

To test this theory, could you run my snippet above yet again, only remove this line entirely?

handler.UseCookies = false;

@aaron-yb
Copy link
Author

Hi @tmenier ,

Looks like you may be on to something!

Here is the output on iOS:

2023-09-30 14:59:15.240374+0100 SLTest[9230:629017] cookieJar:
2023-09-30 14:59:15.240711+0100 SLTest[9230:629017] ROUTEID: .node1
2023-09-30 14:59:15.240812+0100 SLTest[9230:629017] B1SESSION: 883a27aa-5f99-11ee-c000-000c2980395a-7456-7780
2023-09-30 14:59:15.240941+0100 SLTest[9230:629017] flurlResp.Cookies:
2023-09-30 14:59:15.241125+0100 SLTest[9230:629017] B1SESSION: 883a27aa-5f99-11ee-c000-000c2980395a-7456-7780
2023-09-30 14:59:15.241209+0100 SLTest[9230:629017] ROUTEID: .node1
2023-09-30 14:59:15.241285+0100 SLTest[9230:629017] flurlResp.Headers
2023-09-30 14:59:15.244630+0100 SLTest[9230:629017] Server: Apache
2023-09-30 14:59:15.244732+0100 SLTest[9230:629017] Vary: Accept-Encoding
2023-09-30 14:59:15.244825+0100 SLTest[9230:629017] Date: Sat, 30 Sep 2023 13:59:11 GMT
2023-09-30 14:59:15.244914+0100 SLTest[9230:629017] Keep-Alive: timeout=5, max=100
2023-09-30 14:59:15.245062+0100 SLTest[9230:629017] Connection: Keep-Alive
2023-09-30 14:59:15.245135+0100 SLTest[9230:629017] Set-Cookie: B1SESSION=883a27aa-5f99-11ee-c000-000c2980395a-7456-7780; Path=/b1s/v1; Domain= xxx.xxx.xxx; Version=0; Discard; Secure; httponly
2023-09-30 14:59:15.245234+0100 SLTest[9230:629017] Set-Cookie: ROUTEID=.node1; Path=/; Domain=xxx.xxx.xxx; Version=0; Discard; Secure
2023-09-30 14:59:15.245298+0100 SLTest[9230:629017] Content-Type: application/json; odata=minimalmetadata; charset=utf-8
2023-09-30 14:59:15.245366+0100 SLTest[9230:629017] Content-Encoding: gzip
2023-09-30 14:59:15.245423+0100 SLTest[9230:629017] Content-Length: 181
2023-09-30 14:59:15.245486+0100 SLTest[9230:629017] Keep-Alive: timeout=5, max=100

(domain outputs normally, but I have obscured it)

Here is the output on Android:

[DOTNET] ROUTEID: .node9
[DOTNET] B1SESSION: 19955720-5f99-11ee-c000-000c2980395a-6148-7472
[DOTNET] flurlResp.Cookies:
[DOTNET] B1SESSION: 19955720-5f99-11ee-c000-000c2980395a-6148-7472
[DOTNET] ROUTEID: .node9
[DOTNET] flurlResp.Headers
[DOTNET] Connection: Keep-Alive
[DOTNET] Date: Sat, 30 Sep 2023 13:56:05 GMT
[DOTNET] Keep-Alive: timeout=5, max=100
[DOTNET] Server: Apache
[DOTNET] Set-Cookie: B1SESSION=19955720-5f99-11ee-c000-000c2980395a-6148-7472;HttpOnly;;Secure;SameSite=None
[DOTNET] Set-Cookie: ROUTEID=.node9; path=/;Secure;SameSite=None
[DOTNET] Transfer-Encoding: chunked
[DOTNET] Vary: Accept-Encoding
[DOTNET] X-Android-Received-Millis: 1696082170869
[DOTNET] X-Android-Response-Source: NETWORK 200
[DOTNET] X-Android-Selected-Protocol: http/1.1
[DOTNET] X-Android-Sent-Millis: 1696082165165
[DOTNET] Content-Type: application/json; odata=minimalmetadata; charset=utf-8

@tmenier
Copy link
Owner

tmenier commented Oct 18, 2023

Wow. I think you've proven that UseCookies behaves exactly the opposite on iOS than it does on other platforms. I'm going the leave the help-wanted label on here in hopes that you (or someone else) can take the next steps:

  1. Figure out which .NET repository holds this quirky implementation. Open an issue with that team, confirm whether it is bug, if/when they anticipate a fix, and/or what their recommendation is for a work-around.
  2. If I must resort to conditional compilation, which preprocessor symbol(s) should be used for the work-around?

Armed with that information, I'll be willing to move forward with a fix. Thanks!

@tmenier
Copy link
Owner

tmenier commented Oct 20, 2023

Here's the default handler used on iOS platforms:
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.nsurlsessionhandler

And I believe this is the repo where an issue should be raised:
https://github.com/xamarin/xamarin-macios

I might have time to pursue this in the near future, but if someone wants to beat me to it, by all means. :)

@aaron-yb
Copy link
Author

Hey @tmenier thanks for your replies and info- I'm having a go at working this all out, bit of a learning curve! Will see who gets there first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants