diff options
Diffstat (limited to 'handler.go')
-rw-r--r-- | handler.go | 54 |
1 files changed, 39 insertions, 15 deletions
@@ -1,31 +1,21 @@ package main import ( + "bytes" + "context" "fmt" + "io/ioutil" "log" - "mime" "net/url" "os" + "os/exec" "path/filepath" "strings" + "time" gemini "git.sr.ht/~yotam/go-gemini" ) -func absPathMime(path string) string { - ext := filepath.Ext(path) - return mime.TypeByExtension(ext) -} - -func isFile(path string) bool { - fileInfo, err := os.Stat(path) - if err != nil { - return false - } - - return fileInfo.Mode().IsRegular() -} - // Handler is the main handler of the server type Handler struct { cfg Config @@ -83,6 +73,36 @@ func (h Handler) getFilePath(rawURL string) (string, error) { return "", gemini.Error{Err: fmt.Errorf("file not found"), Status: gemini.StatusNotFound} } +func (h Handler) serveExecutable(r gemini.Request, path string) gemini.Response { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(h.cfg.ExecTimeout)*time.Second) + defer cancel() + + cmd := exec.CommandContext(ctx, path) + + stdin, err := cmd.StdinPipe() + if err != nil { + return gemini.ErrorResponse(err) + } + defer stdin.Close() + + _, err = fmt.Fprintf(stdin, "%s\r\n", r.URL) + if err != nil { + return gemini.ErrorResponse(err) + } + + // The gemini library api make it hard to stream stdout instead of reading it into memory + out, err := cmd.Output() + if err != nil { + return gemini.ErrorResponse(err) + } + + if ctx.Err() == context.DeadlineExceeded { + return gemini.ErrorResponse(ctx.Err()) + } + + return gemini.Response{Status: 20, Meta: "text/gemini", Body: ioutil.NopCloser(bytes.NewReader(out))} +} + func (h Handler) serveFile(path string) gemini.Response { log.Println("Serving file from", path) @@ -107,5 +127,9 @@ func (h Handler) Handle(r gemini.Request) gemini.Response { return gemini.ErrorResponse(err) } + if isExecutable(path) { + return h.serveExecutable(r, path) + } + return h.serveFile(path) } |