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

Fix wrap-content-type for requests of directories #452

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

svdo
Copy link

@svdo svdo commented Dec 8, 2021

When the request points to a directory and the body of the response is a file (i.e. index.html or something like that), take the mime type of that file. This fixes the case where previously requesting "/" would serve "index.html" with content type "application/octet-stream".

This fixes #408.

@weavejester
Copy link
Member

Thanks. First, can you remove 34a15b6, as that's not strictly related to the purpose of the PR.

Second, I think I need to consider the best way to go about this. Pulling the file extension from File response bodies is useful, but in production most statically served pages will be resources.

@svdo
Copy link
Author

svdo commented Dec 9, 2021

Thanks. First, can you remove 34a15b6, as that's not strictly related to the purpose of the PR.

Ok. I am curious as to why you wouldn't want this small improvement in that same function, but it's your call 🙂

Second, I think I need to consider the best way to go about this. Pulling the file extension from File response bodies is useful, but in production most statically served pages will be resources.

What's your hesitation exactly? My thinking is that in general, when you're serving something different than requested for whatever reason, the mime type should be the real mime type of what you're serving, not what was being requested. I mean, the Content-Type should primarily reflect the response, not the request, right? Maybe this situation doesn't generally apply to resources (as opposed to files), I'm not sure, but conceptually it should still be the right thing to do.

Let me know if I can help! For now I think I'm going to run a modified copy of the middleware, as I need a solution, but I'm of course still motivated to contribute a solution here.

@weavejester
Copy link
Member

I am curious as to why you wouldn't want this small improvement in that same function

It's good practice to ensure that a pull request contains only code related to the feature or fix being implemented. That way the diff is clean; any line that's changed relates to the pull request.

Formatting changes should be separated out into another commit, and also should ensure that the codebase is consistent. That is, if you decide to replace if with when, then do so for all instances in the codebase.

What's your hesitation exactly?

This change produces inconsistent behaviour when dealing with files on the filesystem, and resources located in jars. This can lead to subtle errors between development and production.

For example, suppose you use the wrap-resource middleware. During development, this will likely draw from the resources folder, while during production it may instead pull from an uberjar. The problem is that wrap-resource uses a File body where possible, which means that in development wrap-content-type will work with index files, and in production it won't.

The solution I'm considering is to allow URL instances to be supplied as the response body, to update wrap-resource to use this, and then to add a protocol to wrap-content-type to handle both File and URL bodies.

When the request points to a directory and the body of the response
is a file (i.e. index.html or something like that), take the mime type
of that file. This fixes the case where previously requesting "/"
would serve "index.html" with content type "application/octet-stream".
@svdo
Copy link
Author

svdo commented Dec 9, 2021

For example, suppose you use the wrap-resource middleware. During development, this will likely draw from the resources folder, while during production it may instead pull from an uberjar. The problem is that wrap-resource uses a File body where possible, which means that in development wrap-content-type will work with index files, and in production it won't.

Maybe that's not actually a problem, as wrap-resource doesn't do that mapping from "/" to "/index.html", so the situation that we're covering here doesn't apply to wrap-resource? My change only triggers when the (:uri request) does not have an extension...

@svdo
Copy link
Author

svdo commented Dec 9, 2021

[...] but in production most statically served pages will be resources.

You got me thinking with that remark by the way. I am now approaching the point that I'll be deploying this to production for the first time. I'm now converting my code to use wrap-resource instead of wrap-file... I'm adding a simple middleware that makes sure my SPAs can be served, e.g. /login/a/b/c?foo=bar causes /login/index.html?foo=barto be served.

I guess this removes the need for the change for me. I'll leave it up to you if we proceed with it anyway, or close it for now...

@weavejester
Copy link
Member

Maybe that's not actually a problem, as wrap-resource doesn't do that mapping from "/" to "/index.html"

Ah, you're right. Though it might be nice if that were an option. Let me think about it.

@maksimr
Copy link

maksimr commented Mar 22, 2022

Faced the same problem. Does this PR still under consideration?
Thanks

@agorgl
Copy link

agorgl commented Nov 9, 2022

Just bumped into this too! I hope this gets fixed because pedestal uses the wrappers around ring's file / resource / content-type middleware as default interceptors

@weavejester
Copy link
Member

Could you give a little more information on what the exact issue you had? Would it be fixed by looking for File bodies without content types and deriving the content type from the file name?

@agorgl
Copy link

agorgl commented Nov 9, 2022

My exact issue is that when using content-type along with file interceptors in pedestal to serve static content/files, when the uri is an index path ("/") while the file interceptor searches and serves correctly index-files like index.html, the content-type interceptor does not set the correct Content-Type header and fallbacks to application/octet-stream.

This happens because content-type interceptor takes to account the only the uri in the mime-type detection as seen here:
https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/content_type.clj#L6

This in turn leads to static files being downloaded and not served by the browser when visiting index paths.

@agorgl
Copy link

agorgl commented Sep 27, 2023

Revisiting the same issue after almost a year, any considerations on merging this?

@weavejester
Copy link
Member

I think my earlier comment is the best solution I can think of:

The solution I'm considering is to allow URL instances to be supplied as the response body, to update wrap-resource to use this, and then to add a protocol to wrap-content-type to handle both File and URL bodies.

Implementing this just for files would produce inconsistent behaviour in wrap-resource.

@agorgl
Copy link

agorgl commented Sep 27, 2023

Ah yeah, this seems a reasonable solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consequences of wrap-file's :index-files? default on wrap-content-type
4 participants