package fs import ( "context" "io/fs" "mime" "strings" "tildegit.org/tjp/gus/gemini" ) // FileHandler builds a handler function which serves up a file system. func FileHandler(fileSystem fs.FS) gemini.Handler { return func(ctx context.Context, req *gemini.Request) *gemini.Response { file, err := fileSystem.Open(strings.TrimPrefix(req.Path, "/")) if isNotFound(err) { return gemini.NotFound("Resource does not exist.") } if err != nil { return gemini.Failure(err) } isDir, err := fileIsDir(file) if err != nil { return gemini.Failure(err) } if isDir { return gemini.NotFound("Resource does not exist.") } return gemini.Success(mediaType(req.Path), file) } } func mediaType(filePath string) string { if strings.HasSuffix(filePath, ".gmi") { // This may not be present in the listings searched by mime.TypeByExtension, // so provide a dedicated fast path for it here. return "text/gemini" } slashIdx := strings.LastIndex(filePath, "/") dotIdx := strings.LastIndex(filePath[slashIdx+1:], ".") if dotIdx == -1 { return "application/octet-stream" } ext := filePath[slashIdx+dotIdx:] mtype := mime.TypeByExtension(ext) if mtype == "" { return "application/octet-stream" } return mtype }