summaryrefslogtreecommitdiff
path: root/contrib/cgi/gemini.go
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cgi/gemini.go')
-rw-r--r--contrib/cgi/gemini.go47
1 files changed, 47 insertions, 0 deletions
diff --git a/contrib/cgi/gemini.go b/contrib/cgi/gemini.go
new file mode 100644
index 0000000..8302e7e
--- /dev/null
+++ b/contrib/cgi/gemini.go
@@ -0,0 +1,47 @@
+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
+ }
+}