wrong content-type is sent with a default index.html

732 views
Skip to first unread message

Kevin Cantu

unread,
Feb 17, 2014, 4:15:12 AM2/17/14
to ring-c...@googlegroups.com
I've got a handler set up with wrap-file and wrap-content type.  Unfortunately, while it seems to give the right MIME type for everything else, why I browse to "/" instead of "/index.html", it gives me the index as an octet stream!

My handler:
(def app
  (-> myhandler
      (ring.middleware.file/wrap-file "www")
      (ring.middleware.content-type/wrap-content-type)))


Since it gets an octet stream content-type header, Chrome says this and downloads the index file:
Resource interpreted as Document but transferred with MIME type application/octet-stream: "http://localhost:9999/".


What am I missing?


Kevin


James Reeves

unread,
Feb 17, 2014, 5:19:37 AM2/17/14
to ring-c...@googlegroups.com
The wrap-content-type middleware determines the content type by the file extension. In the case of "/" it has no file extension, and therefore defaults to application/octet-stream.

You'll want to set the content-type of the index page manually, e.g.

    (GET "/" [] (-> (io/file "www/index.html) (response/content-type "text/html")))

- James


--
You received this message because you are subscribed to the Google Groups "Ring" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ring-clojure...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Matthew Huebert

unread,
May 7, 2015, 11:08:25 AM5/7/15
to ring-c...@googlegroups.com, ja...@booleanknot.com
You can also change the default mime-type for a nil file extension when you add the middleware:
(-> ...
 (wrap-content-type {:mime-types {nil "text/html"}}))

Given how common clean URLs are I find the default `application/octet-stream` odd.

James Reeves

unread,
May 7, 2015, 11:08:29 AM5/7/15
to Matthew Huebert, ring-c...@googlegroups.com
On 7 May 2015 at 15:58, Matthew Huebert <mhue...@gmail.com> wrote:
You can also change the default mime-type for a nil file extension when you add the middleware:
(-> ...
 (wrap-content-type {:mime-types {nil "text/html"}}))

This happens to work now, but isn't guaranteed to work in future.
 
Given how common clean URLs are I find the default `application/octet-stream` odd.

What else could it possibly be? With no other information, you have to assume a generic byte stream.

- James

Matthew Huebert

unread,
May 7, 2015, 11:24:51 AM5/7/15
to James Reeves, ring-c...@googlegroups.com
I would expect text/html, since that's what my handler will be returning for 99% of URLs that don't have an extension.

(unless there is a way to apply it only to files handled by wrap-resource, in which case the current default makes sense)

James Reeves

unread,
May 7, 2015, 12:15:22 PM5/7/15
to Matthew Huebert, ring-c...@googlegroups.com
On 7 May 2015 at 16:24, Matthew Huebert <mhue...@gmail.com> wrote:
I would expect text/html, since that's what my handler will be returning for 99% of URLs that don't have an extension.

That's what *your* handler might be returning, and in which case you can write some middleware to set the content-type as default if you so choose:

    (defn wrap-default-content-type [handler content-type]
      (fn [request]
        (let [response (handler request)]
          (if-not (response/get-header response "Content-Type")
            (response/content-type response content-type)
            response))))

However, in the general case of a low-level API, it's better to be honest. If Ring doesn't know the content-type, it shouldn't lie and tell the client that it does. It might be less convenient in some cases, but it's safer and more predictable.

There's also a security concern with returning text/html by default. HTML can contain scripts, so marking any unknown file as HTML is a possible attack vector.

- James

Edwin Park

unread,
Oct 31, 2015, 12:23:41 AM10/31/15
to Ring, mhue...@gmail.com, ja...@booleanknot.com
What if the file-response function was modified to return the appropriate Content-Type for any index files it finds? Having file-response (and resource-response) return Content-Type sounds like it may be a generally useful thing to do anyways, but it is particularly useful in this case as the information about the file extension is lost downstream.

James Reeves

unread,
Oct 31, 2015, 9:55:21 AM10/31/15
to Edwin Park, Ring, Matthew Huebert
There's no guaranteed way of finding the right Content-Type for a file. We infer the type by the file extension, or we can try and detect a magic number in the file, or we can look for specific set of bytes that usually indicates the type. There are a number of different ways, and none of them are foolproof.

This means that I'd prefer this functionality to be separate from the file-response and resource-response functions, either as additional middleware or as a function that wraps file-response and resource-response.

- James

Edwin Park

unread,
Oct 31, 2015, 10:14:08 AM10/31/15
to Ring, edwin...@gmail.com, mhue...@gmail.com, ja...@booleanknot.com
I see. How about having wrap-content check the body to see if it is a file, and if so use the filename to lookup the appropriate content type? This keeps the strategy out of the file/resource-response functions and places it in the middleware where we're explicitly inferring type by file extension. It just allows wrap-content to use its same inference strategy on files whose names are not represented in the uri.

James Reeves

unread,
Oct 31, 2015, 10:25:06 AM10/31/15
to Ring, Edwin Park, Matthew Huebert
The problem with that approach is that resources on the classpath are returned as files when possible, and input streams otherwise. This means that content-type middleware that looked at the response body might work in development and not in production.

However, in Ring 1.5.0 I'm planning on changing the response body to use a protocol rather than rely on a fixed set of types, so that would mean that resources could use a URL instead of an input stream for the body. This would open up the possibility for the content-type middleware to be a little smarter.

- James

--
You received this message because you are subscribed to the Google Groups "Ring" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ring-clojure...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Edwin Park

unread,
Oct 31, 2015, 10:52:01 AM10/31/15
to Ring, edwin...@gmail.com, mhue...@gmail.com, ja...@booleanknot.com
Cool. Just passing a bit of additional metadata to indicate the actual filename from the response functions would be sufficient for the content-type middleware to handle default index files. Making the filename metadata explicit rather than relying on the implementation of the body seems like it might be a good thing to do anyway. Is this something that could be patched onto ring 1.4 rather than waiting for 1.5?

James Reeves

unread,
Oct 31, 2015, 6:10:33 PM10/31/15
to Ring, Edwin Park, Matthew Huebert
Ring uses semantic versioning, and this would be a new piece of functionality, so it can't be patched into Ring 1.4.

- James
Reply all
Reply to author
Forward
0 new messages