aspnet / StaticFiles

[Archived] Middleware for handling requests for file system resources including files and directories. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
114 stars 72 forks source link

StaticFiles extension serving truncated file for symbolic link #202

Closed colindembovsky closed 7 years ago

colindembovsky commented 7 years ago

(Moving from this issue) I have a SPA app that uses an config.json file with the following contents:

{
   "api": {
     "baseUri": "http://192.168.1.27:30081/api"
   }
}

In the Startup.cs file I configure StaticFiles:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
      ...

      app.UseDefaultFiles();
      app.UseStaticFiles();
    }

I'm deploying the app in a docker container (FROM microsoft/aspnetcore:1.1) using Kubernetes. In the Kubernetes Pod I map a configMap volume to override the config file. Kubernetes creates a symlink in the contianer and the file contents are correct within the container:

host ~> kubectl exec -it $podname -c frontend /bin/bash
container:/app# ls -l wwwroot/config/config.json
lrwxrwxrwx 1 root root 18 Jun 13 15:30 wwwroot/config/config.json -> ..data/config.json
container:/app# cat wwwroot/config/config.json
{
    "api": {
        "baseUri": "http://kubernetes-value:30081/api"
    }
}

However, doing a curl only returns 18 bytes:

host ~> curl http://192.168.1.160:30080/config/config.json
{
    "api": {
host ~>

I think that the StaticFile is seeing the file length as 18 (the length for the symlink, which is the length of the path to the physical file: in this case, ../data/config.json which is 18 chars) and only serving that length even though the file proper is longer.

I don't think this is expected behavior - but perhaps there is some other setting that I should use for StaticFiles?

Tratcher commented 7 years ago

I doubt StaticFiles is doing any special here. I'd bet you could repro the issue using IFileProvider directly. See IHostingEnvironment.WebRootFileProvider and see if you can read your file as expected.

colindembovsky commented 7 years ago

Thanks @Tratcher - I'm busy digging in now. The FileProvider is providing the length field and StaticFiles is returning 0 - length bytes in the response. I suspect that the length property is being set incorrectly for symlinks. Tracking down the point in the clr where the length is read from the OS to see if there's a workaround.

colindembovsky commented 7 years ago

Yep @Tratcher , I've confirmed it. If you do

var fi = new FileInfo("path/to/symLink");

then fi.Length is the length of the symlink (as described above), not the lenght of the file! I think this is a bug on the FileInfo object for Unix.

BrennanConroy commented 7 years ago

Here is the change that made unix FileInfo not follow symlinks and a comment about why https://github.com/dotnet/corefx/pull/5020#r47822345

TLDR; FileInfo behavior on Unix matches Windows behavior for symlinks.

colindembovsky commented 7 years ago

Thanks @brennanconroy. So is there an IFileProvider that uses Stat for symlinks so that I get the expected length? I could roll my own if there isn't one, but was hoping you might know of one before I start hacking ☺️!

colindembovsky commented 7 years ago

Turns out it was pretty easy to write my own IFileProvider to work around the symlink length issue.

Once that was in place, I just changed Startup.cs:

      app.UseStaticFiles(new StaticFileOptions()
      {
          FileProvider = new SymlinkFileProvider(env.WebRootPath)
      });

Now all is well!