code cleanup
This commit is contained in:
parent
2510448ed7
commit
d9e48a7c41
@ -1,7 +1,13 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"crypto/md5"
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed *.ico *.html *.css
|
//go:embed *.ico *.html *.css
|
||||||
@ -10,3 +16,80 @@ var assets embed.FS
|
|||||||
func ReadFile(name string) ([]byte, error) {
|
func ReadFile(name string) ([]byte, error) {
|
||||||
return assets.ReadFile(name)
|
return assets.ReadFile(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StaticContent struct {
|
||||||
|
Type string
|
||||||
|
Content []byte
|
||||||
|
ETag string
|
||||||
|
GZIPContent []byte
|
||||||
|
GZIPETag string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStaticContent(name string, mime string) (*StaticContent, error) {
|
||||||
|
// Load data
|
||||||
|
data, err := assets.ReadFile(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sc := &StaticContent{Type: mime, Content: data}
|
||||||
|
|
||||||
|
// Set a default Content-Type, if needed
|
||||||
|
if sc.Type == "" {
|
||||||
|
sc.Type = "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate ETag
|
||||||
|
sc.ETag = fmt.Sprintf("%x", md5.Sum(sc.Content))
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
gz, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||||
|
defer gz.Close()
|
||||||
|
|
||||||
|
if _, err := gz.Write(sc.Content); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gz.Flush(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using gzip encoding adds a minimum of 24 characters to the HTTP
|
||||||
|
// header, so only accept gzip encoding if we save that much or more
|
||||||
|
if (buf.Len() + 24) < len(sc.Content) {
|
||||||
|
sc.GZIPContent = buf.Bytes()
|
||||||
|
sc.GZIPETag = fmt.Sprintf("%x", md5.Sum(sc.GZIPContent))
|
||||||
|
}
|
||||||
|
return sc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
gzok := strings.Contains(r.Header.Get("Accept-Encoding"), "gzip")
|
||||||
|
gzlen := len(sc.GZIPContent)
|
||||||
|
|
||||||
|
// Use the correct etag
|
||||||
|
var localETag string
|
||||||
|
if gzok && gzlen > 0 {
|
||||||
|
localETag = sc.GZIPETag
|
||||||
|
} else {
|
||||||
|
localETag = sc.ETag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the etag, maybe we don't need to send content
|
||||||
|
remoteETag := r.Header.Get("If-None-Match")
|
||||||
|
if localETag == remoteETag {
|
||||||
|
w.WriteHeader(http.StatusNotModified)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("ETag", localETag)
|
||||||
|
w.Header().Set("Content-Type", sc.Type)
|
||||||
|
|
||||||
|
// Finally, write our content
|
||||||
|
if gzok && gzlen > 0 {
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", gzlen))
|
||||||
|
w.Write(sc.GZIPContent)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(sc.Content)))
|
||||||
|
w.Write(sc.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,9 +2,9 @@ package pages
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.binarythought.com/cdramey/qurl/assets"
|
||||||
"git.binarythought.com/cdramey/qurl/obj"
|
"git.binarythought.com/cdramey/qurl/obj"
|
||||||
"git.binarythought.com/cdramey/qurl/storage"
|
"git.binarythought.com/cdramey/qurl/storage"
|
||||||
"git.binarythought.com/cdramey/qurl/assets"
|
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -12,10 +12,10 @@ import (
|
|||||||
type RootHandler struct {
|
type RootHandler struct {
|
||||||
Storage storage.Storage
|
Storage storage.Storage
|
||||||
|
|
||||||
index *StaticContent
|
index *assets.StaticContent
|
||||||
css *StaticContent
|
css *assets.StaticContent
|
||||||
favi *StaticContent
|
favi *assets.StaticContent
|
||||||
usage *StaticContent
|
usage *assets.StaticContent
|
||||||
submit *template.Template
|
submit *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,40 +67,33 @@ func (ctx *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *RootHandler) Init() error {
|
func (ctx *RootHandler) Init() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
// Initialize the static content object for the index page
|
// Initialize the static content object for the index page
|
||||||
data, err := assets.ReadFile("index.html")
|
ctx.index, err = assets.NewStaticContent("index.html", "text/html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.index = &StaticContent{Type: "text/html", Content: data }
|
|
||||||
ctx.index.Init()
|
|
||||||
|
|
||||||
// Initialize the static content object for the css
|
// Initialize the static content object for the css
|
||||||
data, err = assets.ReadFile("qurl.css")
|
ctx.css, err = assets.NewStaticContent("qurl.css", "text/css")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.css = &StaticContent{Type: "text/css", Content: data }
|
|
||||||
ctx.css.Init()
|
|
||||||
|
|
||||||
// Initialize the static content object favicon
|
// Initialize the static content object favicon
|
||||||
data, err = assets.ReadFile("favicon.ico")
|
ctx.favi, err = assets.NewStaticContent("favicon.ico", "image/x-icon")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.favi = &StaticContent{Type: "image/x-icon", Content: data}
|
|
||||||
ctx.favi.Init()
|
|
||||||
|
|
||||||
// Initialize the api usage instructions
|
ctx.usage, err = assets.NewStaticContent("usage.html", "text/html")
|
||||||
data, err = assets.ReadFile("usage.html")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx.usage = &StaticContent{Type: "text/html", Content: data}
|
|
||||||
ctx.usage.Init()
|
|
||||||
|
|
||||||
// Initialize submit page template
|
// Initialize submit page template
|
||||||
data, err = assets.ReadFile("submit.html")
|
data, err := assets.ReadFile("submit.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package pages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StaticContent struct {
|
|
||||||
Type string
|
|
||||||
Content []byte
|
|
||||||
ETag string
|
|
||||||
GZIPContent []byte
|
|
||||||
GZIPETag string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sc *StaticContent) Init() {
|
|
||||||
// Populate ETag
|
|
||||||
sc.ETag = fmt.Sprintf("%x", md5.Sum(sc.Content))
|
|
||||||
|
|
||||||
// Set a default Content-Type, if needed
|
|
||||||
if sc.Type == "" {
|
|
||||||
sc.Type = "application/octet-stream"
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
gz, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
if _, err := gz.Write(sc.Content); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gz.Flush(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Using gzip encoding adds a minimum of 24 characters to the HTTP
|
|
||||||
// header, so only accept gzip encoding if we save that much or more
|
|
||||||
if (buf.Len() + 24) < len(sc.Content) {
|
|
||||||
sc.GZIPContent = buf.Bytes()
|
|
||||||
sc.GZIPETag = fmt.Sprintf("%x", md5.Sum(sc.GZIPContent))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sc *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
gzok := strings.Contains(r.Header.Get("Accept-Encoding"), "gzip")
|
|
||||||
gzlen := len(sc.GZIPContent)
|
|
||||||
|
|
||||||
// Use the correct etag
|
|
||||||
var localETag string
|
|
||||||
if gzok && gzlen > 0 {
|
|
||||||
localETag = sc.GZIPETag
|
|
||||||
} else {
|
|
||||||
localETag = sc.ETag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the etag, maybe we don't need to send content
|
|
||||||
remoteETag := r.Header.Get("If-None-Match")
|
|
||||||
if localETag == remoteETag {
|
|
||||||
w.WriteHeader(http.StatusNotModified)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("ETag", localETag)
|
|
||||||
w.Header().Set("Content-Type", sc.Type)
|
|
||||||
|
|
||||||
// Finally, write our content
|
|
||||||
if gzok && gzlen > 0 {
|
|
||||||
w.Header().Set("Content-Encoding", "gzip")
|
|
||||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", gzlen))
|
|
||||||
w.Write(sc.GZIPContent)
|
|
||||||
} else {
|
|
||||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(sc.Content)))
|
|
||||||
w.Write(sc.Content)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user