From e47cb5f0e462c200834cada0b6e258bb88f5c4f4 Mon Sep 17 00:00:00 2001 From: khlieng Date: Sat, 16 May 2015 01:18:52 +0200 Subject: [PATCH] Implement Last-Modified caching --- server/serve_files.go | 89 +++++++++++++++++++++++++++++++++++++++++++ server/server.go | 51 ------------------------- 2 files changed, 89 insertions(+), 51 deletions(-) create mode 100644 server/serve_files.go diff --git a/server/serve_files.go b/server/serve_files.go new file mode 100644 index 00000000..29d41666 --- /dev/null +++ b/server/serve_files.go @@ -0,0 +1,89 @@ +package server + +import ( + "bytes" + "compress/gzip" + "io/ioutil" + "net/http" + "strconv" + "strings" + "time" +) + +var files = []File{ + File{"bundle.js", "text/javascript"}, + File{"bundle.css", "text/css"}, + File{"font/fontello.woff", "application/font-woff"}, + File{"font/fontello.ttf", "application/x-font-ttf"}, + File{"font/fontello.eot", "application/vnd.ms-fontobject"}, + File{"font/fontello.svg", "image/svg+xml"}, +} + +type File struct { + Path string + ContentType string +} + +func serveFiles(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + serveFile(w, r, "index.html.gz", "text/html") + return + } + + for _, file := range files { + if strings.HasSuffix(r.URL.Path, file.Path) { + serveFile(w, r, file.Path+".gz", file.ContentType) + return + } + } + + serveFile(w, r, "index.html.gz", "text/html") +} + +func serveFile(w http.ResponseWriter, r *http.Request, path, contentType string) { + info, err := AssetInfo(path) + if err != nil { + http.Error(w, "", http.StatusInternalServerError) + return + } + + if !modifiedSince(w, r, info.ModTime()) { + return + } + + data, err := Asset(path) + if err != nil { + http.Error(w, "", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", contentType) + + if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { + w.Header().Set("Content-Encoding", "gzip") + w.Header().Set("Content-Length", strconv.Itoa(len(data))) + w.Write(data) + } else { + gzr, err := gzip.NewReader(bytes.NewReader(data)) + buf, err := ioutil.ReadAll(gzr) + if err != nil { + http.Error(w, "", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Length", strconv.Itoa(len(buf))) + w.Write(buf) + } +} + +func modifiedSince(w http.ResponseWriter, r *http.Request, modtime time.Time) bool { + t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")) + + if err == nil && modtime.Before(t.Add(1*time.Second)) { + w.WriteHeader(http.StatusNotModified) + return false + } + + w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat)) + return true +} diff --git a/server/server.go b/server/server.go index 5079e9b3..1735ad49 100644 --- a/server/server.go +++ b/server/server.go @@ -1,13 +1,9 @@ package server import ( - "bytes" - "compress/gzip" - "io/ioutil" "log" "net/http" "strconv" - "strings" "sync" "github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/gorilla/websocket" @@ -21,15 +17,6 @@ var ( sessions map[string]*Session sessionLock sync.Mutex - files = []File{ - File{"bundle.js", "text/javascript"}, - File{"bundle.css", "text/css"}, - File{"font/fontello.eot", "application/vnd.ms-fontobject"}, - File{"font/fontello.svg", "image/svg+xml"}, - File{"font/fontello.ttf", "application/x-font-ttf"}, - File{"font/fontello.woff", "application/font-woff"}, - } - upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -39,11 +26,6 @@ var ( } ) -type File struct { - Path string - ContentType string -} - func Run(port int) { defer storage.Close() @@ -71,39 +53,6 @@ func upgradeWS(w http.ResponseWriter, r *http.Request) { handleWS(conn) } -func serveFiles(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/" { - serveFile("index.html.gz", "text/html", w, r) - return - } - - for _, file := range files { - if strings.HasSuffix(r.URL.Path, file.Path) { - serveFile(file.Path+".gz", file.ContentType, w, r) - return - } - } - - serveFile("index.html.gz", "text/html", w, r) -} - -func serveFile(path, contentType string, w http.ResponseWriter, r *http.Request) { - data, _ := Asset(path) - - w.Header().Set("Content-Type", contentType) - - if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { - w.Header().Set("Content-Encoding", "gzip") - w.Header().Set("Content-Length", strconv.Itoa(len(data))) - w.Write(data) - } else { - gzr, _ := gzip.NewReader(bytes.NewReader(data)) - buf, _ := ioutil.ReadAll(gzr) - w.Header().Set("Content-Length", strconv.Itoa(len(buf))) - w.Write(buf) - } -} - func reconnect() { for _, user := range storage.LoadUsers() { session := NewSession()