summaryrefslogtreecommitdiff
path: root/contrib/cgi/gopher.go
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cgi/gopher.go')
-rw-r--r--contrib/cgi/gopher.go45
1 files changed, 45 insertions, 0 deletions
diff --git a/contrib/cgi/gopher.go b/contrib/cgi/gopher.go
new file mode 100644
index 0000000..29bfdba
--- /dev/null
+++ b/contrib/cgi/gopher.go
@@ -0,0 +1,45 @@
+package cgi
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "tildegit.org/tjp/gus"
+ "tildegit.org/tjp/gus/gopher"
+)
+
+// GopherCGIDirectory 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 GopherCGIDirectory(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 gopher.Error(err).Response()
+ }
+ if filepath == "" {
+ return nil
+ }
+
+ stdout, exitCode, err := RunCGI(ctx, request, filepath, pathinfo)
+ if err != nil {
+ return gopher.Error(err).Response()
+ }
+ if exitCode != 0 {
+ return gopher.Error(
+ fmt.Errorf("CGI process exited with status %d", exitCode),
+ ).Response()
+ }
+
+ return gopher.File(0, stdout)
+ }
+}