fix: race condition introduced in 04fdc0c (#2180)

Fix issue introduced in 04fdc0c1e8
This commit is contained in:
Kévin Dunglas
2026-02-11 13:07:09 +01:00
committed by GitHub
parent 24d6c991a7
commit 471c5af2df
4 changed files with 39 additions and 26 deletions

View File

@@ -118,7 +118,12 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
if len(f.SplitPath) == 0 { if len(f.SplitPath) == 0 {
f.SplitPath = []string{".php"} f.SplitPath = []string{".php"}
} }
f.requestOptions = append(f.requestOptions, frankenphp.WithRequestSplitPath(f.SplitPath))
if opt, err := frankenphp.WithRequestSplitPath(f.SplitPath); err == nil {
f.requestOptions = append(f.requestOptions, opt)
} else {
f.requestOptions = append(f.requestOptions, opt)
}
if f.ResolveRootSymlink == nil { if f.ResolveRootSymlink == nil {
rrs := true rrs := true
@@ -188,6 +193,10 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer) repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
documentRoot := f.resolvedDocumentRoot documentRoot := f.resolvedDocumentRoot
opts := make([]frankenphp.RequestOption, 0, len(f.requestOptions)+4)
opts = append(opts, f.requestOptions...)
if documentRoot == "" { if documentRoot == "" {
documentRoot = repl.ReplaceKnown(f.Root, "") documentRoot = repl.ReplaceKnown(f.Root, "")
if documentRoot == "" && frankenphp.EmbeddedAppPath != "" { if documentRoot == "" && frankenphp.EmbeddedAppPath != "" {
@@ -197,7 +206,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
// If we do not have a resolved document root, then we cannot resolve the symlink of our cwd because it may // If we do not have a resolved document root, then we cannot resolve the symlink of our cwd because it may
// resolve to a different directory than the one we are currently in. // resolve to a different directory than the one we are currently in.
// This is especially important if there are workers running. // This is especially important if there are workers running.
f.requestOptions = append(f.requestOptions, frankenphp.WithRequestDocumentRoot(documentRoot, false)) opts = append(opts, frankenphp.WithRequestDocumentRoot(documentRoot, false))
} }
if f.preparedEnvNeedsReplacement { if f.preparedEnvNeedsReplacement {
@@ -206,7 +215,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
env[k] = repl.ReplaceKnown(v, "") env[k] = repl.ReplaceKnown(v, "")
} }
f.requestOptions = append(f.requestOptions, frankenphp.WithRequestPreparedEnv(env)) opts = append(opts, frankenphp.WithRequestPreparedEnv(env))
} }
workerName := "" workerName := ""
@@ -220,7 +229,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
fr, err := frankenphp.NewRequestWithContext( fr, err := frankenphp.NewRequestWithContext(
r, r,
append( append(
f.requestOptions, opts,
frankenphp.WithOriginalRequest(&origReq), frankenphp.WithOriginalRequest(&origReq),
frankenphp.WithWorkerName(workerName), frankenphp.WithWorkerName(workerName),
)..., )...,

2
go.mod
View File

@@ -12,6 +12,7 @@ require (
github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_golang v1.23.2
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
golang.org/x/net v0.49.0 golang.org/x/net v0.49.0
golang.org/x/text v0.33.0
) )
require ( require (
@@ -60,7 +61,6 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.47.0 // indirect golang.org/x/crypto v0.47.0 // indirect
golang.org/x/sys v0.40.0 // indirect golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View File

@@ -82,34 +82,34 @@ func WithRequestResolvedDocumentRoot(documentRoot string) RequestOption {
// Future enhancements should be careful to avoid CVE-2019-11043, // Future enhancements should be careful to avoid CVE-2019-11043,
// which can be mitigated with use of a try_files-like behavior // which can be mitigated with use of a try_files-like behavior
// that 404s if the FastCGI path info is not found. // that 404s if the FastCGI path info is not found.
func WithRequestSplitPath(splitPath []string) RequestOption { func WithRequestSplitPath(splitPath []string) (RequestOption, error) {
return func(o *frankenPHPContext) error { var b strings.Builder
var b strings.Builder
for i, split := range splitPath { for i, split := range splitPath {
b.Grow(len(split)) b.Grow(len(split))
for j := 0; j < len(split); j++ { for j := 0; j < len(split); j++ {
c := split[j] c := split[j]
if c >= utf8.RuneSelf { if c >= utf8.RuneSelf {
return ErrInvalidSplitPath return nil, ErrInvalidSplitPath
}
if 'A' <= c && c <= 'Z' {
b.WriteByte(c + 'a' - 'A')
} else {
b.WriteByte(c)
}
} }
splitPath[i] = b.String() if 'A' <= c && c <= 'Z' {
b.Reset() b.WriteByte(c + 'a' - 'A')
} else {
b.WriteByte(c)
}
} }
splitPath[i] = b.String()
b.Reset()
}
return func(o *frankenPHPContext) error {
o.splitPath = splitPath o.splitPath = splitPath
return nil return nil
} }, nil
} }
type PreparedEnv = map[string]string type PreparedEnv = map[string]string

View File

@@ -8,6 +8,8 @@ import (
) )
func TestWithRequestSplitPath(t *testing.T) { func TestWithRequestSplitPath(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
name string name string
splitPath []string splitPath []string
@@ -52,9 +54,10 @@ func TestWithRequestSplitPath(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ctx := &frankenPHPContext{} ctx := &frankenPHPContext{}
opt := WithRequestSplitPath(tt.splitPath) opt, err := WithRequestSplitPath(tt.splitPath)
err := opt(ctx)
if tt.wantErr != nil { if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr) require.ErrorIs(t, err, tt.wantErr)
@@ -63,6 +66,7 @@ func TestWithRequestSplitPath(t *testing.T) {
} }
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, opt(ctx))
assert.Equal(t, tt.wantSplitPath, ctx.splitPath) assert.Equal(t, tt.wantSplitPath, ctx.splitPath)
}) })
} }