167 lines
4.7 KiB
Go
167 lines
4.7 KiB
Go
package servlet
|
|
|
|
import (
|
|
util "geniuscartel.xyz/vinegar/vinegarUtil"
|
|
"net/http"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
FileRoute struct {
|
|
*VinegarRoute
|
|
srv *VinegarServlet
|
|
fileRoot string
|
|
UseCache bool
|
|
}
|
|
|
|
RouteConstructor func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute
|
|
)
|
|
|
|
var NewTextRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
|
|
defaultPrune := strings.Replace(urlPattern, ".*", "", -1)
|
|
route := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache}
|
|
textRouteHandler := createCompressibleFileServletFunction(&route, defaultPrune, pathlike)
|
|
rootRoute := NewServletRoute(urlPattern, textRouteHandler) //i *still* kinda don't like this pattern
|
|
route.VinegarRoute = rootRoute
|
|
|
|
servlet.AddRoute(route.VinegarRoute)
|
|
|
|
return &route
|
|
}
|
|
|
|
var NewImageRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
|
|
defaultPrune := strings.Replace(urlPattern, ".*", "", -1)
|
|
route := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache}
|
|
rootRoute := NewServletRoute(urlPattern, createUncompressedFileServletFunction(&route, defaultPrune, pathlike))
|
|
route.VinegarRoute = rootRoute //i *kinda* don't like this pattern
|
|
|
|
servlet.AddRoute(route.VinegarRoute)
|
|
return &route
|
|
}
|
|
|
|
var NewSingleFileRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
|
|
route := FileRoute{
|
|
srv: servlet,
|
|
fileRoot: pathlike,
|
|
UseCache: useCache,
|
|
}
|
|
singleFileServletHandler := createSingleFileServletFunction(&route)
|
|
sfCache := util.NewSingleFileCache(pathlike)
|
|
|
|
parentRoute := NewServletRoute(urlPattern, singleFileServletHandler)
|
|
parentRoute.Handler = singleFileServletHandler
|
|
parentRoute.Cache = sfCache
|
|
|
|
route.VinegarRoute = parentRoute
|
|
|
|
servlet.AddRoute(route.VinegarRoute)
|
|
|
|
return &route
|
|
}
|
|
|
|
func createSingleFileServletFunction(route *FileRoute) VinegarHandlerFunction {
|
|
|
|
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
|
var cache *util.LruEntry
|
|
var exists bool
|
|
|
|
if route.UseCache {
|
|
cache, exists = route.Cache.Get("")
|
|
} else {
|
|
cache, exists = route.Cache.GetFresh("")
|
|
}
|
|
|
|
if !exists {
|
|
route.srv.SendError(w, 404, "File not found.")
|
|
return
|
|
}
|
|
|
|
var content []byte
|
|
if clientAcceptsGzip(req) {
|
|
content = cache.CompressedContent
|
|
w.Header().Add(ContentEncodingHeaderKey, "gzip")
|
|
} else {
|
|
content = cache.Content
|
|
}
|
|
w.Header().Add(ContentTypeHeaderKey, cache.MimeType)
|
|
_, err := w.Write(content)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return fun
|
|
}
|
|
|
|
func createCompressibleFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
|
|
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
|
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
|
|
cachedContent, exists := route.Cache.Get(stub)
|
|
//i don't like this logic below. we need to streamline this a lot better. it's a twisty jungle right now
|
|
|
|
resourcePath := path.Join(pathlike, stub)
|
|
|
|
if !exists {
|
|
content, fileExists := util.GetDiskContent(resourcePath)
|
|
if fileExists {
|
|
if route.UseCache {
|
|
route.Cache.Put(stub, resourcePath)
|
|
cachedContent, _ = route.Cache.Get(stub)
|
|
} else {
|
|
w.Header().Add(ContentTypeHeaderKey, util.GuessMimetype(stub))
|
|
w.Write(*content)
|
|
return
|
|
}
|
|
} else {
|
|
route.srv.SendError(w, 404, "Couldn't find your content.")
|
|
return
|
|
}
|
|
}
|
|
w.Header().Add(ContentTypeHeaderKey, cachedContent.MimeType)
|
|
var err error = nil
|
|
|
|
if clientAcceptsGzip(req) {
|
|
w.Header().Add(ContentEncodingHeaderKey, "gzip")
|
|
_, err = w.Write(cachedContent.CompressedContent)
|
|
} else {
|
|
_, err = w.Write(cachedContent.Content)
|
|
}
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|
|
return fun
|
|
}
|
|
|
|
func createUncompressedFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
|
|
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
|
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
|
|
resourcePath := path.Join(pathlike, stub)
|
|
entry, exists := route.Cache.Get(stub)
|
|
if !exists {
|
|
route.Cache.Put(stub, resourcePath)
|
|
entry, exists = route.Cache.Get(stub)
|
|
}
|
|
|
|
if exists {
|
|
w.Header().Add(ContentTypeHeaderKey, util.GuessMimetype(stub))
|
|
_, err := w.Write(entry.Content)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return
|
|
|
|
} else {
|
|
route.srv.SendError(w, 404, "Couldn't find your content.")
|
|
}
|
|
}
|
|
return fun
|
|
}
|
|
|
|
func clientAcceptsGzip(req *http.Request) bool {
|
|
encodings := req.Header.Get(AcceptEncodingHeaderKey)
|
|
return strings.Contains(encodings, "gzip")
|
|
}
|