package sushi import ( "fmt" "path" "strings" "time" "github.com/valyala/fasthttp" ) // StaticOptions configures static file serving type StaticOptions struct { Root string IndexNames []string GenerateIndexPages bool Compress bool CompressBrotli bool AcceptByteRange bool CacheDuration time.Duration MaxAge int } // StaticFS creates a handler for serving static files with fasthttp.FS func StaticFS(fsOptions StaticOptions) Handler { // Set defaults if fsOptions.Root == "" { fsOptions.Root = "." } if len(fsOptions.IndexNames) == 0 { fsOptions.IndexNames = []string{"index.html"} } fs := &fasthttp.FS{ Root: fsOptions.Root, IndexNames: fsOptions.IndexNames, GenerateIndexPages: fsOptions.GenerateIndexPages, Compress: fsOptions.Compress, CompressBrotli: fsOptions.CompressBrotli, AcceptByteRange: fsOptions.AcceptByteRange, CacheDuration: fsOptions.CacheDuration, } if fsOptions.MaxAge > 0 { fs.PathRewrite = func(ctx *fasthttp.RequestCtx) []byte { ctx.Response.Header.Set("Cache-Control", fmt.Sprintf("max-age=%d", fsOptions.MaxAge)) return ctx.Path() } } fsHandler := fs.NewRequestHandler() return func(ctx Ctx) { fsHandler(ctx.RequestCtx) } } // Static creates a simple static file handler func Static(root string) Handler { return StaticFS(StaticOptions{Root: root}) } // StaticFile serves a single file func StaticFile(filePath string) Handler { return func(ctx Ctx) { fasthttp.ServeFile(ctx.RequestCtx, filePath) } } // StaticEmbed creates a handler for embedded files func StaticEmbed(files map[string][]byte) Handler { return func(ctx Ctx) { requestPath := string(ctx.Path()) // Try to find the file if data, exists := files[requestPath]; exists { // Set content type based on extension ext := path.Ext(requestPath) contentType := getContentType(ext) ctx.SetContentType(contentType) ctx.Write(data) return } // Try index files if requestPath == "/" || strings.HasSuffix(requestPath, "/") { indexPath := requestPath + "index.html" if data, exists := files[indexPath]; exists { ctx.SetContentType("text/html") ctx.Write(data) return } } ctx.SetStatusCode(fasthttp.StatusNotFound) } } func getContentType(ext string) string { switch ext { case ".html", ".htm": return "text/html" case ".css": return "text/css" case ".js": return "application/javascript" case ".json": return "application/json" case ".png": return "image/png" case ".jpg", ".jpeg": return "image/jpeg" case ".gif": return "image/gif" case ".svg": return "image/svg+xml" case ".ico": return "image/x-icon" case ".pdf": return "application/pdf" case ".txt": return "text/plain" default: return "application/octet-stream" } }