Browse Source

code cleanup

master
Christopher Ramey 4 weeks ago
parent
commit
d9e48a7c41
  1. 83
      assets/assets.go
  2. 31
      pages/root.go
  3. 79
      pages/static.go

83
assets/assets.go

@ -1,7 +1,13 @@
package assets
import (
"bytes"
"compress/gzip"
"crypto/md5"
"embed"
"fmt"
"net/http"
"strings"
)
//go:embed *.ico *.html *.css
@ -10,3 +16,80 @@ var assets embed.FS
func ReadFile(name string) ([]byte, error) {
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)
}
}

31
pages/root.go

@ -2,9 +2,9 @@ package pages
import (
"fmt"
"git.binarythought.com/cdramey/qurl/assets"
"git.binarythought.com/cdramey/qurl/obj"
"git.binarythought.com/cdramey/qurl/storage"
"git.binarythought.com/cdramey/qurl/assets"
"html/template"
"net/http"
)
@ -12,10 +12,10 @@ import (
type RootHandler struct {
Storage storage.Storage
index *StaticContent
css *StaticContent
favi *StaticContent
usage *StaticContent
index *assets.StaticContent
css *assets.StaticContent
favi *assets.StaticContent
usage *assets.StaticContent
submit *template.Template
}
@ -67,40 +67,33 @@ func (ctx *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func (ctx *RootHandler) Init() error {
var err error
// 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 {
return err
}
ctx.index = &StaticContent{Type: "text/html", Content: data }
ctx.index.Init()
// 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 {
return err
}
ctx.css = &StaticContent{Type: "text/css", Content: data }
ctx.css.Init()
// 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 {
return err
}
ctx.favi = &StaticContent{Type: "image/x-icon", Content: data}
ctx.favi.Init()
// Initialize the api usage instructions
data, err = assets.ReadFile("usage.html")
ctx.usage, err = assets.NewStaticContent("usage.html", "text/html")
if err != nil {
return err
}
ctx.usage = &StaticContent{Type: "text/html", Content: data}
ctx.usage.Init()
// Initialize submit page template
data, err = assets.ReadFile("submit.html")
data, err := assets.ReadFile("submit.html")
if err != nil {
return err
}

79
pages/static.go

@ -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…
Cancel
Save