diff --git a/cgi.go b/cgi.go index 391174ceb4..9fcbd8fe46 100644 --- a/cgi.go +++ b/cgi.go @@ -204,9 +204,8 @@ func splitCgiPath(fc *frankenPHPContext) { // If a worker is already assigned explicitly, derive SCRIPT_NAME from its filename if fc.worker != nil { fc.scriptFilename = fc.worker.fileName - docRootWithSep := fc.documentRoot + string(filepath.Separator) - if strings.HasPrefix(fc.worker.fileName, docRootWithSep) { - fc.scriptName = filepath.ToSlash(strings.TrimPrefix(fc.worker.fileName, fc.documentRoot)) + if rest, ok := strings.CutPrefix(fc.worker.fileName, fc.documentRoot); ok && rest != "" && rest[0] == filepath.Separator { + fc.scriptName = filepath.ToSlash(rest) } else { fc.docURI = "" fc.pathInfo = "" diff --git a/cgi_test.go b/cgi_test.go index 4a3a1c41f6..81107c55c2 100644 --- a/cgi_test.go +++ b/cgi_test.go @@ -1,6 +1,8 @@ package frankenphp import ( + "net/http" + "net/url" "path/filepath" "runtime" "strings" @@ -519,3 +521,43 @@ func FuzzSplitRemoteAddr(f *testing.F) { splitRemoteAddr(remoteAddr) }) } + +func TestAssignedWorkerScriptPath(t *testing.T) { + t.Parallel() + sep := string(filepath.Separator) + root := filepath.Join(sep, "var", "www") + cases := []struct{ name, root, file string }{ + {"inside", root, root + sep + "index.php"}, + {"neighbor", root, root + "-other" + sep + "index.php"}, + {"exact", root, root}, + {"empty filename", root, ""}, + {"empty root", "", sep + "index.php"}, + {"empty paths", "", ""}, + {"trailing separator", root + sep, root + sep + sep + "index.php"}, + {"missing second separator", root + sep, root + sep + "index.php"}, + {"filesystem root", sep, sep + sep + "index.php"}, + {"unicode", root + sep + "приложение", root + sep + "приложение" + sep + "index.php"}, + {"binary", root + "\x00\xff", root + "\x00\xff" + sep + "index.php"}, + {"long root", strings.Repeat(root, 16), strings.Repeat(root, 16) + sep + "index.php"}, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + fc := frankenPHPContext{ + documentRoot: tt.root, + request: &http.Request{URL: &url.URL{Path: "/index.php/info"}}, + worker: &worker{fileName: tt.file}, + } + splitCgiPath(&fc) + assert.Equal(t, tt.file, fc.scriptFilename) + if strings.HasPrefix(tt.file, tt.root+sep) { + assert.Equal(t, filepath.ToSlash(strings.TrimPrefix(tt.file, tt.root)), fc.scriptName) + assert.Equal(t, "/index.php", fc.docURI) + assert.Equal(t, "/info", fc.pathInfo) + } else { + assert.Empty(t, fc.scriptName) + assert.Empty(t, fc.docURI) + assert.Empty(t, fc.pathInfo) + } + }) + } +}