package servlet import ( "net/http" "path" "strings" util "vinegar/vinegarUtil" ) type ( FileRoute struct { *VinegarRoute srv *VinegarServlet fileRoot string UseCache bool } ) func NewImageRoute(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute { defaultPrune := strings.Replace(urlPattern, ".*", "", -1) imgRoute := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache} rootRoute := NewServletRoute(urlPattern, createUncompressedFileServletFunction(&imgRoute, defaultPrune, pathlike)) imgRoute.VinegarRoute = rootRoute //i *kinda* don't like this pattern return &imgRoute } func NewTextRoute(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute { defaultPrune := strings.Replace(urlPattern, ".*", "", -1) fr := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache} textRouteHandler := createCompressibleFileServletFunction(&fr, defaultPrune, pathlike) rootRoute := NewServletRoute(urlPattern, textRouteHandler) //i *still* kinda don't like this pattern fr.VinegarRoute = rootRoute return &fr } func NewSingleFileRoute(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 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 { 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 } _, 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 { SendError(w, 404, "Oops! Something went wrong.") 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) } else { SendError(w, 404, "Oops! Something went wrong!") return } if !exists { SendError(w, 404, "Oops! Something went wrong.") } else { _, err := w.Write(entry.Content) if err != nil { panic(err) } return } } return fun } func clientAcceptsGzip(req *http.Request) bool { encodings := req.Header.Get(AcceptEncodingHeaderKey) return strings.Contains(encodings, "gzip") }