diff --git a/caddyhttp/root/root.go b/caddyhttp/root/root.go index b3dded1c..f9f11bfa 100644 --- a/caddyhttp/root/root.go +++ b/caddyhttp/root/root.go @@ -28,16 +28,23 @@ func setupRoot(c *caddy.Controller) error { return c.ArgErr() } } - - // Check if root path exists - _, err := os.Stat(config.Root) - if err != nil { - if os.IsNotExist(err) { - // Allow this, because the folder might appear later. - // But make sure the user knows! - log.Printf("[WARNING] Root path does not exist: %s", config.Root) - } else { - return c.Errf("Unable to access root path '%s': %v", config.Root, err) + //first check that the path is not a symlink, os.Stat panics when this is true + info, _ := os.Lstat(config.Root) + if info != nil && info.Mode()&os.ModeSymlink == os.ModeSymlink { + //just print out info, delegate responsibility for symlink validity to + //underlying Go framework, no need to test / verify twice + log.Printf("[INFO] Root path is symlink: %s", config.Root) + } else { + // Check if root path exists + _, err := os.Stat(config.Root) + if err != nil { + if os.IsNotExist(err) { + // Allow this, because the folder might appear later. + // But make sure the user knows! + log.Printf("[WARNING] Root path does not exist: %s", config.Root) + } else { + return c.Errf("Unable to access root path '%s': %v", config.Root, err) + } } } diff --git a/caddyhttp/root/root_test.go b/caddyhttp/root/root_test.go index daeb9eea..e4ad8841 100644 --- a/caddyhttp/root/root_test.go +++ b/caddyhttp/root/root_test.go @@ -91,7 +91,7 @@ func TestRoot(t *testing.T) { } } -// getTempDirPath returnes the path to the system temp directory. If it does not exists - an error is returned. +// getTempDirPath returns the path to the system temp directory. If it does not exists - an error is returned. func getTempDirPath() (string, error) { tempDir := os.TempDir() _, err := os.Stat(tempDir) @@ -104,3 +104,39 @@ func getTempDirPath() (string, error) { func getInaccessiblePath(file string) string { return filepath.Join("C:", "file\x00name") // null byte in filename is not allowed on Windows AND unix } + +func TestSymlinkRoot(t *testing.T) { + origDir, err := ioutil.TempDir("", "root_test") + if err != nil { + t.Fatalf("BeforeTest: Failed to create temp dir for testing! Error was: %v", err) + } + defer func() { + os.Remove(origDir) + }() + + tempDir, err := getTempDirPath() + if err != nil { + t.Fatalf("BeforeTest: Failed to find an existing directory for testing! Error was: %v", err) + } + symlinkDir := filepath.Join(tempDir, "symlink") + + err = os.Symlink(origDir, symlinkDir) + if err != nil { + if strings.Contains(err.Error(), "A required privilege is not held by the client") { + t.Skip("BeforeTest: A required privilege is not held by the client and is required to create a symlink to run this test.") + } + t.Fatalf("BeforeTest: Cannot create symlink! Error was: %v", err) + } + defer func() { + os.Remove(symlinkDir) + }() + + input := fmt.Sprintf(`root %s`, symlinkDir) + c := caddy.NewTestController("http", input) + err = setupRoot(c) + _ = httpserver.GetConfig(c) + + if err != nil { + t.Errorf("Test Symlink Root: Expected no error but found one for input %s. Error was: %v", input, err) + } +}