diff options
author | Yotam Nachum <me@yotam.net> | 2019-11-01 13:29:44 +0200 |
---|---|---|
committer | Yotam Nachum <me@yotam.net> | 2019-11-01 13:29:44 +0200 |
commit | 89276ae650ca12af46ac386ca9c7626cc6b67a27 (patch) | |
tree | 31823689a7f8e236482ed489cad603b7ebab50be | |
parent | Initial commit (diff) | |
download | shavit-89276ae650ca12af46ac386ca9c7626cc6b67a27.tar.gz shavit-89276ae650ca12af46ac386ca9c7626cc6b67a27.zip |
Add support for index file
-rw-r--r-- | handler.go | 98 | ||||
-rw-r--r-- | main.go | 36 |
2 files changed, 98 insertions, 36 deletions
diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..aaab9eb --- /dev/null +++ b/handler.go @@ -0,0 +1,98 @@ +package main + +import ( + "fmt" + "log" + "net/url" + "os" + "path/filepath" + "strings" + + "git.sr.ht/~yotam/go-gemini" +) + +type GeminiError struct { + Err error + Status int +} + +func (e GeminiError) Error() string { + return e.Err.Error() +} + +type MainHandler struct { + source string +} + +func (h MainHandler) urlAbsPath(rawURL string) (string, error) { + u, err := url.Parse(rawURL) + if err != nil { + return "", GeminiError{err, gemini.StatusBadRequest} + } + + itemPath, err := filepath.Abs(filepath.Join(h.source, u.Path)) + if err != nil { + return "", GeminiError{err, gemini.StatusTemporaryFailure} + } + + if !strings.HasPrefix(itemPath, h.source) { + return "", GeminiError{fmt.Errorf("Permission Denied"), gemini.StatusBadRequest} + } + + return itemPath, nil +} + +func (h MainHandler) isFile(path string) bool { + fileInfo, err := os.Stat(path) + if err != nil { + return false + } + + return fileInfo.Mode().IsRegular() +} + +func (h MainHandler) getFilePath(rawURL string) (string, error) { + itemPath, err := h.urlAbsPath(rawURL) + if err != nil { + return "", err + } + + if h.isFile(itemPath) { + return itemPath, nil + } + + indexPath := filepath.Join(itemPath, "index.gemi") + if h.isFile(indexPath) { + return indexPath, nil + } + + return "", GeminiError{fmt.Errorf("File Not Found"), gemini.StatusNotFound} +} + +func (h MainHandler) errorResponse(err error) gemini.Response { + if err == nil { + panic("nil error is not a valid parameter") + } + + if ge, ok := err.(GeminiError); ok { + return gemini.Response{ge.Status, ge.Error(), nil} + } + + return gemini.Response{gemini.StatusTemporaryFailure, err.Error(), nil} +} + +func (h MainHandler) Handle(r gemini.Request) gemini.Response { + itemPath, err := h.getFilePath(r.URL) + if err != nil { + return h.errorResponse(err) + } + + log.Println("Serving file from", itemPath) + + file, err := os.Open(itemPath) + if err != nil { + return h.errorResponse(err) + } + + return gemini.Response{gemini.StatusSuccess, "text/gemini", file} +} @@ -2,47 +2,11 @@ package main import ( "log" - "net/url" - "os" "path/filepath" - "strings" "git.sr.ht/~yotam/go-gemini" ) -type MainHandler struct { - source string -} - -func (h MainHandler) Handle(r gemini.Request) gemini.Response { - u, err := url.Parse(r.URL) - if err != nil { - return gemini.Response{gemini.StatusBadRequest, err.Error(), nil} - } - - itemPath, err := filepath.Abs(filepath.Join(h.source, u.Path)) - if err != nil { - return gemini.Response{gemini.StatusTemporaryFailure, err.Error(), nil} - } - - log.Println("Serving file from", itemPath) - - if !strings.HasPrefix(itemPath, h.source) { - return gemini.Response{gemini.StatusBadRequest, "Permission denied", nil} - } - - if _, err := os.Stat(itemPath); os.IsNotExist(err) { - return gemini.Response{gemini.StatusNotFound, "Not found", nil} - } - - file, err := os.Open(itemPath) - if err != nil { - return gemini.Response{gemini.StatusTemporaryFailure, err.Error(), nil} - } - - return gemini.Response{gemini.StatusSuccess, "text/gemini", file} -} - func main() { cfg, err := getConfig("config.toml") if err != nil { |