Runtime: Httpclient PostAsync with null HttpContent differs on Windows/Linux

Created on 6 Jun 2017  路  9Comments  路  Source: dotnet/runtime

var client = new HttpClient();
var result = client.PostAsync("http://localhost", null).Result.Content.ReadAsStringAsync().Result;
Console.WriteLine("Content-type:" + result);

Only thing server-side does is echo back the "content-type" header.

When runned on windows 10, this is what I get:
Content-type:

When runned on Ubuntu, I instead get this:
Content-type:application/x-www-form-urlencoded

Is this the intended behaviour?

area-System.Net.Http bug os-linux

Most helpful comment

@davidsh Yeah I know how it's supposed to work, the "echo back" from localhost was just a simple way to debug on multiple systems/OS:es and to show you the bug, instead of using wireshark, log it on some remote web server, or whatever. I was just trying to write a nice "issue" that you easily could reproduce.
I could have just gone "Why the 陇#&/&%#"陇/ is your HttpClient-POST-implementation broken?!?!!!!!!"

The question was rhetorical/irony. There was 2 problems with this in my opinion:

  1. It should at least behave the same way across platforms
  2. It behaved incorrectly on linux

But at least I learned a lesson: do _not_ develop .net core on Windows and then expect it to work 100% on linux.

The only workaround I could figure was this one, so I guess I have to live with it and just do a ugly "TODO: fix someday, ehh?". (I needed this yesterday, not whenever the next release is coming, so this fix is more or less irrelevant, since this workaround was already "developed" and is now in production. I doubt I or anyone on my team will ever find the time to monitor when this fix is released and then remove this workaround :P).
But since it was so nasty, I submitted the issue for any other poor soul to avoid it in the future.

// TODO: fix tomorrow
var foo = new StringContent("");
foo.Headers.ContentType = null;
client.PostAsync(url, foo);

And yeah, I guess I'm not making any friends with this harsh reply, but you are Microsoft, I guess I expected more from you. hehe.
(The reason I'm grumpy? I have already lost track of how many workarounds like this one I have had to do when porting an existing project to .net core to circumvent bugs in the framework. There's so many 'gotchas'. We even have a "BrokenFrameworkHelpers.cs" in our project now to share solutions for broken stuff like this issue in our team.)

Thanks for your time, xoxo bassebaba.

All 9 comments

'Content-Type' request header is an entity body header. It is only carried when there is non-NULL request body content. It has no meaning otherwise. It is not a generic request/response header.

You are sending a POST request with empty request body content:

c# client.PostAsync("http://localhost", null)

There is no 'Content-Type' header sent on the wire to the server and thus, probably, the server can't echo one back. It is invalid for the server, in general, to send a 'Content-Type' header back as the response header unless it is the correct 'Content-Type' header for the response body.

The *Nix HttpClient shouldn't be sending any 'Content-Type' request header to the server if the request body is empty.

cc: @stephentoub

Hmm. If libcurl adds a Content-Type header by default, this logic might be wrong. It checks _requestMessage.Content != null and _requestMessage.Content.Headers.ContentType == null before removing the Content-Type header, but in this case _requestMessage.Content == null, so it's never removed.

@khellang, thanks, that does look like the culprit. Want to submit a fix and associated test? If not, I can.

Want to submit a fix and associated test? If not, I can.

Sure, I'll see if I can get the environment up and running 馃憤

@stephentoub Any pointers on where to put the test? Can't see any CurlHandler-specific tests. Should I just put it in PostScenarioTest?

Can't see any CurlHandler-specific tests

Doesn't need to be Unix-specific, as this behavior should be the same across implementations.

Should I just put it in PostScenarioTest?

Sounds good, thanks for fixing this.

@davidsh Yeah I know how it's supposed to work, the "echo back" from localhost was just a simple way to debug on multiple systems/OS:es and to show you the bug, instead of using wireshark, log it on some remote web server, or whatever. I was just trying to write a nice "issue" that you easily could reproduce.
I could have just gone "Why the 陇#&/&%#"陇/ is your HttpClient-POST-implementation broken?!?!!!!!!"

The question was rhetorical/irony. There was 2 problems with this in my opinion:

  1. It should at least behave the same way across platforms
  2. It behaved incorrectly on linux

But at least I learned a lesson: do _not_ develop .net core on Windows and then expect it to work 100% on linux.

The only workaround I could figure was this one, so I guess I have to live with it and just do a ugly "TODO: fix someday, ehh?". (I needed this yesterday, not whenever the next release is coming, so this fix is more or less irrelevant, since this workaround was already "developed" and is now in production. I doubt I or anyone on my team will ever find the time to monitor when this fix is released and then remove this workaround :P).
But since it was so nasty, I submitted the issue for any other poor soul to avoid it in the future.

// TODO: fix tomorrow
var foo = new StringContent("");
foo.Headers.ContentType = null;
client.PostAsync(url, foo);

And yeah, I guess I'm not making any friends with this harsh reply, but you are Microsoft, I guess I expected more from you. hehe.
(The reason I'm grumpy? I have already lost track of how many workarounds like this one I have had to do when porting an existing project to .net core to circumvent bugs in the framework. There's so many 'gotchas'. We even have a "BrokenFrameworkHelpers.cs" in our project now to share solutions for broken stuff like this issue in our team.)

Thanks for your time, xoxo bassebaba.

Was this page helpful?
0 / 5 - 0 ratings