CSS files served as text/html

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
)

//allTemplates is of type pointer to a template
var allTemplates *template.Template

func contact(writer http.ResponseWriter, request *http.Request) {
	err := request.ParseForm()
	check(err)
	err = allTemplates.ExecuteTemplate(writer, "index.html", request.Form)
	check(err)
}

func init() {
	allTemplates = template.Must(template.ParseFiles("public/html/index.html"))

}

func main() {

	http.HandleFunc("/", contact)
	http.Handle("/css", http.FileServer(http.Dir("public")))
	http.Handle("/js/", http.FileServer(http.Dir("public")))
	http.Handle("/images/", http.FileServer(http.Dir("public")))
	http.Handle("/media-files/", http.FileServer(http.Dir("public")))
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

@toddmcleod will be glad if you could take a moment to review this

If I understand your question correctly, you ask why

	http.Handle("/css", http.FileServer(http.Dir("public")))

returns CSS files with the Content-Type header of text/html.

I can not reproduce this problem. This simple program

package main

import (
	"log"
	"net/http"
)

func main() {
	// Simple static webserver:
	log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/tmp/styles"))))
}

servers CSS files from /tmp/styles correctly with Content-Type: text/css:

$ curl -i http://localhost:8080/foo.css
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 35
Content-Type: text/css; charset=utf-8
Last-Modified: Sun, 13 May 2018 14:52:05 GMT
Date: Sun, 13 May 2018 14:54:09 GMT

* {
    font-family: sans-serif;
}

I have changed
http.Handle("/css", http.FileServer(http.Dir("public"))) to
http.Handle("/css", http.FileServer(http.Dir("./public")))
and everything is working fine but i want to know reason for this behaviour as all other files like images are don’t have “./” prepended before directory name and everything works fine

Also filserver serves files with respetive content-Type header I’ve used same in my example but it’s behaving differently for different file types

I still can not reproduce this. Even when I change my code to

    log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("./styles"))))

and run this program inside the directory that contains styles/, the Content-Type is if foo.css is set to text/css.

Let’s take a look at the source code:

// If the response's Content-Type header is not set, ServeContent 
// first tries to deduce the type from name's file extension and,
// if that fails, falls back to reading the first block of the content
// and passing it to DetectContentType.

Let’s take a look at net/http.DetectContentType:

DetectContentType implements the algorithm described at http://mimesniff.spec.whatwg.org/ to determine the Content-Type of the given data. It considers at most the first 512 bytes of data. DetectContentType always returns a valid MIME type: if it cannot determine a more specific one, it returns “application/octet-stream”.

  • What are the names of your CSS files? Do they have the extension .css?
  • If not, what do they contain in the first 512 bytes? Is this enought to know that they containt CSS and not some other language like C or JavaScript?

I’m not sure how the fallback to content sniffing works, but mime.TypeByExtension which is used in the first stage requires registry stuff on Windows, and is (or was) vulnerable to cross compilation damage or just lack of registry entries on the target computer. That is, at least on Windows this autodetection stuff was less reliable than I’d expected.

But I think that resulted in application/octet-stream as lutzhorn says. Are you sure this is not what you get? Maybe the browser is adding its own defaults on top of that.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.