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

Why does HttpClient in Core allow GET requests with bodies, while Framework version does not? #1333

Closed
IanKemp opened this issue Mar 12, 2018 · 5 comments

Comments

@IanKemp
Copy link

IanKemp commented Mar 12, 2018

As per the title, the HttpClient implementation between Core and Framework differs in this regard. Consider the following example:

using (var client = new HttpClient())
{
    var request = new HttpRequestMessage
    {
        RequestUri = new Uri("some url"),
        Method = HttpMethod.Get,
    };

    request.Content = new ByteArrayContent(Encoding.UTF8.GetBytes("some json"));

    request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

    var result = client.SendAsync(request).Result;
    result.EnsureSuccessStatusCode();

    var responseBody = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
}
  • In .NET Core (tested with 1.0 and 2.0), the above executes successfully.
  • In .NET framework (tested with 4.7.1, 4.6.1, 4.5), the above throws a ProtocolViolationException with the message Cannot send a content-body with this verb-type on the SendAsync call.

While I am very happy that Core allows this (technically correct, but unusual) request type, I am less happy that the Framework does not support it. Why does Core allow this why Framework does not? Is this intentional or an oversight? Is there somewhere where these differences/idiosyncrasies are documented?

(For another example of differing HTTP behaviour in Core vs Framework, see this issue.)

@AppBeat
Copy link

AppBeat commented Mar 12, 2018

Interesting. According to this post: https://stackoverflow.com/questions/978061/http-get-with-request-body
standard does not explicitly forbid this. GET body should be ignored by server.

@IanKemp
Copy link
Author

IanKemp commented Mar 12, 2018

@AppBeat The server is free to ignore or accept the body; that should not prevent the client from sending a request that the server may ignore. It is ultimately up to the client to determine whether the server accepts requests like this.

A popular example of a product (server) that supports GET requests with bodies is Elasticsearch, specifically their REST query API. In particular, the section on that page "A GET Request with a Body?" explains their rationale (but note that they do also allow POST as a fallback option for clients that do not support this).

@AppBeat
Copy link

AppBeat commented Mar 12, 2018

I didn't say that this should be removed from .NET Core :) Although this is not common (bad?) practice I think .NET Core version in this case is more correct than .NET Framework implementation.

I will try to test this on new managed implementation of SocketsHttpHandler which will probably be prefered HttpHandler in future for more consistent behaviour across all different platforms.
https://github.com/dotnet/corefx/tree/master/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler

@AppBeat
Copy link

AppBeat commented Mar 12, 2018

I created new functional test for SocketsHttpHandler and it works as it should:

[Fact]
public async Task SendAsync_HttpGetWithPayload_Success()
{
    await LoopbackServer.CreateServerAsync(async (server, url) =>
    {
        string responseBody =
            "HTTP/1.1 200 OK\r\n" +
            $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
            "Content-Length: 0\r\n" +
            "Connection: close\r\n" +
            "\r\n";

        using (HttpClient client = CreateHttpClient())
        {
            var request = new HttpRequestMessage
            {
                RequestUri = url,
                Method = HttpMethod.Get,
            };

            request.Content = new StringContent("{}", Encoding.UTF8, "application/json");
            Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
            await server.AcceptConnectionAsync(async connection =>
            {
                Task<List<string>> serverTask = connection.ReadRequestHeaderAndSendCustomResponseAsync(responseBody);
                await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
            });

            Assert.True(getResponseTask.IsCompletedSuccessfully);
            var result = getResponseTask.Result;
            Assert.True(result.IsSuccessStatusCode);
        }
    });
}

@joshfree
Copy link
Member

Hi @IanKemp, I've moved this issue to https://github.com/dotnet/corefx/issues/28135 where the HttpClient owners can take a look. Thanks

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

No branches or pull requests

3 participants