diff --git a/main.go b/main.go index e6006f6..c678d93 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "net/http" "os" "qurl/pages" - "qurl/static" "qurl/storage" "runtime" ) @@ -54,22 +53,15 @@ func main() { return } - mux := http.NewServeMux() - mux.Handle("/index.html", &static.StaticContent{Content: "index.html"}) - mux.Handle("/favicon.ico", &static.StaticContent{Content: "favicon.ico"}) - mux.Handle("/qurl.css", &static.StaticContent{Content: "qurl.css"}) - - submit := &pages.SubmitHandler{Storage: stor} - err = submit.Init() + root := &pages.RootHandler{Storage: stor} + err = root.Init() if err != nil { - fmt.Fprintf(os.Stderr, "Submit init error: %s\n", err.Error()) + fmt.Fprintf(os.Stderr, "Handler Init Error: %s\n", err.Error()) return } - mux.Handle("/submit.html", submit) - fmt.Fprintf(os.Stdout, "qurl listening .. \n") - err = http.Serve(listen, mux) + err = http.Serve(listen, root) if err != nil { fmt.Fprintf(os.Stderr, "Serve error: %s\n", err.Error()) } diff --git a/pages/root.go b/pages/root.go new file mode 100644 index 0000000..a2d08a3 --- /dev/null +++ b/pages/root.go @@ -0,0 +1,75 @@ +package pages + +import ( + "fmt" + "html/template" + "net/http" + "qurl/static" + "qurl/storage" +) + +type RootHandler struct { + Storage storage.Storage + + index *static.StaticContent + css *static.StaticContent + favi *static.StaticContent + submit *template.Template +} + +func (ctx *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + fname := r.URL.Path + + switch fname { + case "/index.html": + fallthrough + case "/": + ctx.index.ServeHTTP(w, r) + + case "/submit.html": + ctx.ServeSubmit(w, r) + + case "/qurl.css": + ctx.css.ServeHTTP(w, r) + + case "/favicon.ico": + ctx.favi.ServeHTTP(w, r) + + default: + fmt.Printf("Path: %s\n", fname) + } +} + +func (ctx *RootHandler) Init() error { + // Initialize the static content object for the index page + index := &static.StaticContent{Content: "index.html"} + err := index.Init() + if err != nil { + return err + } + ctx.index = index + + // Initialize the static content object for the css + css := &static.StaticContent{Content: "qurl.css"} + err = css.Init() + if err != nil { + return err + } + ctx.css = css + + // Initialize the static content object for the css + favi := &static.StaticContent{Content: "favicon.ico"} + err = favi.Init() + if err != nil { + return err + } + ctx.favi = favi + + // Initialize submit page template + ctx.submit = template.New("submit.html") + _, err = ctx.submit.Parse(string(static.Assets["submit.html"])) + if err != nil { + return err + } + return nil +} diff --git a/pages/submit.go b/pages/submit.go index c918b2d..b8aead7 100644 --- a/pages/submit.go +++ b/pages/submit.go @@ -3,36 +3,18 @@ package pages import ( "bytes" "fmt" - "html/template" - "net/http" "net" + "net/http" "qurl/qurl" - "qurl/static" - "qurl/storage" "time" ) -type SubmitHandler struct { - Storage storage.Storage - template *template.Template -} - type submitPage struct { Message string URL string } -func (ctx *SubmitHandler) Init() error { - ctx.template = template.New("submit.html") - - _, err := ctx.template.Parse(string(static.Assets["submit.html"])) - if err != nil { - return err - } - return nil -} - -func (ctx *SubmitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (ctx *RootHandler) ServeSubmit(w http.ResponseWriter, r *http.Request) { var pg submitPage u := r.FormValue("url") @@ -79,7 +61,7 @@ func (ctx *SubmitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } var buf bytes.Buffer - err := ctx.template.Execute(&buf, pg) + err := ctx.submit.Execute(&buf, pg) if err != nil { http.Error(w, fmt.Sprintf("Template execute error: %s", err.Error()), http.StatusInternalServerError) diff --git a/static/static.go b/static/static.go index 7cb44a5..180f23e 100644 --- a/static/static.go +++ b/static/static.go @@ -12,41 +12,43 @@ import ( ) type StaticContent struct { - ContentType string Content string + ContentType string ETag string GZIPContent []byte GZIPETag string DisableGZIP bool } -func (ctx *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // By default, don't use gzip - useGZIP := false +func (ctx *StaticContent) Init() error { + // Do we have a content type? If not, initialize it + if ctx.ContentType == "" { + ext := path.Ext(ctx.Content) + ctx.ContentType = mime.TypeByExtension(ext) + // Fallback to default mime type + if ctx.ContentType == "" { + ctx.ContentType = "application/octet-stream" + } + } - // If gzip isn't explicitly disabled, test for it - if !ctx.DisableGZIP { - useGZIP = strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") + // Do we have an etag? If not, generate one + if ctx.ETag == "" { + ctx.ETag = fmt.Sprintf("%x", md5.Sum(Assets[ctx.Content])) } - // If gzip is enabled, and there's no gzip etag, - // generate the gzip'd content plus the etag - if useGZIP && len(ctx.GZIPETag) == 0 { + // If gzip is allowed and we have no gzip etag, generate + // gzip content and etag + if !ctx.DisableGZIP && ctx.GZIPETag == "" { var buf bytes.Buffer - gz, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) defer gz.Close() if _, err := gz.Write(Assets[ctx.Content]); err != nil { - http.Error(w, fmt.Sprintf("GZIP write error: %s", err.Error()), - http.StatusInternalServerError) - return + return err } if err := gz.Flush(); err != nil { - http.Error(w, fmt.Sprintf("GZIP flush error: %s", err.Error()), - http.StatusInternalServerError) - return + return err } // Check if GZIP actually resulted in a smaller file @@ -56,18 +58,26 @@ func (ctx *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { } else { // If gzip turns out to be ineffective, disable it ctx.DisableGZIP = true - useGZIP = false } } + return nil +} + +func (ctx *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // By default, don't use gzip + useGZIP := false + + // If gzip isn't explicitly disabled, test for it + if !ctx.DisableGZIP { + useGZIP = strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") + } + + // Use the correct etag var localETag string if useGZIP { localETag = ctx.GZIPETag } else { - // Generate an ETag for content if necessary - if ctx.ETag == "" { - ctx.ETag = fmt.Sprintf("%x", md5.Sum(Assets[ctx.Content])) - } localETag = ctx.ETag } @@ -79,17 +89,6 @@ func (ctx *StaticContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { } w.Header().Set("ETag", localETag) - // Check the content type, if we don't already - // have one, make one - if ctx.ContentType == "" { - ext := path.Ext(ctx.Content) - ctx.ContentType = mime.TypeByExtension(ext) - // Fallback to default mime type - if ctx.ContentType == "" { - ctx.ContentType = "application/octet-stream" - } - } - w.Header().Set("Content-Type", ctx.ContentType) // Finally, write our content