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

Double-check of FileInfo in SendFileFallback causes issues in templating #34575

Closed
nibblesnbits opened this issue Jul 21, 2021 · 12 comments
Closed
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions Docs This issue tracks updating documentation ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. help wanted Up for grabs. We would accept a PR to help resolve this issue Status: Resolved
Milestone

Comments

@nibblesnbits
Copy link

I've written a custom IFileProvider that does in-line replacements of file contents based on the incoming request. This worked back in .NET Core 2.2, but has since broken due to #12328.

The offending lines are below.

var fileInfo = new FileInfo(filePath);
if (offset < 0 || offset > fileInfo.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
}
if (count.HasValue &&
(count.Value < 0 || count.Value > fileInfo.Length - offset))
{
throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty);
}

Is there a new suggested approach if I need to send a modified or different file from a custom IFileProvider? Also, is it stricly necessary to have this check at all?

@Tratcher
Copy link
Member

Are you using your custom IFileProvider with the StaticFile middleware? If the file length has been modified then your response has a mismatched Content-Length which can lead to protocol violations and failed responses.

Note the above code path is only hit if your IFileInfo preserves the original PhysicalPath property. If you're modifying the contents in the Stream then you'll want to remove the PhysicalPath property and update the length.

private static async Task SendFileAsyncCore(HttpResponse response, IFileInfo file, long offset, long? count, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(file.PhysicalPath))
{
CheckRange(offset, count, file.Length);
using var fileContent = file.CreateReadStream();
var useRequestAborted = !cancellationToken.CanBeCanceled;
var localCancel = useRequestAborted ? response.HttpContext.RequestAborted : cancellationToken;
try
{
localCancel.ThrowIfCancellationRequested();
if (offset > 0)
{
fileContent.Seek(offset, SeekOrigin.Begin);
}
await StreamCopyOperation.CopyToAsync(fileContent, response.Body, count, StreamCopyBufferSize, localCancel);
}
catch (OperationCanceledException) when (useRequestAborted) { }
}
else
{
await response.SendFileAsync(file.PhysicalPath, offset, count, cancellationToken);

Have you considered doing this kind of inline processing in an MVC controller or custom middleware instead?

@Tratcher Tratcher added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Jul 21, 2021
@nibblesnbits
Copy link
Author

Yes, I am feeding that custom IFileProvider to the StaticFile middleware. I had no idea I could just not return a PhysicalPath! I'll update that and get back to you.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Jul 21, 2021
@Tratcher Tratcher added Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. and removed Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. labels Jul 21, 2021
@nibblesnbits
Copy link
Author

That totally works!

Would it make sense to put together something for the docs on a task like this? I can throw up a small example repo of my current code to ensure it's not a totally off-the-rails approach if need be.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Jul 21, 2021
@Tratcher
Copy link
Member

Feel free, I doubt we have much coverage for custom file providers.

@Tratcher Tratcher removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Jul 21, 2021
@nibblesnbits
Copy link
Author

Will do! I'll link my repo here tonight and work on the docs soon.

@nibblesnbits
Copy link
Author

Here's a quick-and-dirty demo: https://github.com/nibblesnbits/TemplateFileProviderDemo

@Tratcher
Copy link
Member

404? Is it private?

@BrennanConroy BrennanConroy added Docs This issue tracks updating documentation help wanted Up for grabs. We would accept a PR to help resolve this issue labels Jul 21, 2021
@BrennanConroy BrennanConroy added this to the Backlog milestone Jul 21, 2021
@ghost
Copy link

ghost commented Jul 21, 2021

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@nibblesnbits
Copy link
Author

I've updated the visibility. It is public now; my mistake.

@Tratcher
Copy link
Member

That's an interesting setup, I'm glad it works for you. I don't know that I'd recommend to the general public integrating dynamic content into the static file provider like that, it breaks some of the assumptions about immutability, cachability, range support, etc.. I hope your files aren't very big or else this would be really expensive to do on demand. You still might want to consider some caching logic like:
A) caching the original file in memory so you don't have to read it off the disk every time.
B) caching some of the templated results by host name so you don't have to keep regenerating them.

One alternative to consider is razor views. If everything is HTML anyways then it might be simpler to turn them into cshtml files and dynamically insert the content that way. That engine should be more efficient for templating than what you're using here.

@Tratcher Tratcher added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Jul 21, 2021
@ghost ghost added the Status: Resolved label Jul 21, 2021
@nibblesnbits
Copy link
Author

nibblesnbits commented Jul 21, 2021 via email

@ghost
Copy link

ghost commented Jul 22, 2021

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@ghost ghost closed this as completed Jul 22, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 21, 2021
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 24, 2023
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions Docs This issue tracks updating documentation ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. help wanted Up for grabs. We would accept a PR to help resolve this issue Status: Resolved
Projects
None yet
Development

No branches or pull requests

4 participants