Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Make My Web Server written in Golang to support HTTP/2 Server Push?

Tags:

server

go

http2

My Web Server is Coded in Golang and supports HTTPS. I wish to leverage HTTP/2 Server Push features in the Web Server. The following Link explains how to convert HTTP Server to Support HTTP/2 :- https://www.ianlewis.org/en/http2-and-go
However, it is not clear how to implement the Server Push notifications in Golang.
- How should I add the Server Push functionality ?
- How do I control, or manage, the documents and files to be Pushed ?

like image 378
Dhumil Agarwal Avatar asked Jan 05 '17 16:01

Dhumil Agarwal


People also ask

Does go use http2?

Go's standard library HTTP server supports HTTP/2 by default.

How do I create an HTTP server on go?

Once you've set up your handlers, call the http. ListenAndServe function to start the server and listen for requests. In this first chunk of code, you set up the package for your Go program, import the required packages for your program, and create two functions: the getRoot function and the getHello function.


2 Answers

Go 1.7 and older do not support HTTP/2 server push in the standard library. Support for server push will be added in the upcoming 1.8 release (see the release notes, expected release is February).

With Go 1.8 you can use the new http.Pusher interface, which is implemented by net/http's default ResponseWriter. Pushers Push method returns ErrNotSupported, if server push is not supported (HTTP/1) or not allowed (the client has disabled server push).

Example:

package main                                                                              

import (
    "io"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/pushed", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "hello server push")
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if pusher, ok := w.(http.Pusher); ok {
            if err := pusher.Push("/pushed", nil); err != nil {
                log.Println("push failed")
            }
        }

        io.WriteString(w, "hello world")
    })

    http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}

If you want to use server push with Go 1.7 or older use can use the golang.org/x/net/http2 and write the frames directly.

like image 107
nussjustin Avatar answered Nov 15 '22 14:11

nussjustin


As mentioned in other answers, you can make use of Go 1.8 feature (cast the writer to http.Pusher and then use the Push method).

That comes with a caveat: you must be serving the HTTP2 traffic right from your server.

If you're behind a proxy like NGINX, this might not work. If you want to consider that scenario, you can make use of the Link header to advertise the URLs to be pushed.

// In the case of HTTP1.1 we make use of the `Link` header
// to indicate that the client (in our case, NGINX) should
// retrieve a certain URL.
//
// See more at https://www.w3.org/TR/preload/#server-push-http-2.
func handleIndex(w http.ResponseWriter, r *http.Request) {
  var err error

  if *http2 {
    pusher, ok := w.(http.Pusher)
    if ok {
      must(pusher.Push("/image.svg", nil))
    }
  } else {
    // This ends up taking the effect of a server push
    // when interacting directly with NGINX.
    w.Header().Add("Link", 
      "</image.svg>; rel=preload; as=image")
  }

  w.Header().Add("Content-Type", "text/html")
  _, err = w.Write(assets.Index)
  must(err)
}

ps.: I wrote more about this here https://ops.tips/blog/nginx-http2-server-push/ if you're interested.

like image 23
Ciro Costa Avatar answered Nov 15 '22 14:11

Ciro Costa