Skip to content

NSUrlSessionHandler loses Content of reused HttpRequestMessage #16339

@wcoder

Description

@wcoder

Steps to Reproduce

  1. Create a new iOS project;
  2. Create a custom DelegatingHandler with InnerHandler = new NSUrlSessionHandler();
  3. Simulate retry logic in custom handler via call method SendAsync twice;
  4. Send simple POST request with StringContent via httpClient.SendAsync(...)

Code example:

var handler = new TestDelegateHandler()
{
    InnerHandler = new NSUrlSessionHandler(),
};
var httpClient = new HttpClient(handler);

var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("https://httpbin.org/post"),
    Content = new StringContent("test_data_string", Encoding.UTF8, "application/json")
};

var response = await httpClient.SendAsync(request);
public class TestDelegateHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // simulate retry logic (for example Polly+Auth)

        // request.content="test_data_string"
        var response1 = await base.SendAsync(request, cancellationToken);

        // request.content=""
        var response2 = await base.SendAsync(request, cancellationToken);

        return response2;
    }
}

Expected Behavior

Two requests will be sent to the server with the same body content.

Actual Behavior

The first request was correctly sent to the server.
The second request was sent without content (request body is empty).

CFNETWORK_DIAGNOSTICS logs

First request:

Task <C2FDC90D-355A-41C9-91DE-409AC90C876C>.<1> sent request, body S 16
...
Task <C2FDC90D-355A-41C9-91DE-409AC90C876C>.<1> summary for task success {transaction_duration_ms=942, response_status=200, connection=1, protocol="h2", domain_lookup_duration_ms=45, connect_duration_ms=692, secure_connection_duration_ms=558, private_relay=false, request_start_ms=776, request_duration_ms=0, response_start_ms=903, response_duration_ms=1, request_bytes=152, response_bytes=685, cache_hit=false}

Second request:

Task <E1B85B9A-55E4-491E-A10D-7254F21F2B70>.<2> sent request, body N 0
...
Task <E1B85B9A-55E4-491E-A10D-7254F21F2B70>.<2> summary for task success {transaction_duration_ms=144, response_status=200, connection=1, reused=1, request_start_ms=0, request_duration_ms=0, response_start_ms=140, response_duration_ms=0, request_bytes=27, response_bytes=668, cache_hit=false}

Managed HttpClientHandler works as expected.

Environment

Version information
Visual Studio Community 2022 for Mac
Version 17.3.7 (build 11)
Installation UUID: 718c9426-9b34-4dad-a550-66605f1e5527

Runtime
.NET 6.0.5 (64-bit)
Architecture: X64

Roslyn (Language Service)
6.3.0-3.22312.2+52adfb8b2dc71ed4278debcf13960f2116868608

NuGet
Version: 6.2.2.1

.NET SDK (x64)
SDK: /usr/local/share/dotnet/sdk/6.0.402/Sdks
SDK Versions:
	7.0.402
	6.0.401
	6.0.400
	6.0.302
	6.0.301
	6.0.300
	6.0.202
	6.0.201
	6.0.106
	6.0.103
	6.0.102
	6.0.101
	6.0.100
	6.0.408
	5.0.407
	5.0.406
	5.0.405
	5.0.404
	5.0.403
	5.0.402
	5.0.401
	5.0.400
	5.0.302
	5.0.301
	5.0.203
	5.0.202
	5.0.201
	5.0.103
	5.0.102
	5.0.101
	5.0.100
	3.1.424
	3.1.423
	3.1.422
	3.1.421
	3.1.420
	3.1.419
	3.1.418
	3.1.417
	3.1.416
	3.1.415
	3.1.414
	3.1.413
	3.1.412
	3.1.411
	3.1.410
	3.1.409
	3.1.408
	3.1.407
	3.1.406
	3.1.405
	3.1.404
	3.1.403
	3.1.402
	3.1.401
	3.1.302
	3.1.301
	3.1.300
	3.1.202
	3.1.200
	3.1.102
MSBuild SDKs: /Applications/Visual Studio.app/Contents/MonoBundle/MSBuild/Current/bin/Sdks

.NET Runtime (x64)
Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
	8.0.10
	6.0.9
	6.0.8
	6.0.7
	6.0.6
	6.0.5
	6.0.4
	6.0.3
	6.0.2
	6.0.1
	6.0.0
	5.0.17
	5.0.16
	5.0.15
	5.0.14
	5.0.13
	5.0.12
	5.0.11
	5.0.10
	5.0.9
	5.0.8
	5.0.7
	5.0.6
	5.0.5
	5.0.4
	5.0.3
	5.0.2
	5.0.1
	5.0.0
	3.1.30
	3.1.29
	3.1.28
	3.1.27
	3.1.26
	3.1.25
	3.1.24
	3.1.23
	3.1.22
	3.1.21
	3.1.20
	3.1.19
	3.1.18
	3.1.17
	3.1.16
	3.1.15
	3.1.14
	3.1.13
	3.1.12
	3.1.11
	3.1.10
	3.1.9
	3.1.8
	3.1.7
	3.1.6
	3.1.5
	3.1.4
	3.1.2
	2.1.23
	2.1.22
	2.1.21
	2.1.20
	2.1.19
	2.1.18
	2.1.17
	2.1.16

Xamarin.Profiler
Version: 1.8.0.19
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Updater
Version: 11

Apple Developer Tools
Xcode 14.0.1 (21336)
Build 14A400

Xamarin.Mac
Version: 8.12.0.2 (Visual Studio Community)
Hash: 87f98a75e
Branch: d17-3
Build date: 2022-07-25 20:18:54-0400

Xamarin.iOS
Version: 16.0.0.72 (Visual Studio Community)
Hash: 6756a1146
Branch: release/6.0.4xx-xcode14
Build date: 2022-09-21 08:51:06-0400

Xamarin Designer
Version: 17.3.0.208
Hash: 0de472ea0
Branch: remotes/origin/d17-3
Build date: 2022-10-05 17:21:42 UTC

Xamarin.Android
Version: 13.0.0.0 (Visual Studio Community)
Commit: xamarin-android/d17-3/030cd63
Android SDK: /Users/yauhenipakala/Library/Developer/Xamarin/android-sdk-macosx
	Supported Android versions:
		12.1 (API level 32)
		9.0  (API level 26)
		6.0  (API level 23)
		12.0 (API level 31)
		8.1  (API level 27)
		5.1  (API level 22)
		11.0 (API level 30)
		10.0 (API level 29)
		8.1  (API level 25)
		10.0  (API level 28)
		13.0 (API level 33)
		7.0  (API level 24)

SDK Command-line Tools Version: 7.0
SDK Platform Tools Version: 33.0.3
SDK Build Tools Version: 33.0.0

Build Information: 
Mono: dffa5ab
Java.Interop: xamarin/java.interop/d17-3@7716ae53
SQLite: xamarin/sqlite/3.38.5@df4deab
Xamarin.Android Tools: xamarin/xamarin-android-tools/main@14076a6

Microsoft Build of OpenJDK
Java SDK: /Library/Java/JavaVirtualMachines/microsoft-11.jdk
11.0.12
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

Eclipse Temurin JDK
Java SDK: /Library/Java/JavaVirtualMachines/temurin-8.jdk
1.8.0.302
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

Android SDK Manager
Version: 17.3.0.23
Hash: 965bf40
Branch: remotes/origin/d17-3
Build date: 2022-10-05 17:21:47 UTC

Android Device Manager
Version: 0.0.0.1169
Hash: fafb1d5
Branch: fafb1d5
Build date: 2022-10-05 17:21:47 UTC

Build Information
Release ID: 1703070011
Git revision: b625496a1b9780a50e1935e641beecf8979c795b
Build date: 2022-10-05 17:19:47+00
Build branch: release-17.3
Build lane: release-17.3

Operating System
Mac OS X 12.6.0
Darwin 21.6.0 Darwin Kernel Version 21.6.0
    Mon Aug 22 20:17:10 PDT 2022
    root:xnu-8020.140.49~2/RELEASE_X86_64 x86_64

Build Logs

msbuild.binlog.zip

Example Project (If Possible)

ExampleProject.zip

Possible solution

After some investigation, I saw that the problem is in this part:
https://github.com/xamarin/xamarin-macios/blob/8cecb962a46e8c7be55b5db5e29cc416028b2803/src/Foundation/NSUrlSessionHandler.cs#L478-L485

In short:

  • stream.Position after the first request equals the last position which means that stream was read;
  • second request reuses the stream from the previous one and starts reading from the last position so the content for the second request equals 0;
  • in this part stream should be rewound to the beginning.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIf an issue is a bug or a pull request a bug fix

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions