From ff05d62013906f3086b452bfeda3e0d5b9b7a541 Mon Sep 17 00:00:00 2001 From: tjpcc Date: Mon, 9 Jan 2023 16:40:24 -0700 Subject: Initial commit. some basics: - minimal README - some TODOs - server and request handler framework - contribs: file serving, request logging - server examples - CI setup --- contrib/fs/file.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 contrib/fs/file.go (limited to 'contrib/fs/file.go') diff --git a/contrib/fs/file.go b/contrib/fs/file.go new file mode 100644 index 0000000..cdcd1a9 --- /dev/null +++ b/contrib/fs/file.go @@ -0,0 +1,55 @@ +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 +} -- cgit v1.2.3