0

I created an MVC endpoint returning a file and then deleting it on the server side once the client download is finished. My implementation is based on this SO post, with this difference that my endpoint serves plain text files.

        [Authorize, HttpGet]
        public FileResult DownloadLogFile(string fileName)
        {
            var path = Path.Combine(this.logFilesRoot, fileName);
            var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
            return File(fs, MediaTypeNames.Text.Plain, fileName);
        }

This code works in most of the cases, but for bigger files (more than 40 MB) it randomly fails from time to time:

download failed

The picture shows my Chrome with an error, but I checked it also with Firefox and Edge, so it's not a problem with browser.

What could be the reason for the random failures?

Some details:

  • Net7
  • ASPNetCore 6
  • Windows OS

EDIT

I've changed the endpoint's method to "POST", but still no good. I'm getting net::ERR_CONNECTION_RESET 200 exceptions from JS fetch method now.

The code I use on client side is:

    const redirectToLogFile = (fileName: SignalR.IDownloadableLogFileDetails): void => {
        const url = `${Utils.root}home/DownloadLogFile/${fileName.FileName}`;
        fetch(url, { method: "POST" })
        .then(response => response.blob())
        .then(blob => {
            const a = document.createElement("a");
            a.href = window.URL.createObjectURL(blob);
            a.download = fileName;
            a.click();
        })
        .catch(err => console.log(err));
    }
LA.27
  • 1,888
  • 19
  • 35
  • 2
    Fun-fact: `Path.Combine` allows arguments to use `..` for [directory-traversal attacks](https://stackoverflow.com/questions/48777564/path-traversal-warning-when-using-path-combine). You should fix that. – Dai Mar 21 '23 at 10:37
  • 1
    [HTTP `GET` actions should be _safe_](https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP) - but your code as-is violates this (i.e. a `GET` action should never cause anything to be deleted/overwritten server-side, but that's exactly what your code does) - because browsers assume a `GET` action _is_ safe it means they'll gladly make a second `GET` request if they feel like it, which is a likely explanation for what's going on. So change your action to be `POST`-only, and think carefully about what should happen if a request is canceled or aborted. – Dai Mar 21 '23 at 10:40
  • Re `..` - not that big problem in my app, as it's for internal use only, but still worth fixing it, so thanks for the hint. Re: Get method - giving it a go now, thanks. – LA.27 Mar 21 '23 at 11:00
  • @Dai I've switched to POST but still no good. I've updated my question. Hints more than welcome. – LA.27 Mar 21 '23 at 14:49
  • In that case all I can suggest is to improve your code-quality by actually catching and logging exceptions and relevant detail in the request so you can reproduce it with a debugger and browser-simulator (like Postman, or Puppeteer). – Dai Mar 21 '23 at 15:04

0 Answers0