Engineer in Tokyo

HTTP/2 and Go

UPDATE (2015/10/15): HTTP/2 is now enabled by default for http servers in tip and will be released as part of Go 1.6. That means that you will be able to create HTTP/2 servers without even calling ConfigureServer().

HTTP/2 is a new version of HTTP with added functionality, including connection multiplexing and header compression. There is currently no HTTP/2 implementation in the Go standard library, but there are a couple of libraries under development that you can use to create HTTP/2 servers and clients in Go.

The canonical library is the golang.org/x/net/http2 library by Brad Fitzpatrick. This library will eventually be added to the Go standard library, but it currently lives in a separate package while under development. It’s still under active development so your milage may vary, but you should probably use this library if you are implementing an HTTP/2 server.

Create an HTTP/2 Server

Using the http2 library to write a server is fairly easy. The http2 library integrates with the http package in the standard library. You just need to make a call to http2.ConfigureServer() to configure a normal http server to use HTTP/2. You will need to set up TLS encryption if accessing your server via a browser or it will fall back to using HTTP 1.x. Though encryption isn’t required, no browser clients currently support unencrypted HTTP/2.

package main

import (
  "log"
  "net/http"
  "os"

  "golang.org/x/net/http2"
)

func main() {
  cwd, err := os.Getwd()
  if err != nil {
    log.Fatal(err)
  }

  srv := &http.Server{
    Addr:    ":8000", // Normally ":443"
    Handler: http.FileServer(http.Dir(cwd)),
  }
  http2.ConfigureServer(srv, &http2.Server{})
  log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key"))
}

Create an HTTP/2 Client

Currently the implementation in the http2 library is pretty hacky. Although it spits out lots of debug style logging, it works for the most part. You use an http2.Transport object and pass it to a normal client from the http package.

package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"

  "golang.org/x/net/http2"
)

func main() {
  client := http.Client{
    // InsecureTLSDial is temporary and will likely be
    // replaced by a different API later.
    Transport: &http2.Transport{InsecureTLSDial: true},
  }

  resp, err := client.Get("https://localhost:8000/")
  if err != nil {
    log.Fatal(err)
  }

  body, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Println(string(body))
}

Further Reading

If you’re interested in learning more about HTTP/2 you can check out the HTTP/2 homepage, which has lots of links to other material and implementations in other languages.

If you are interested in a deeper look at how HTTP/2 clients and servers are implemented one alternative implementation worth exploring is Jxck’s http2 implementation. Jxck implements HTTP/2 handling by hooking into TLSNextProto on a standard HTTP server. You can see a sample use of it here.

The grpc-go library also has its own implementation of an HTTP/2 client and server in the transport package.