diff options
author | tjpcc <tjp@ctrl-c.club> | 2023-01-09 16:40:24 -0700 |
---|---|---|
committer | tjpcc <tjp@ctrl-c.club> | 2023-01-09 16:40:24 -0700 |
commit | ff05d62013906f3086b452bfeda3e0d5b9b7a541 (patch) | |
tree | 3be29de0b1bc7c273041c6d89b71ca447c940556 /contrib/fs/file.go |
Initial commit.
some basics:
- minimal README
- some TODOs
- server and request handler framework
- contribs: file serving, request logging
- server examples
- CI setup
Diffstat (limited to 'contrib/fs/file.go')
-rw-r--r-- | contrib/fs/file.go | 55 |
1 files changed, 55 insertions, 0 deletions
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 +} |