From 04449ed66e4272ee08bc1dd00f6bdefb2be51a43 Mon Sep 17 00:00:00 2001 From: tjpcc Date: Tue, 10 Oct 2023 14:47:54 -0600 Subject: support an overridden "cmd" for CGIs --- contrib/cgi/cgi.go | 22 ++++++++++------------ contrib/cgi/cgi_test.go | 2 +- contrib/cgi/gemini.go | 14 ++++++++++---- contrib/cgi/gopher.go | 18 ++++++++++++------ 4 files changed, 33 insertions(+), 23 deletions(-) (limited to 'contrib/cgi') diff --git a/contrib/cgi/cgi.go b/contrib/cgi/cgi.go index 48af04a..b7dd14a 100644 --- a/contrib/cgi/cgi.go +++ b/contrib/cgi/cgi.go @@ -11,6 +11,7 @@ import ( "net" "os" "os/exec" + "path/filepath" "strings" sr "tildegit.org/tjp/sliderule" @@ -88,16 +89,9 @@ func RunCGI( request *sr.Request, executable string, pathInfo string, + workdir string, stderr io.Writer, ) (*bytes.Buffer, int, error) { - pathSegments := strings.Split(executable, "/") - - dirPath := "." - if len(pathSegments) > 1 { - dirPath = strings.Join(pathSegments[:len(pathSegments)-1], "/") - } - basename := pathSegments[len(pathSegments)-1] - infoLen := len(pathInfo) if pathInfo == "/" { infoLen = 0 @@ -106,9 +100,14 @@ func RunCGI( scriptName := request.Path[:len(request.Path)-infoLen] scriptName = strings.TrimSuffix(scriptName, "/") - cmd := exec.CommandContext(ctx, "./"+basename) + execpath, err := filepath.Abs(executable) + if err != nil { + return nil, 0, err + } + + cmd := exec.CommandContext(ctx, execpath) cmd.Env = prepareCGIEnv(ctx, request, scriptName, pathInfo) - cmd.Dir = dirPath + cmd.Dir = workdir if body, ok := request.Meta.(io.Reader); ok { cmd.Stdin = body @@ -117,8 +116,7 @@ func RunCGI( cmd.Stdout = responseBuffer cmd.Stderr = stderr - err := cmd.Run() - if err != nil { + if err := cmd.Run(); err != nil { var exErr *exec.ExitError if errors.As(err, &exErr) { return responseBuffer, exErr.ExitCode(), nil diff --git a/contrib/cgi/cgi_test.go b/contrib/cgi/cgi_test.go index 5469fc8..e5fb306 100644 --- a/contrib/cgi/cgi_test.go +++ b/contrib/cgi/cgi_test.go @@ -21,7 +21,7 @@ func TestCGIDirectory(t *testing.T) { tlsconf, err := gemini.FileTLS("testdata/server.crt", "testdata/server.key") require.Nil(t, err) - handler := cgi.GeminiCGIDirectory("./testdata", "/cgi-bin") + handler := cgi.GeminiCGIDirectory("./testdata", "/cgi-bin", "") server, err := gemini.NewServer(context.Background(), "localhost", "tcp", "127.0.0.1:0", handler, nil, tlsconf) require.Nil(t, err) diff --git a/contrib/cgi/gemini.go b/contrib/cgi/gemini.go index 3ad407d..0aa3044 100644 --- a/contrib/cgi/gemini.go +++ b/contrib/cgi/gemini.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "path/filepath" "strings" sr "tildegit.org/tjp/sliderule" @@ -17,23 +18,28 @@ import ( // 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(fsroot, urlroot string) sr.Handler { +func GeminiCGIDirectory(fsroot, urlroot, cmd string) sr.Handler { fsroot = strings.TrimRight(fsroot, "/") return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { if !strings.HasPrefix(request.Path, urlroot) { return nil } - filepath, pathinfo, err := ResolveCGI(request.Path[len(urlroot):], fsroot) + execpath, pathinfo, err := ResolveCGI(request.Path[len(urlroot):], fsroot) if err != nil { return gemini.Failure(err) } - if filepath == "" { + if execpath == "" { return nil } + workdir := filepath.Dir(execpath) + + if cmd != "" { + execpath = cmd + } stderr := &bytes.Buffer{} - stdout, exitCode, err := RunCGI(ctx, request, filepath, pathinfo, stderr) + stdout, exitCode, err := RunCGI(ctx, request, execpath, pathinfo, workdir, stderr) if err != nil { return gemini.Failure(err) } diff --git a/contrib/cgi/gopher.go b/contrib/cgi/gopher.go index bb3e73e..7067a6d 100644 --- a/contrib/cgi/gopher.go +++ b/contrib/cgi/gopher.go @@ -21,7 +21,7 @@ import ( // 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(fsroot, urlroot string, settings *gophermap.FileSystemSettings) sr.Handler { +func GopherCGIDirectory(fsroot, urlroot, cmd string, settings *gophermap.FileSystemSettings) sr.Handler { if settings == nil || !settings.Exec { return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { return nil }) } @@ -41,12 +41,12 @@ func GopherCGIDirectory(fsroot, urlroot string, settings *gophermap.FileSystemSe return nil } - return runGopherCGI(ctx, request, fullpath, pathinfo, *settings) + return runGopherCGI(ctx, request, fullpath, pathinfo, cmd, *settings) }) } // ExecGopherMaps runs any gophermaps -func ExecGopherMaps(fsroot, urlroot string, settings *gophermap.FileSystemSettings) sr.Handler { +func ExecGopherMaps(fsroot, urlroot, cmd string, settings *gophermap.FileSystemSettings) sr.Handler { if settings == nil || !settings.Exec { return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response { return nil }) } @@ -85,7 +85,7 @@ func ExecGopherMaps(fsroot, urlroot string, settings *gophermap.FileSystemSettin if !m.IsRegular() || m&5 != 5 { continue } - return runGopherCGI(ctx, request, fpath, "/", *settings) + return runGopherCGI(ctx, request, fpath, "/", cmd, *settings) } return nil @@ -96,7 +96,7 @@ func ExecGopherMaps(fsroot, urlroot string, settings *gophermap.FileSystemSettin return nil } - return runGopherCGI(ctx, request, fullpath, "/", *settings) + return runGopherCGI(ctx, request, fullpath, "/", cmd, *settings) }) } @@ -105,10 +105,16 @@ func runGopherCGI( request *sr.Request, fullpath string, pathinfo string, + cmd string, settings gophermap.FileSystemSettings, ) *sr.Response { + workdir := filepath.Dir(fullpath) + if cmd != "" { + fullpath = cmd + } + stderr := &bytes.Buffer{} - stdout, exitCode, err := RunCGI(ctx, request, fullpath, pathinfo, stderr) + stdout, exitCode, err := RunCGI(ctx, request, fullpath, pathinfo, workdir, stderr) if err != nil { return gopher.Error(err).Response() } -- cgit v1.2.3