serve-static icon indicating copy to clipboard operation
serve-static copied to clipboard

fix(status): Send response with 404 when ENOENT is found

Open tristan957 opened this issue 4 years ago • 27 comments

PR Checklist

Please check if your PR fulfills the following requirements:

  • [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
  • [ ] Tests for the changes have been added (for bug fixes / features)
  • [ ] Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:

What is the current behavior?

Issue Number: #139

What is the new behavior?

Sends the response back with a 404 when ENOENT is included in the error message.

Does this PR introduce a breaking change?

[x] Yes
[ ] No

Maybe it is a breaking change. If you are someone who is catching 500 level errors in a catch all interceptor and checking for ENOENT existence in your error message, then chances are you would be affected by this change.

tristan957 avatar May 13 '20 01:05 tristan957

@kamilmysliwiec I am not familiar with Fastify, so I would not feel comfortable trying to make a similar change, nor do I know if the same behavior even exists in the FastifyAdapter.

I am looking into testing now.

tristan957 avatar May 13 '20 01:05 tristan957

I am actually not sure how to test this is my project. @kamilmysliwiec would appreciate a tip here. I thought npm link and adding it to my project would do the trick but no dice.

tristan957 avatar May 13 '20 01:05 tristan957

@tristan957 Yes you need to clone, build and link it npm linkin the clone repo and npm link @nestjs/serve-static in your project.

micaelmbagira avatar May 16 '20 20:05 micaelmbagira

Hi @micaelmbagira I will give that a try again hopefully some time this week. Maybe I forgot to build it last time I tried, and had only linked it.

tristan957 avatar May 18 '20 03:05 tristan957

@kamilmysliwiec what's the status on this one? Is there anything left to do or can it be merged?

micaelmbagira avatar Jun 24 '20 12:06 micaelmbagira

@micaelmbagira really just needs to be tested I think. I haven't had a chance recently.

tristan957 avatar Jun 24 '20 14:06 tristan957

@tristan957 Will do now

micaelmbagira avatar Jun 24 '20 14:06 micaelmbagira

Sweet let me know how it goes.

tristan957 avatar Jun 24 '20 14:06 tristan957

@micaelmbagira I committed your suggested change. Does everything work for you now?

tristan957 avatar Jun 24 '20 14:06 tristan957

Whoops looks like an import statement is needed according CircleCI. @micaelmbagira I can add you as a contrib on my fork or you can suggest the change and I can commit it again. Later today I can squash the commits

tristan957 avatar Jun 24 '20 14:06 tristan957

@tristan957 yes you can add me

micaelmbagira avatar Jun 24 '20 14:06 micaelmbagira

you should be in now

tristan957 avatar Jun 24 '20 14:06 tristan957

@tristan957 @kamilmysliwiec Done, please let me know if any more changes needed. In any case, seems to work fine

micaelmbagira avatar Jun 24 '20 14:06 micaelmbagira

@micaelmbagira thanks for your work :)

tristan957 avatar Jun 24 '20 15:06 tristan957

@kamilmysliwiec could you review the changes? 🙂

micaelmbagira avatar Jul 08 '20 14:07 micaelmbagira

@kamilmysliwiec Hello? Can we merge that one? Or is there anything to be adjusted?

micaelmbagira avatar Aug 29 '20 20:08 micaelmbagira

~Yes, I will make the change for fastify.loader.ts.~ serve-static seems to be broken (not working at all) with fastify...

Regarding the release, it's actually a bug fix IMO: it should not return 500 if the files are not found. What do you think?

micaelmbagira avatar Aug 30 '20 11:08 micaelmbagira

serve-static seems to be broken (not working at all) with fastify...

How so? I have a working example on my machine.

jmcdo29 avatar Aug 30 '20 17:08 jmcdo29

@jmcdo29 Never mind it was my bad. So, I found out the issue is not caused by express.static nor fastify-static (they both behave as expected when the requested file does not exist) but by app.get(options.renderPath, renderFn);.

With fastify, the fix is not easy because res.send(stream) causes the error to happen inside fastify. Hence I decided to use fs.exists. For express, I scoped the error handling to res.sendFile (because that's what triggers the error) instead of having this general error handler.

Overall, I don't think the solution looks super nice but couldn't come up with something better...

@kamilmysliwiec if you have time to give it a look

micaelmbagira avatar Aug 30 '20 20:08 micaelmbagira

Can this be merged? And not as a major release as this is a bug IMO. Besides the current behaviour being wrong I doubt if my security department will allow me to deploy any app with a broken HTTP status like this. A merge would be much appreciated otherwise I will need to fork or move to an alternate solution.

However, there is one problem with the PR. The response includes the full internal path of the file that wasn't found. This is a security issue as it exposes information about the internal server. If the file name is included in the error in needs to be relative to the public endpoint. Also, it would be nice is the error was completely customizable.

donnd-t avatar Nov 04 '20 23:11 donnd-t

I am in the same boat.

tristan957 avatar Nov 05 '20 00:11 tristan957

Any updates?

gax97 avatar Apr 15 '21 16:04 gax97

Any updates?

gabdusch avatar Aug 29 '21 14:08 gabdusch

Any updates?

art1c0 avatar Sep 07 '21 15:09 art1c0

Is there any interest from the maintainers to review this PR? It's been open for a few years but at least to my eyes looks like it was in a working state.

Folks have been working around this by creating global exception filters, but then if an ENOENT springs up from somewhere else in your application when you don't expect it, it gets handled like a 404, which is not desired.

Edit: Turns out global filters don't quite work for this. Nest's logic checks if any filters apply by using the type that's passed to the @Catch(MyError) decorator, and if there's a match, your filter takes over with no way to fall through. So in order to catch ENOENT errors I'd have to use @Catch(Error) and then I lose the ability to allow any other filters to handle the error. i.e. there's no way just to handle errors with error.code === 'ENOENT'.

adalinesimonian avatar Sep 19 '22 20:09 adalinesimonian

Any updates?

NeoDobby avatar Feb 24 '23 17:02 NeoDobby

I have given up on getting this merged, and I no longer work with Nest.

tristan957 avatar Feb 24 '23 18:02 tristan957

you can do it with

app.get(renderPath, async (req: any, res: any) => {
          await new Promise((resolve, reject) => {
            const stream = fs.createReadStream(indexFilePath);
            stream.on("data", (chunk) => {
              res.type('text/html').send(chunk);
              resolve(undefined);
            });
            stream.on("error", () => {
              reject(new NotFoundException("Not found"));
            });
          });
        });

Lokkve0126 avatar May 01 '23 15:05 Lokkve0126