Echo: Echo static middleware returns wrong content type

Created on 3 Dec 2017  Â·  10Comments  Â·  Source: labstack/echo

As titled

    e.Static("/", "/dist")

AssetsBuildDir

 -- app.css
--- app.js

Actual result

Expected result

  • app.css, Content-Type:text/css; charset=utf-8
  • app.js, Content-Type: application/javascript
invalid wontfix

Most helpful comment

I also ran into this problem recently.

A project is working as expected on Mac, and the Content-Type is correct, however, on Windows it's giving us 'text/plain' for js files.

Mac is using Go 1.9.2.
Windows is using Go 1.10 and we're downgrading now to see if that might be the issue.

EDIT: It seems it's not Go's version, 1.9.2 on Windows is behaving the same as 1.10 on Windows, Chrome is still reporting that the MIME Type is not correct so it won't allow the execution of js files.

The cause of this issue is the Windows registry. On my Windows 7 machine, HKEY_CLASSES_ROOT/.js has a string value named Content Type whose value is text/plain. Modifying this to application/javascript causes mime.TypeByExtension(".js") to return correctly. You can also call mime.AddExtensionType(".js", "application/javascript") to force overwrite the mapping the mime package uses.

All 10 comments

As I am not able to reproduce it, can you provide a sample code/repo?

Closing as no response from the OP.

I also ran into this problem recently.

A project is working as expected on Mac, and the Content-Type is correct, however, on Windows it's giving us 'text/plain' for js files.

Mac is using Go 1.9.2.
Windows is using Go 1.10 and we're downgrading now to see if that might be the issue.

EDIT: It seems it's not Go's version, 1.9.2 on Windows is behaving the same as 1.10 on Windows, Chrome is still reporting that the MIME Type is not correct so it won't allow the execution of js files.

Ok, so this code is enough on Windows to see the difference.

e := echo.New()

// e.Use(middleware.Secure())

e.Static(`/`, `....\dist`)

It seems that the content type on Windows is still text/plain in both cases, however, without the Secure option, it accepts the fact that it's text/plain. On Mac or Ubuntu this is not the case, the content type is application/javascript.

With Secure on Windows
screen shot 2018-03-02 at 11 16 18

Without Secure on Windows
screen shot 2018-03-02 at 11 17 21

With Secure on OS X
screen shot 2018-03-02 at 12 50 21

I'll set up a small Windows dev env to test this out further.

Please reopen

It looks like e.Static() uses static() https://github.com/labstack/echo/blob/3cdcc65b23540bffa1d271a22e77014f627de569/echo.go#L444 which uses c.File() which uses http.ServeContent() https://github.com/labstack/echo/blob/ec048ea5231ff36137b9efd41fec86759e21e553/context.go#L508

Nowhere along this chain I see echo setting up the Content-Type. The only place that I see in Echo that the Content-Type is set (not counting the middleware) is here: https://github.com/labstack/echo/blob/ec048ea5231ff36137b9efd41fec86759e21e553/context.go#L433 which does not seem related to this.

That means that whatever Content-Type is set, is set by https://golang.org/pkg/net/http/#ServeContent which basically boils down to:

  1. mime.TypeByExtension(filepath.Ext(name)) (https://golang.org/src/net/http/fs.go?s=4818:4922#L194) or, if that fails (returns empty string), then
  2. http.DetectContentType(...) (https://golang.org/src/net/http/fs.go?s=4818:4922#L199).

@vishr please correct me if I'm wrong in any of this.

Shouldn't be hard to write a tiny program that tests these two functions directly and see what they return under each OS.

Did a tiny test with this (and using http://zeptojs.com/zepto.js for testing):

package main

import (
    "fmt"
    "io/ioutil"
    "mime"
    "net/http"
    "os"
    "path/filepath"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Need a filename")
        os.Exit(1)
    }

    name := os.Args[1]

    fmt.Println("mime.TypeByExtension:", mime.TypeByExtension(filepath.Ext(name)))

    content, err := ioutil.ReadFile(name)
    if err != nil {
        fmt.Println(err)
        os.Exit(2)
    }

    fmt.Println("http.DetectContentType:", http.DetectContentType(content))
}

Under Linux Mint 18.3 I get:

$ ./x zepto.js 
mime.TypeByExtension: application/javascript
http.DetectContentType: text/plain; charset=utf-8

Under Windows 10 I get:

E:\>x.exe zepto.js
mime.TypeByExtension: application/x-javascript
http.DetectContentType: text/plain; charset=utf-8

So far so good. Then I tried this little program:

package main

import "github.com/labstack/echo"

func main() {
    e := echo.New()
    e.Static("/", "dist")
    e.Start(":3000")
}

Under Linux I get:

$ curl -IXGET http://localhost:3000/zepto.js
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 58707
Content-Type: application/javascript
Last-Modified: Mon, 11 Dec 2017 23:15:09 GMT
Date: Fri, 02 Mar 2018 14:54:43 GMT

and under Windows:

Accept-Ranges:bytes
Content-Length:58707
Content-Type:application/x-javascript
Date:Fri, 02 Mar 2018 14:58:53 GMT
Last-Modified:Fri, 02 Mar 2018 14:45:38 GMT

It seems to perfectly match the earlier test, and also both seem to output an accepted content type for javascript (https://mathiasbynens.be/demo/javascript-mime-type).

Now if I add middleware.Secure into the mix, I still get the correct Content-Type under Linux BUT no Content-Type at all under Windows:

Date:Fri, 02 Mar 2018 15:04:10 GMT
Last-Modified:Fri, 02 Mar 2018 14:45:38 GMT
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Xss-Protection:1; mode=block

This is quite odd, I don't see anything in that middleware that would overwrite ContentType, so http.ServeContent should kick in and add it. @vishr going to reopen this, hope that's OK.

We run our echo in docker and use Alpine linux, and found that .json doesn't return contentType. After adding mailcap to Dockerfile RUN apk add --no-cache ca-certificates mailcap contentType is returned normal.

// TypeByExtension returns the MIME type associated with the file extension ext.
//
// The built-in table is small but on unix it is augmented by the local
// system's mime.types file(s) if available under one or more of these
// names:
//
// /etc/mime.types
// /etc/apache2/mime.types
// /etc/apache/mime.types

I also ran into this problem recently.

A project is working as expected on Mac, and the Content-Type is correct, however, on Windows it's giving us 'text/plain' for js files.

Mac is using Go 1.9.2.
Windows is using Go 1.10 and we're downgrading now to see if that might be the issue.

EDIT: It seems it's not Go's version, 1.9.2 on Windows is behaving the same as 1.10 on Windows, Chrome is still reporting that the MIME Type is not correct so it won't allow the execution of js files.

The cause of this issue is the Windows registry. On my Windows 7 machine, HKEY_CLASSES_ROOT/.js has a string value named Content Type whose value is text/plain. Modifying this to application/javascript causes mime.TypeByExtension(".js") to return correctly. You can also call mime.AddExtensionType(".js", "application/javascript") to force overwrite the mapping the mime package uses.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

toorop picture toorop  Â·  4Comments

danieldaeschle picture danieldaeschle  Â·  3Comments

wangxianzhuo picture wangxianzhuo  Â·  4Comments

younisshah picture younisshah  Â·  4Comments

dre1080 picture dre1080  Â·  4Comments