drogonframework / drogon

Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
MIT License
11.06k stars 1.06k forks source link

Filters are not called on uploads folder #1960

Open Mis1eader-dev opened 4 months ago

Mis1eader-dev commented 4 months ago

Describe the bug Applying a filter on "/uploads" folder, does not get called.

To Reproduce Steps to reproduce the behavior:

  1. Create a sample filter with a std::cout inside.
  2. Make sure the uploads folder is set in config.json.
  3. Add a "locations" config entry:
    {
    "uri_prefix": "/uploads",
    "filters": [ "YourFilter" ]
    }
  4. In the HTML file, add an <img> tag.
  5. Set the image's src to a file or a random name within the uploads folder. (e.g. src="/uploads/random.png")
  6. Run the application, no output will be observed when opening the HTML file page.

Expected behavior The filter should get called.

Desktop (please complete the following information):

Additional context Alternatively, we could do this with Sync AOP, but we would have to always check for the path.

Mis1eader-dev commented 4 months ago

To add more context, this is a security issue for some applications, as the server may want to restrict who views certain files.

hwc0919 commented 3 months ago

What's the http response? The filter will be only be called after router finds the file.

And note that the directory starts at 'document_root', not filesystem root '/'.

Mis1eader-dev commented 3 months ago

The response is normal 200 OK for existing files and 404 for nonexistent files, however, the filter doesn't get called

I believe I even tried using the 'alias' option to point it to the uploads folder manually, and nothing worked

So I resorted to creating an HttpController with a method via regex "/uploads/(.+)" to catch what is requested after the uploads folder and serve the file using HttpResponse::newFileResponse(drogon::app().getUploadPath() + '/' + file)

Applied an UploadsFilter on that controller to perform checks whether a certain file is allowed to be viewed with fccb(), or a 401 Unauthorized will be returned with fcb(...)

Mis1eader-dev commented 3 months ago

While we're at it, the location filters also won't get called on custom 404 response endpoints. For a Single Page Application made in say Vue.js we have to use a custom 404 that makes a file response to /index.html, however, no filter gets called on any of the paths added to the locations config entry. Hence I ended up making an HttpSimpleController for each page I'm interested in to have a filter, and perform the 404 response for each one:

callback(HttpResponse::newNotFound());

This is a lot of repetitive controller files doing a 404 response just for a filter

hwc0919 commented 1 month ago

I think I know the reason. Is your config file like this?

"locations": [
    {
        "uri_prefix": "/",
    },
    {
        "uri_prefix": "/uploads",
        "filters": ["MyFilter"]
    }
]

The "/uploads/random.png" will also match the first location block.

If you put location prefix "/" after the "/uploads", the filter will be invoked. Like below:

"locations": [
    {
        "uri_prefix": "/uploads",
        "filters": ["MyFilter"]
    },
    {
        "uri_prefix": "/",
    }
]
Mis1eader-dev commented 1 month ago

That could be the case, I'll try it out when I have time and report back