Search code examples
gomime-types

Go Mime package (1.14) behaves differently locally compared to the official Docker image


I have upgraded my local Go version from 1.13 to 1.14 and then I updated a project I was working on via re-initializing using go mod.

Locally:

$ go version
go version go1.14 linux/amd64

go.mod of my project:

module example-project

go 1.14

There has been an update in the mime package in Go 1.14 that changes the default type of .js files from application/javascript to text/javascript.

I have an application that serves a folder with a JavaScript file in it like:

func main() {

    http.HandleFunc("/static/", StaticHandler)

    http.ListenAndServe(":3000", nil)
}

func StaticHandler(w http.ResponseWriter, r *http.Request) {
    fs := http.StripPrefix("/static", http.FileServer(http.Dir("public/")))

    fs.ServeHTTP(w, r)
}

I updated a test case to reflect the mime changes in Go 1.14:

func TestStaticHandlerServeJS(t *testing.T) {
    req, err := http.NewRequest("GET", "/static/index.js", nil)
    if err != nil {
        t.Fatal(err)
    }

    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(StaticHandler)

    handler.ServeHTTP(rr, req)

    if status := rr.Code; status != http.StatusOK {
        t.Errorf("handler returned wrong status code: got %v want %v",
            status, http.StatusOK)
    }

    expected := "text/javascript; charset=utf-8"
    if rr.Header().Get("Content-Type") != expected {
        t.Errorf("handler returned unexpected Content-Type: got %v want %v",
            rr.Header().Get("Content-Type"), expected)
    }
}

When I run this locally, the test case which checks the Content-Type fails:

TestStaticHandlerServeJS: main_test.go:27: handler returned unexpected Content-Type: got application/javascript want text/javascript; charset=utf-8

I can also confirm in the browser that the file is indeed served with the Mime Type "application/javascript" as it was back in Go 1.13.

When I run this test on a Docker container using the official golang:1.14.0-alpine3.11 image, this test passes, and it reflects the changed behavior of the mime package.

So as a result, I'm left with a test case that fails locally and passes on the container. I maintain only a single version of Go locally, and that's 1.14 as I've shown above. What could be the reason why my local Go installation has the mime package behaving differently?


Solution

  • It was interesting to me too and I have had the same behaviour like you - go 1.14 delivered on my mashine (macOs catalina) application/javascript instead of text/javascript. I debugged the program and found this function in type.go of mime package:

    func initMime() {
        if fn := testInitMime; fn != nil {
            fn()
        } else {
            setMimeTypes(builtinTypesLower, builtinTypesLower)
            osInitMime()
        }
    }
    

    interesting stuff is going on in else block. After setting builtInTypes where extention js is assigned to text/javascript there is os specific assignment of file extention to content type, which overwrites the built-in assignment. On mac it is going to file type_unix.go where files

    "/etc/mime.types",
    "/etc/apache2/mime.types",
    "/etc/apache/mime.types",
    

    are tested to be available and in my case a file /etc/apache2/mime.types was present in the os and it contains ... surprise a line application/javascript js and this line overwrites the go built-in definition for .js extention and results in Content-Type: application/javascript to be delivered to client and cause your test to fail.