-
Notifications
You must be signed in to change notification settings - Fork 486
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
Native iOS/macOS HttpClientHandler incorrectly encodes query strings #20629
Labels
bug
If an issue is a bug or a pull request a bug fix
networking
If an issue or pull request is related to networking
Milestone
Comments
2 tasks
I can reproduce the behavior. The HttpResponse.RequestUri is changed/updated here:
this code is rather old, but apparently RequestUri is updated to reflect any redirects: |
Updating RequestUri after a redirect seems correct, a console app does that. Test code: async static Task Main ()
{
var client = new HttpClient () { BaseAddress = new Uri("https://httpbin.org") };
var request = new HttpRequestMessage (HttpMethod.Get,
"/redirect-to?url=https%3A%2F%2Fmicrosoft.com&status_code=302&queries[]={}"
);
Console.WriteLine ($"Request uri 1: {request.RequestUri}");
var response = await client.SendAsync(request);
Console.WriteLine ($"Request uri 2: {request.RequestUri}");
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine ((int) response.StatusCode);
Console.WriteLine(content.Length);
} prints:
|
Looks like SocketsHttpHandler only updates RequestUri in case of a redirect: |
rolfbjarne
added
bug
If an issue is a bug or a pull request a bug fix
networking
If an issue or pull request is related to networking
labels
May 22, 2024
rolfbjarne
added a commit
to rolfbjarne/xamarin-macios
that referenced
this issue
May 22, 2024
…ection occurred. Fixes xamarin#20629. The logic to update the request's RequestUri is somewhat old: xamarin/ModernHttpClient@518ac1b but it makes sense to do so. Some testing with a console app, also revealed that a plain .NET does this in case of a redirect: ```cs async static Task Main () { var client = new HttpClient () { BaseAddress = new Uri("https://httpbin.org") }; var request = new HttpRequestMessage (HttpMethod.Get, "/redirect-to?url=https%3A%2F%2Fmicrosoft.com&status_code=302&queries[]={}" ); Console.WriteLine ($"Request uri 1: {request.RequestUri}"); var response = await client.SendAsync(request); Console.WriteLine ($"Request uri 2: {request.RequestUri}"); var content = await response.Content.ReadAsStringAsync(); Console.WriteLine ((int) response.StatusCode); Console.WriteLine(content.Length); } ``` prints: ``` Request uri 1: /redirect-to?url=https%3A%2F%2Fmicrosoft.com&status_code=302&queries[]={} Request uri 2: https://www.microsoft.com/es-es/ 200 201252 ``` Further looking into .NET's code, `SocketsHttpHandler` updates RequestUri after following a redirect: https://github.com/dotnet/runtime/blob/f5eb26e4da0d0d7a5874553d8a793a551c34af0a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs#L65-L66 So it seems the expected behavior is to update RequestUri only in case of a redirect. Now the question becomes: how to detect whether we're a redirect or not? Contrary to `SocketsHttpHandler`, we don't do the actual redirect, it's handled transparently by `NSUrlSession`. Fortunately `NSUrlSessionTask` has two properties which help: [`OriginalRequest`][1] and [`CurrentRequest`][2]. According to Apple's documentation, these are the same, "except when the server has responded to the initial request with a redirect to a different URL." This sounds perfect for us, so use these two properties to determine whether a redirect occurred. Note that we can't use object identity, because these are 'copy' properties, which means they'll never be the same instances, only at most a copy of eachother. So instead compare the `AbsoluteString` property to check for equality. As far as I'm aware, none of the other properties (request body, headers, cookies, etc.) can be set by the server in a redirect, so there's no need to compare those. Fixes xamarin#20629. [1]: https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411572-originalrequest [2]: https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411649-currentrequest
rolfbjarne
added a commit
that referenced
this issue
May 28, 2024
…ection occurred. Fixes #20629. (#20633) The logic to update the request's RequestUri is somewhat old: xamarin/ModernHttpClient@518ac1b but it makes sense to do so. Some testing with a console app, also revealed that a plain .NET does this in case of a redirect: ```cs async static Task Main () { var client = new HttpClient () { BaseAddress = new Uri("https://httpbin.org") }; var request = new HttpRequestMessage (HttpMethod.Get, "/redirect-to?url=https%3A%2F%2Fmicrosoft.com&status_code=302&queries[]={}" ); Console.WriteLine ($"Request uri 1: {request.RequestUri}"); var response = await client.SendAsync(request); Console.WriteLine ($"Request uri 2: {request.RequestUri}"); var content = await response.Content.ReadAsStringAsync(); Console.WriteLine ((int) response.StatusCode); Console.WriteLine(content.Length); } ``` prints: ``` Request uri 1: /redirect-to?url=https%3A%2F%2Fmicrosoft.com&status_code=302&queries[]={} Request uri 2: https://www.microsoft.com/es-es/ 200 201252 ``` Further looking into .NET's code, `SocketsHttpHandler` updates RequestUri after following a redirect: https://github.com/dotnet/runtime/blob/f5eb26e4da0d0d7a5874553d8a793a551c34af0a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs#L65-L66 So it seems the expected behavior is to update RequestUri only in case of a redirect. Now the question becomes: how to detect whether we're a redirect or not? Contrary to `SocketsHttpHandler`, we don't do the actual redirect, it's handled transparently by `NSUrlSession`. Fortunately `NSUrlSessionTask` has two properties which help: [`OriginalRequest`][1] and [`CurrentRequest`][2]. According to Apple's documentation, these are the same, "except when the server has responded to the initial request with a redirect to a different URL." This sounds perfect for us, so use these two properties to determine whether a redirect occurred. Note that we can't use object identity, because these are 'copy' properties, which means they'll never be the same instances, only at most a copy of eachother. So instead compare the `AbsoluteString` property to check for equality. As far as I'm aware, none of the other properties (request body, headers, cookies, etc.) can be set by the server in a redirect, so there's no need to compare those. Fixes #20629. [1]: https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411572-originalrequest [2]: https://developer.apple.com/documentation/foundation/nsurlsessiontask/1411649-currentrequest
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
bug
If an issue is a bug or a pull request a bug fix
networking
If an issue or pull request is related to networking
Steps to Reproduce
HttpClient
HttpRequestMessage
for a GET request, with a request URI including a query string with special charactersSendAsync
methodSendAsync
call, the query string is encoded incorrectly<UseNativeHandler>false</UseNativeHandler>
to project fileExpected Behavior
Query string is encoded correctly
Actual Behavior
Query string is encoded incorrectly
Environment
Version information
Build Logs
msbuild.binlog.zip
Example Project (If Possible)
MauiApp1.zip
Before request sent
After request sent
The text was updated successfully, but these errors were encountered: