Add HTTP/2 push
This commit is contained in:
parent
8d4b707757
commit
37c8e780bc
@ -1,9 +1,6 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5.4
|
||||
- 1.6.4
|
||||
- 1.7.5
|
||||
- 1.8.1
|
||||
- tip
|
||||
|
||||
|
@ -21,12 +21,7 @@ There is a few different ways of getting it:
|
||||
- [Other versions](https://github.com/khlieng/dispatch/releases)
|
||||
|
||||
### 2. Go
|
||||
This requires a [Go environment](http://golang.org/doc/install).
|
||||
|
||||
If running go 1.5 this environment variable is needed, versions <1.5 are not supported:
|
||||
```bash
|
||||
export GO15VENDOREXPERIMENT=1
|
||||
```
|
||||
This requires a [Go environment](http://golang.org/doc/install), version 1.8 or greater.
|
||||
|
||||
Fetch, compile and run dispatch:
|
||||
```bash
|
||||
|
@ -28,6 +28,7 @@ type File struct {
|
||||
Path string
|
||||
Asset string
|
||||
GzipAsset []byte
|
||||
Hash string
|
||||
ContentType string
|
||||
CacheControl string
|
||||
Compressed bool
|
||||
@ -69,7 +70,8 @@ func initFileServer() {
|
||||
}
|
||||
|
||||
hash := md5.Sum(data)
|
||||
files[0].Path = "bundle." + base64.RawURLEncoding.EncodeToString(hash[:]) + ".js"
|
||||
files[0].Hash = base64.RawURLEncoding.EncodeToString(hash[:])
|
||||
files[0].Path = "bundle." + files[0].Hash + ".js"
|
||||
|
||||
br, err := brotli.NewReader(bytes.NewReader(data), nil)
|
||||
if err != nil {
|
||||
@ -92,7 +94,8 @@ func initFileServer() {
|
||||
}
|
||||
|
||||
hash = md5.Sum(data)
|
||||
files[1].Path = "bundle." + base64.RawURLEncoding.EncodeToString(hash[:]) + ".css"
|
||||
files[1].Hash = base64.RawURLEncoding.EncodeToString(hash[:])
|
||||
files[1].Path = "bundle." + files[1].Hash + ".css"
|
||||
|
||||
br.Reset(bytes.NewReader(data))
|
||||
buf = &bytes.Buffer{}
|
||||
@ -196,6 +199,36 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Strict-Transport-Security", hstsHeader)
|
||||
}
|
||||
|
||||
if pusher, ok := w.(http.Pusher); ok {
|
||||
options := &http.PushOptions{
|
||||
Header: http.Header{
|
||||
"Accept-Encoding": r.Header["Accept-Encoding"],
|
||||
},
|
||||
}
|
||||
|
||||
cookie, err := r.Cookie("push")
|
||||
if err != nil {
|
||||
err = pusher.Push("/"+files[1].Path, options)
|
||||
err = pusher.Push("/"+files[0].Path, options)
|
||||
setPushCookie(w, r)
|
||||
} else {
|
||||
pushed := false
|
||||
|
||||
if files[1].Hash != cookie.Value[22:] {
|
||||
pusher.Push("/"+files[1].Path, options)
|
||||
pushed = true
|
||||
}
|
||||
if files[0].Hash != cookie.Value[:22] {
|
||||
pusher.Push("/"+files[0].Path, options)
|
||||
pushed = true
|
||||
}
|
||||
|
||||
if pushed {
|
||||
setPushCookie(w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
|
||||
@ -207,6 +240,17 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func setPushCookie(w http.ResponseWriter, r *http.Request) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "push",
|
||||
Value: files[0].Hash + files[1].Hash,
|
||||
Path: "/",
|
||||
Expires: time.Now().AddDate(1, 0, 0),
|
||||
HttpOnly: true,
|
||||
Secure: r.TLS != nil,
|
||||
})
|
||||
}
|
||||
|
||||
func serveFile(w http.ResponseWriter, r *http.Request, file *File) {
|
||||
info, err := assets.AssetInfo(file.Asset)
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -10,7 +11,6 @@ import (
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
"github.com/khlieng/dispatch/letsencrypt"
|
||||
"github.com/khlieng/dispatch/storage"
|
||||
@ -59,8 +59,6 @@ func startHTTP() {
|
||||
Handler: http.HandlerFunc(serve),
|
||||
}
|
||||
|
||||
http2.ConfigureServer(server, nil)
|
||||
|
||||
if certExists() {
|
||||
log.Println("[HTTPS] Listening on port", portHTTPS)
|
||||
server.ListenAndServeTLS(viper.GetString("https.cert"), viper.GetString("https.key"))
|
||||
@ -79,10 +77,12 @@ func startHTTP() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
server.TLSConfig.GetCertificate = letsEncrypt.GetCertificate
|
||||
server.TLSConfig = &tls.Config{
|
||||
GetCertificate: letsEncrypt.GetCertificate,
|
||||
}
|
||||
|
||||
log.Println("[HTTPS] Listening on port", portHTTPS)
|
||||
log.Fatal(listenAndServeTLS(server))
|
||||
log.Fatal(server.ListenAndServeTLS("", ""))
|
||||
} else {
|
||||
log.Fatal("Could not locate SSL certificate or private key")
|
||||
}
|
||||
|
@ -1,43 +1,11 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func listenAndServeTLS(srv *http.Server) error {
|
||||
if srv.TLSConfig.NextProtos == nil {
|
||||
srv.TLSConfig.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", srv.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig)
|
||||
return srv.Serve(tlsListener)
|
||||
}
|
||||
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
tc, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
func certExists() bool {
|
||||
cert := viper.GetString("https.cert")
|
||||
key := viper.GetString("https.key")
|
||||
|
Loading…
Reference in New Issue
Block a user