code cleanup
This commit is contained in:
		| @ -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) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| 	} | ||||
|  | ||||
| @ -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) | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user