Search code examples
httpsinatracontent-typesendfile

What is the process by which sinatra's send_file decides what content-type to use?


What is the process by which sinatra's send_file decides what content-type to use?

For example, it seems that it works by the extension of the file passed to send_file, so if it is send_file blah.txt . then when I http to the route, I will get/ the response header will be, content-type: text/plain, so any html in the txt file will be interpreted by the web browser as plain text. Whereas if the file is blah.html then the server will respond with content-type: text/html.(and any html in the file is rendered as such)

And of course the route name is irrelevant so you could go to http://127.0.0.1:4567/zzz.html and it could lead to send_file a.txt and a.txt may contain html tags but since it's a .txt file send_file will cause sinatra to respond with content-type: text/plain and the browser won't render any html sent and will show it as plain text. I may be wrong but that seems to be what my quick tests indicate. Where I tried different routes, different filename extensions(.txt, and .html), sometimes files with html in them sometimes not, seeing whether the browser renders the html or not, and seeing what the content-type header was, with wget -d.

So then my question related to that is, is there a list that sinatra's send_file function uses, that relates file extension to content-type? I would like to see that list. And if not, then what is the process it is using.

Note- I understand there is a way to pass in a content-type Sinatra: How to respond with an image with headers "content-type" => "image/jpeg" but i'm asking how/ by what method, send_file determines content-type when no content-type is passed in.


Solution

  • This is the send_file method in the Sinatra framework (currently v2.0.5), notice it hands off finding out the content type straight away if none has been set:

    if opts[:type] or not response['Content-Type']
      content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
    end
    

    The content_type method will either return immediately or hand off to mime_type, which is a delegate of Rack's mime_type method (currently v2.0.7). This uses a well known list of extensions to check against.

    def mime_type(ext, fallback='application/octet-stream')
      MIME_TYPES.fetch(ext.to_s.downcase, fallback)
    end
    

    The list begins on line 49:

    MIME_TYPES = {
      ".123"       => "application/vnd.lotus-1-2-3",
      ".3dml"      => "text/vnd.in3d.3dml",
      ".3g2"       => "video/3gpp2",
      ".3gp" => "video/3gpp",
      # <snip>
    

    As you can see from the content_type snippet, the default it falls back on is application/octet-stream.