From 2ae8c119279826ef81223e3b2155a08779f3ee8b Mon Sep 17 00:00:00 2001
From: Manuel Dalla Lana <manuel@dallalana.it>
Date: Mon, 20 Jul 2020 20:16:13 +0200
Subject: fastcgi: Add resolve_root_symlink (#3587)

---
 modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go | 12 ++++++++++++
 modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go   | 15 +++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go b/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
index 03b7226..8228439 100644
--- a/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
@@ -39,6 +39,7 @@ func init() {
 //         root <path>
 //         split <at>
 //         env <key> <value>
+//         resolve_root_symlink
 //     }
 //
 func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
@@ -67,6 +68,9 @@ func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
 				}
 				t.EnvVars[args[0]] = args[1]
 
+			case "resolve_root_symlink":
+				t.ResolveRootSymlink = true
+
 			default:
 				return d.Errf("unrecognized subdirective %s", d.Val())
 			}
@@ -196,6 +200,14 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
 					return nil, dispenser.ArgErr()
 				}
 				indexFile = args[0]
+
+			case "resolve_root_symlink":
+				args := dispenser.RemainingArgs()
+				dispenser.Delete()
+				for range args {
+					dispenser.Delete()
+				}
+				fcgiTransport.ResolveRootSymlink = true
 			}
 		}
 	}
diff --git a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
index 8c03172..de6d0a4 100644
--- a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
+++ b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
@@ -54,6 +54,14 @@ type Transport struct {
 	// that 404s if the fastcgi path info is not found.
 	SplitPath []string `json:"split_path,omitempty"`
 
+	// Path declared as root directory will be resolved to its absolute value
+	// after the evaluation of any symbolic links.
+	// Due to the nature of PHP opcache, root directory path is cached: when
+	// using a symlinked directory as root this could generate errors when
+	// symlink is changed without php-fpm being restarted; enabling this
+	// directive will set $_SERVER['DOCUMENT_ROOT'] to the real directory path.
+	ResolveRootSymlink bool `json:"resolve_root_symlink,omitempty"`
+
 	// Extra environment variables.
 	EnvVars map[string]string `json:"env,omitempty"`
 
@@ -179,6 +187,13 @@ func (t Transport) buildEnv(r *http.Request) (map[string]string, error) {
 		return nil, err
 	}
 
+	if t.ResolveRootSymlink {
+		root, err = filepath.EvalSymlinks(root)
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	fpath := r.URL.Path
 
 	// split "actual path" from "path info" if configured
-- 
cgit v1.2.3