diff options
author | tjp <tjp@ctrl-c.club> | 2023-11-13 07:25:39 -0700 |
---|---|---|
committer | tjp <tjp@ctrl-c.club> | 2023-11-13 07:27:16 -0700 |
commit | 1e0f8e0aaeaf1bd2ee39c02e922238b641bcf88b (patch) | |
tree | 020e5de91f2343119fed10dede9d2c8262a3cd83 /internal | |
parent | a808b4692656c10bb43e2d54a2f5ef2746d231d5 (diff) |
refactor contribs to work with a Protocol interface
Diffstat (limited to 'internal')
-rw-r--r-- | internal/filetypes.go | 57 | ||||
-rw-r--r-- | internal/types/protocol.go | 19 |
2 files changed, 76 insertions, 0 deletions
diff --git a/internal/filetypes.go b/internal/filetypes.go new file mode 100644 index 0000000..6824ffc --- /dev/null +++ b/internal/filetypes.go @@ -0,0 +1,57 @@ +package internal + +import ( + "mime" + "os" + "strings" + "unicode/utf8" +) + +func MediaType(fpath string) string { + if strings.HasSuffix(fpath, ".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(fpath, "/") + dotIdx := strings.LastIndex(fpath[slashIdx+1:], ".") + if dotIdx == -1 { + return "application/octet-stream" + } + ext := fpath[slashIdx+1+dotIdx:] + + mtype := mime.TypeByExtension(ext) + if mtype == "" { + if ContentsAreText(fpath) { + return "text/plain" + } + return "application/octet-stream" + } + return mtype +} + +func ContentsAreText(fpath string) bool { + f, err := os.Open(fpath) + if err != nil { + return false + } + defer func() { _ = f.Close() }() + + var buf [1024]byte + n, err := f.Read(buf[:]) + if err != nil { + return false + } + + for i, c := range string(buf[:n]) { + if i+utf8.UTFMax > n { + // incomplete last char + break + } + if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' { + return false + } + } + return true +} diff --git a/internal/types/protocol.go b/internal/types/protocol.go new file mode 100644 index 0000000..7166d8f --- /dev/null +++ b/internal/types/protocol.go @@ -0,0 +1,19 @@ +package types + +import ( + "io" + "net/url" +) + +type ServerProtocol interface { + TemporaryRedirect(*url.URL) *Response + PermanentRedirect(*url.URL) *Response + + TemporaryServerError(error) *Response + PermanentServerError(error) *Response + CGIFailure(error) *Response + + Success(filename string, body io.Reader) *Response + + ParseResponse(io.Reader) (*Response, error) +} |