37

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?

Jacob Marble
  • 28,555
  • 22
  • 67
  • 78
moraes
  • 13,213
  • 7
  • 45
  • 59

1 Answers1

59

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()
Jacob Marble
  • 28,555
  • 22
  • 67
  • 78
jmibanez
  • 1,040
  • 1
  • 10
  • 13
  • Interesting. Thanks for being so detailed. It is a little weird nevertheless that those are not present while using the dev server (I'd guess that the development server would setup some kind of host environment to fill the request). request.Host did work but to use URL.Scheme I'll need to check conditionally if the dev server is being used or not. – moraes Aug 02 '11 at 14:59
  • 6
    Thanks for the answer! Could you tell how to prevent this behaviour (headache for URL parsing)? Because I even can't get the scheme from the Request object :( Is this normal? – Timur Fayzrakhmanov Feb 17 '15 at 08:31
  • It's worth noting that sometimes you can spot bots this way (they use the full URL when requesting a page). – Xeoncross Nov 28 '16 at 16:41
  • 2
    You can tell https from http using the attribute `r.TLS`. If it's http, `r.TLS == nil` is false, while in https it's true. Source: http://www.01happy.com/golang-get-full-url/ – btwiuse Jul 31 '17 at 14:44
  • 3
    This is not really true. I'm using a request with an absolute path including scheme (`ws://`). And the `Scheme` field is also empty. @navigaid This will also be true in case of `wss` scheme, so it's insufficient to match `https` only requests, – Emrys Myrooin Sep 19 '17 at 13:06