48 lines
1.2 KiB
Go
48 lines
1.2 KiB
Go
package cgi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"tildegit.org/tjp/gus"
|
|
"tildegit.org/tjp/gus/gemini"
|
|
)
|
|
|
|
// GeminiCGIDirectory runs any executable files relative to a root directory on the file system.
|
|
//
|
|
// It will also find and run any executables _part way_ through the path, so for example
|
|
// a request for /foo/bar/baz can also run an executable found at /foo or /foo/bar. In
|
|
// such a case the PATH_INFO environment variable will include the remaining portion of
|
|
// the URI path.
|
|
func GeminiCGIDirectory(pathRoot, fsRoot string) gus.Handler {
|
|
fsRoot = strings.TrimRight(fsRoot, "/")
|
|
return func(ctx context.Context, request *gus.Request) *gus.Response {
|
|
if !strings.HasPrefix(request.Path, pathRoot) {
|
|
return nil
|
|
}
|
|
|
|
filepath, pathinfo, err := ResolveCGI(request.Path[len(pathRoot):], fsRoot)
|
|
if err != nil {
|
|
return gemini.Failure(err)
|
|
}
|
|
if filepath == "" {
|
|
return nil
|
|
}
|
|
|
|
stdout, exitCode, err := RunCGI(ctx, request, filepath, pathinfo)
|
|
if err != nil {
|
|
return gemini.Failure(err)
|
|
}
|
|
if exitCode != 0 {
|
|
return gemini.CGIError(fmt.Sprintf("CGI process exited with status %d", exitCode))
|
|
}
|
|
|
|
response, err := gemini.ParseResponse(stdout)
|
|
if err != nil {
|
|
return gemini.Failure(err)
|
|
}
|
|
return response
|
|
}
|
|
}
|