-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
HttpMessageContent breaks on dotnet core 2.1 #27218
Comments
The PackageReference for WebAPI is bringing in System.Net.Http.Formatting: <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" /> https://apisof.net/catalog/System.Net.Http.HttpMessageContent cc: @Tratcher |
Should I open this issue under |
It is true that it is part of the asp.net but it breaks with netcoreapp2.1 and works with netcoreapp2.0. [I closed it to open under ASP.NET but prefer for you to tell me to move it hence re-opened it] |
It should be evaluated first higher in the stack. If it is CoreFX problem, then please isolate a repro which does not use ASP.NET components at all. |
This appears to be a break between .NET Core 2.0 and 2.1. w.r.t. how date headers are parsed. In 2.0, The message is I don't have time right at the moment to create a smaller repro. But, this core scenario involves a |
Is |
According to RFC 7234, we are supposed to handle
|
-1 is quite common but invalid per spec. |
More discussion: http://www.httpwatch.com/httpgallery/headers/
|
Based on this, I think we should fix .NET Core to be more resilent with getting "Expires: -1" etc. headers. |
using System.Net.Http.Headers;
class Program
{
static void Main()
{
var headers = new DerivedHttpHeaders();
headers.Add("Expires", "-1");
}
}
internal sealed class DerivedHttpHeaders : HttpHeaders { } |
Not surprisingly, we do not work correctly even for This may be good candidate for 2.1 / 2.2 fix if it impacts more people and/or it impacts someone hard. @aliostad were you able to work around the problem for now? |
I don't think this is a case of a regression in the handling of "Expires" with regards to the actual content Expires header, e.g. this fails on both .NET Framework and .NET Core (all versions I tested): using System.Net.Http;
class Program
{
static void Main()
{
var headers = new ByteArrayContent(new byte[0]).Headers;
headers.Add("Expires", "-1");
}
} with:
This fails because it uses the DateTimeParser to parse the value. However, what's changed in .NET Core 2.1 is that this DateTimeParser is now used to parse an arbitrary header named "Expires", i.e. when it's being added to any HttpHeaders collection rather than to an HttpContentHeaders collection. Previously, the knowledge that "Expires" was associated with a DateTimeParser only came as part of instantiating an HttpContentHeaders instance, with that assocation stored in the HttpContentHeader's parser store: But dotnet/corefx#23091 changed that (cc: @geoffkizer). Now as of that PR, HttpHeaders itself is aware of all known headers and their associated parsers, so whereas previously any value at all could be stored in an "Expires" header added to a custom HttpHeaders-derived type (e.g. this succeeds): using System.Net.Http.Headers;
class Program
{
static void Main()
{
var headers = new DerivedHttpHeaders();
headers.Add("Expires", "the best expires value ever");
}
}
internal sealed class DerivedHttpHeaders : HttpHeaders { } now such use validates the value for "Expires" with DateTimeParser, and the above of course fails. So, there are then two questions:
|
As @Tratcher said,
Not validating the |
@dougbu, for (1), I'm taking about the difference between whether HttpHeaders should itself know about Expires or not. Previously it didn't; now it does. The case that Chris is talking about has never been supported as far as I can tell. That's my (2). |
Thank you guys. It seems the issue has been isolated now. It did appear to me to be related to chunked encoding but that turns out to be a coincidence. So I understand my other issue https://github.com/dotnet/corefx/issues/31918 in corefx has been re-opened. I will leave it to you whether to close this one. |
The end-to-end scenario needs to be fixed. If an HTTP request receives a response from a server and that response has a response header of "Expires: -1" (or anything invalid), our HTTP stack should ignore the header. We should not throw an exception. Semantically, our HTTP stack doesn't really do anything with that header because it is really for browsers that cache responses etc. But at the very least, the HTTP request should not fail because it got an response header for "Expires" that has an invalid date format. |
Ignoring the value is not quite enough, the presence of the header is significant. If the client asks for the value of that header from the strongly typed property they shouldn't get null, they should get DateTime.MinValue or similar. |
@davidsh this is not technically true. A cache server or intermediary is free to cache any resource that does not have cache directives. But Expires: "-1" is a cache directive (albeit against spec) which should not be ignored. This means item can be cached but not without validating with the server first. |
The HTTP stack in .NET Core doesn't cache responses. It doesn't function like a browser. So, practically speaking, the HTTP stack doesn't do anything because of the presence of the header. |
Yes, that is probably a good compromise especially since the RFC implies that invalid date formats should be treated as sometime in the "past". |
That's fine, I just want to make sure it's clear that, as far as I can tell (and I could of course be wrong), that end-to-end scenario never worked with HttpClient, at least not if it's the issue highlighted in the simple repro. We can of course choose to make it work, but that would be fixing something other than the regression for which this issue was opened, which is that previously there was zero validation applied to an Expires header associated with an HttpHeaders instance other than HttpContentHeaders, and now the same validation is applied to all HttpHeaders instances, regardless of whether it's HttpContentHeaders or not. |
So, what's the plan of attack, guys? Should we expect it in 2.2? |
No |
I've have been encountering this issue as well. It seems that the |
This is a bug, I believe. I'm not sure why an HttpHeaders-derived type is causing this validation to occur, but it shouldn't be. |
The problem seems to be here: https://github.com/dotnet/corefx/pull/23091/files#diff-3b3d828e1c3f9a9d2e926e471d0ca21cR49 For custom HttpHeader derived types, this is causing all known headers to be validated, instead of being treated as custom headers. |
Is this coming in 3.0? |
Milestone says 3.0, so it has a chance. We will see. |
It is just I have people complaining using my library, It is broken here, I am at loss why such a critical bug has been open for so long. I am happy to supply a PR, if that makes it quicker. |
Why do you think it is that critical? I see only 3 people commenting here and no upvotes on the top post. It does not seem to be affecting that many. If you can submit PR, that would significantly increase chances to get it fixed in 3.0. We would definitely appreciate that! |
It was assumed this issue was fixed in .NET Core 3.0 with PR dotnet/corefx#36908. If that is not the case, please open a new issue and attach your repro. It's possible you are hitting a different bug. |
@davidsh Repro is exactly the same and the error is exactly the same: System.InvalidOperationException: Error parsing HTTP message header byte 818 of message System.Byte[].
at System.Net.Http.HttpContentMessageExtensions.ReadAsHttpResponseMessageAsyncCore(HttpContent content, Int32 bufferSize, Int32 maxHeaderSize, CancellationToken cancellationToken)
at CacheCowCrashRepro.MessageContentHttpMessageSerializer.DeserializeToResponseAsync(Stream stream) in C:\Users\aliostad\RiderProjects\ConsoleApp1\Program.cs:line 78
at CacheCowCrashRepro.Program.Main(String[] args) in C:\Users\aliostad\RiderProjects\ConsoleApp1\Program.cs:line 23 How do you say it is fixed? Simply put the repro code I have supplied and bang it crashes the same way in .NET 3.0 as in .NET 2.1. I can create a new issue but not sure why. |
Yes please. Just put it in a console app with netcoreapp3.0 and you should see the same error - or maybe I am doing something completely wrong. |
@aliostad if you look at the bug history, you can notice there was a PR to fix it: https://github.com/dotnet/corefx/issues/31918#ref-pullrequest-433538984 |
The fix was for underlying parsing issue. Note that HttpContentMessageExtensions and ReadAsHttpResponseMessageAsyncCore are not part of corefx. The code would need to be updated to use |
@Tratcher At this point, it looks like the bug is now in ASP.NET component as described here <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" /> Where is the code source for the HttpMessageContent component? And is there a recommended workaround or newer component in ASP.NET that would help here? Update: And @danroth27 says the package is still supported for .NET Core. |
I suspect that the bug fix for this needs to made in this source code here to use .TryAddWithoutValidation() instead of .Add(): |
Indeed, a new bug will need to be opened in https://github.com/aspnet/AspNetWebStack/. |
5.2.7 creates the same problem |
Sorry @Tratcher do you want me to open the bug? I am happy to do that. |
Yes please, you seem to have the most context on the issue. |
Hi,
[NOT ENTIRELY SURE IF THIS IS ASP.NET OR COREFX]
I have an HTTP Caching library for .NET and I use
HttpMessageContent
class to help me serialise and deseralise the messages. This has been working throughout including .NET Core 2.0 but it seems to have been broken by .NET Core 2.1 on Mac.Here is the repro code. Works with
netcoreapp2.0
but breaks with netcoreapp2.1.Project file:
Program.cs:
Here is the response I get which is nothing special. The only thing I notice is that there is no
ContentLength
header and encoding is chunked but looking at the message, I could not see a chunked encoding, the response is all in one block - maybe I missed.response.bin
The text was updated successfully, but these errors were encountered: