Search code examples
c#posttcphttpclientservicepointmanager

c# httpclient post force single packet


Using Microsoft Message Analyzer, I can see that post data using the HttpClient is being sent in two tcp packets. One for the header, then one for the post data. This data could easily fit into one packet, however it is being split into two. I have explicitly turned on nagling and expect 100 continue off using the ServicePointManager, though, it doesn't seem to help.

        ServicePointManager.Expect100Continue = false;
        ServicePointManager.UseNagleAlgorithm = true;

Microsoft Message Analyzer 5023 (.Net) shows 2 packets are sent to destination, 8170 (Postman) shows 1 packet being sent. Tests were done with the same payload.

Below is some sample code used to generate the request in .net

    public void TestRequest()
    {
        var uri = new Uri("http://www.webscantest.com/");
        ServicePointManager.Expect100Continue = false;
        ServicePointManager.UseNagleAlgorithm = true;
        var p = ServicePointManager.FindServicePoint(uri);
        p.Expect100Continue = false;
        p.UseNagleAlgorithm = true;
        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("Connection", "close");

        var values = new Dictionary<string, string>
        {
            { "thing1", "hello" },
            { "thing2", "world" }
        };

        var content = new FormUrlEncodedContent(values);

        var response = client.PostAsync("http://www.webscantest.com/", content, CancellationToken.None).Result;
    }

Is there a way to force the payload into a single packet?

Using .Net Framework 4.7

related question here


Solution

  • So after looking at the dotnet core source code (can only assume the same in other .net versions), I can see in the WinHttpHandler that the Request Header and Request Body are sent at different points.

    The request header is sent with Interop.WinHttp.WinHttpSendRequest. Then the request body with Interop.WinHttp.WinHttpWriteData which according to the WinHttp docs, will "Wait until WinHttpSendRequest has completed before calling this function".

    I think this issue could be solved, if the request body was sent with the WinHttpSendRequest, which currently sets the body as IntPtr.Zero.

    Request Header here

    Request Body here