Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Zero Content-Length for static file 304 #6875

Closed
Tratcher opened this issue Sep 22, 2017 · 18 comments
Closed

Zero Content-Length for static file 304 #6875

Tratcher opened this issue Sep 22, 2017 · 18 comments
Assignees

Comments

@Tratcher
Copy link
Member

From @rustamkulenov on September 22, 2017 8:29

I've developed SPA application (ASP core,MVC,Angular) on Windows but can not host it on Linux. When I reload webpage in browser by F5 Kestrel prints out error and webbrowser receives HTTP code 500. This happens every second reload.

fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HL81HU49MSPA", Request id "0HL81HU49MSPA:00000002": An unhandled exception was thrown by the application.
System.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 42).

Environment:

#dotnet --info

.NET Command Line Tools (2.0.0)

Product Information:
Version: 2.0.0
Commit SHA-1 hash: cdcd1928c9

Runtime Environment:
OS Name: ubuntu
OS Version: 16.04
OS Platform: Linux
RID: ubuntu.16.04-x64
Base Path: /usr/share/dotnet/sdk/2.0.0/

Microsoft .NET Core Shared Framework Host

Version : 2.0.0
Build : e8b8861ac7faf042c87a5c2f9f2d04c98b69f28d

Steps to reproduce:

  1. Create new MVC application:
    #dotnet new mvc
  2. Place file named 1.txt with any content into wwwroot
  3. Change Home/Index controller method to:

public IActionResult Index()
{
return File("~/1.txt", "text/plain");
}

  1. #dotnet run

Now, If you try to open localhost:5000 browser will show content of the 1.txt, if you press F5 it'll show error 500. Press F5 again and it'll display content of 1.txt again, etc...

I tried to change Startup.cs to (as stated in #1289 ):

app.UseStaticFiles(new StaticFileOptions(){
OnPrepareResponse=context=>{
context.Context.Response.Headers.Remove("Content-Length");
}
});

, but this does not help.

If I set breakpoint in Home/Index controller method it is hit every time (i.e. on every reload). But it returns content-length=0 on every even reload. On every odd reload it returns correct value.

Copied from original issue: aspnet/KestrelHttpServer#2082

@Tratcher
Copy link
Member Author

Can you share a Fiddler trace?

Note there's no functional link between the File result in MVC and UseStaticFiles, they operate independently.

I've seen this behavior before. The odd requests are normal request but the even requests have conditional headers like if-modified-since. The result from these even requests is supposed to be a 304 not-modified with no body. There's a disconnect where something sets the content-length but then does not write the body, likely based on these conditional headers.

I'll try to track down the old bug for you. I don't think #1289 is the same issue, that was an overwrite rather than an underwrite.

@Tratcher
Copy link
Member Author

I'm not finding the matching bug.

I assume you're hitting this new code path:

if (preconditionState == PreconditionState.NotModified)
{
serveBody = false;
response.StatusCode = StatusCodes.Status304NotModified;
}

But I don't see it setting the Content-Length in this case. In fact, I don't see it setting the ContentLength for the 200 responses either. @jbagga

@Tratcher
Copy link
Member Author

From @jbagga on September 22, 2017 17:54

I think this might be the bug https://github.com/aspnet/Mvc/blob/rel/2.0.0/src/Microsoft.AspNetCore.Mvc.Core/Internal/FileResultExecutorBase.cs#L85-L91

If the status is 304 or 412, Content-Length should not be set because an empty body is being returned. @Tratcher

@rynowak
Copy link
Member

rynowak commented Sep 22, 2017

There's a disconnect where something sets the content-length but then does not write the body, likely based on these conditional headers

It could also be the case that we throw while trying to do I/O after setting headers

@rustamkulenov
Copy link

@Tratcher , here are two Fiddler trace files. For a text file ('1.txt') the issue is reproducible every time. For zip file ('2.zip') behavior may depend on a browser being used.
When browser sends 'If-Modified-Since' header, then the issue is reproducible.

trace.zip
trace2.zip

@Tratcher Tratcher added the bug label Sep 25, 2017
@Tratcher Tratcher changed the title Zero Content-Length for static file on Ubuntu Zero Content-Length for static file 304 Sep 25, 2017
@Tratcher
Copy link
Member Author

@Eilon this is a patch candidate.

@Eilon
Copy link
Member

Eilon commented Sep 25, 2017

@jbagga - can you take a look? Is your fix for the 2.0.x patch such that people won't hit this by default? And how does it look in the dev branch?

@jbagga
Copy link
Contributor

jbagga commented Sep 25, 2017

@Eilon This won't be solved with the 2.0.x patch fix from before. Range processing is on by default for VirtualFileResult and PhysicalFileResult. I am working on a fix for dev which we can port to 2.0.x as well.

@mayconbeserra
Copy link

@jbagga @Eilon is there any workaround for that issue?

I started having this issue since I moved to .NET Core 2

Exception:

System.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 1640).

@rustamkulenov
Copy link

May be it is possible to strip out 'If-Modified-Since' header value from a request?

@mayconbeserra
Copy link

@rustamkulenov I'm adding the code below but it doesn't work

      server
             .UseStaticFiles(new StaticFileOptions
             {
                 OnPrepareResponse = context =>
                 {
                     context.Context.Response.Headers.Remove("If-Modified-Since");
                     context.Context.Response.Headers.Remove("Content-Length");
                 }
             })
             .UseMvc(Routes);

Besides that, I have two behaviours:

  1. Ctrl + F5 - it works fine
  2. F5 - it doesn't work and the Middleware UseStaticFiles isn't triggered

Any more thoughts how to solve? How did you remove the headers?

@Tratcher
Copy link
Member Author

UseStaticFiles is unrelated. You can however put Context.Request.Headers.Remove("If-Modified-Since"); into your controller/action.

@mayconbeserra
Copy link

mayconbeserra commented Sep 27, 2017

Thanks @Tratcher and @rustamkulenov, it works fine now.

Would you mind to tell me why I'm getting that issue? I haven't had the issue with .net core 1.1

@Tratcher
Copy link
Member Author

There is a bug in a new 2.0 feature that processes if-modified-since. See #6886

@Eilon
Copy link
Member

Eilon commented Oct 2, 2017

Right, it was a bug cause by a new feature in 2.0.0 (it didn't exist in 1.x), but it's fixed in the 2.1 development branch, and we will also release this as a patch fix for 2.0.x.

@shravan2x
Copy link

Do we have an ETA on the patch? This is a fairly serious issue.

@jbagga
Copy link
Contributor

jbagga commented Oct 26, 2017

@shravan2x #6887 (comment)
Please give it a shot if possible and let us know if you see any issues

@RtyLi
Copy link

RtyLi commented Nov 14, 2017

I've got this bug today and right now I've found your fix. It is working. Thank you.

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

No branches or pull requests

8 participants