diff options
-rw-r--r-- | contrib/fs/file.go | 30 | ||||
-rw-r--r-- | contrib/fs/gopher.go | 3 | ||||
-rw-r--r-- | gopher/response.go | 33 |
3 files changed, 64 insertions, 2 deletions
diff --git a/contrib/fs/file.go b/contrib/fs/file.go index 7690a62..9f11f4f 100644 --- a/contrib/fs/file.go +++ b/contrib/fs/file.go @@ -2,7 +2,9 @@ package fs import ( "mime" + "os" "strings" + "unicode/utf8" ) func mediaType(filePath string) string { @@ -21,6 +23,9 @@ func mediaType(filePath string) string { mtype := mime.TypeByExtension(ext) if mtype == "" { + if contentsAreText(filePath) { + return "text/plain" + } return "application/octet-stream" } return mtype @@ -34,3 +39,28 @@ func isPrivate(fullpath string) bool { } return false } + +func contentsAreText(filepath string) bool { + f, err := os.Open(filepath) + 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/contrib/fs/gopher.go b/contrib/fs/gopher.go index db21227..0a0b482 100644 --- a/contrib/fs/gopher.go +++ b/contrib/fs/gopher.go @@ -185,7 +185,8 @@ func isFile(path string) (bool, error) { } func isMap(path string, settings gophermap.FileSystemSettings) bool { - if strings.HasSuffix(path, ".gophermap") { + base := filepath.Base(path) + if base == "gophermap" || strings.HasSuffix(base, ".gph") || strings.HasSuffix(base, ".gophermap") { return true } return slices.Contains(settings.DirMaps, filepath.Base(path)) diff --git a/gopher/response.go b/gopher/response.go index c594fa7..269176f 100644 --- a/gopher/response.go +++ b/gopher/response.go @@ -5,9 +5,11 @@ import ( "fmt" "io" "mime" + "os" "path" "strings" "sync" + "unicode/utf8" "tildegit.org/tjp/sliderule/internal/types" ) @@ -173,7 +175,7 @@ func GuessItemType(filepath string) types.Status { case ".txt", ".gmi", ".md": return TextFileType case ".gif": - return GifFileType + return GifFileType case ".png": return PngImageFileType case ".jpg", ".jpeg", ".tif", ".tiff": @@ -205,5 +207,34 @@ func GuessItemType(filepath string) types.Status { return TextFileType } + if contentsAreText(filepath) { + return TextFileType + } + return BinaryFileType } + +func contentsAreText(filepath string) bool { + f, err := os.Open(filepath) + 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 +} |