Search code examples
gohttpserver

Why are request.URL.Host and Scheme blank in the development server?


I'm very new to Go. Tried this first hello, world from the documentation, and wanted to read the Host and Scheme from the request:

package hello

import (
    "fmt"
    "http"
)

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Host: " + r.URL.Host + " Scheme: " + r.URL.Scheme)
}

But their values are both blank. Why?


Solution

  • Basically, since you're accessing the HTTP server not from an HTTP proxy, a browser can issue a relative HTTP request, like so:

    GET / HTTP/1.1
    Host: localhost:8080
    

    (Given that, of course, the server is listening on localhost port 8080).

    Now, if you were accessing said server using a proxy, the proxy may use an absolute URL:

    GET http://localhost:8080/ HTTP/1.1
    Host: localhost:8080
    

    In both cases, what you get from Go's http.Request.URL is the raw URL (as parsed by the library). In the case you're getting, you're accessing the URL from a relative path, hence the lack of a Host or Scheme in the URL object.

    If you do want to get the HTTP host, you may want to access the Host attribute of the http.Request struct. See http://golang.org/pkg/http/#Request

    You can validate that by using netcat and an appropriately formatted HTTP request (you can copy the above blocks, make sure there's a trailing blank line after in your file). To try it out:

    cat my-http-request-file | nc localhost 8080
    

    Additionally, you could check in the server/handler whether you get a relative or absolute URL in the request by calling the IsAbs() method:

    isAbsoluteURL := r.URL.IsAbs()