// Copyright 2015 Matthew Holt and The Caddy Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package integration import ( "fmt" "io" "net" "net/http" "net/http/fcgi" "os" "path/filepath" "strings" "testing" "github.com/caddyserver/caddy/v2/caddytest" ) // startFakePHPFPM starts a FastCGI responder that reports the SCRIPT_FILENAME it // was asked to execute, so a test can assert which script Caddy selected. func startFakePHPFPM(t *testing.T) string { t.Helper() ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listening: %v", err) } t.Cleanup(func() { ln.Close() }) go func() { _ = fcgi.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { env := fcgi.ProcessEnv(r) fmt.Fprintf(w, "SCRIPT_FILENAME=%s", env["SCRIPT_FILENAME"]) })) }() return ln.Addr().String() } // A php_fastcgi route protected by a path matcher must not execute a script the // matcher never evaluated. Path matchers judge the cleaned request path, so // /admin.php/../../other.php is matched as /other.php and must not cause // /admin.php to be executed. // // `index off` is used so that php_fastcgi generates no rewrite route at all // (fastcgi/caddyfile.go skips the redirect and try_files routes entirely). That // rewrite is otherwise the only step that normalizes r.URL.Path before the // transport reads it, so without this the test would be satisfied by the rewrite // rather than by the transport, and would not cover the transport's own // normalization. func TestPHPFastCGIProtectedRouteIgnoresDotSegments(t *testing.T) { root := t.TempDir() if err := os.WriteFile(filepath.Join(root, "admin.php"), []byte("