Repository: caddyserver/caddy
File: replacer.go (Go)

Code before:
type replacementProvider interface {
	replace(key string) (any, bool)
}

// fileReplacementsProvider handles {file.*} replacements,
// reading a file from disk and replacing with its contents.
type fileReplacementProvider struct{}

func (f fileReplacementProvider) replace(key string) (any, bool) {
	if !strings.HasPrefix(key, filePrefix) {
		return nil, false
	}

	filename := key[len(filePrefix):]
	maxSize := 1024 * 1024
	body, err := readFileIntoBuffer(filename, maxSize)
	if err != nil {
		wd, _ := os.Getwd()
		Log().Error("placeholder: failed to read file",
			zap.String("file", filename),
			zap.String("working_dir", wd),
			zap.Error(err))
		return nil, true
	}
	content := string(body)
	content = strings.TrimSuffix(content, "\n")
	return content, true
}

// globalDefaultReplacementsProvider handles replacements
// that can be used in any context, such as system variables,
// time, or environment variables.
type globalDefaultReplacementProvider struct{}

func (f globalDefaultReplacementProvider) replace(key string) (any, bool) {
	// check environment variable
	const envPrefix = "env."
	if strings.HasPrefix(key, envPrefix) {
		return os.Getenv(key[len(envPrefix):]), true
	}

	switch key {
	case "system.hostname":
		// OK if there is an error; just return empty string
		name, _ := os.Hostname()
		return name, true
	case "system.slash":
		return string(filepath.Separator), true
	case "system.os":
		return runtime.GOOS, true
	case "system.wd":

Review comment (suggestion):
Let's try this? 

```suggestion
	content = strings.TrimRight(content, "\r\n")
```

Though now that I think about it, this might recursively remove all the newlines from the end, so it might not preserve the extra newline. Bah.

Code after:
// which type of provider it is.
type replacementProvider interface {
	replace(key string) (any, bool)
}

// fileReplacementsProvider handles {file.*} replacements,
// reading a file from disk and replacing with its contents.
type fileReplacementProvider struct{}

func (f fileReplacementProvider) replace(key string) (any, bool) {
	if !strings.HasPrefix(key, filePrefix) {
		return nil, false
	}

	filename := key[len(filePrefix):]
	maxSize := 1024 * 1024
	body, err := readFileIntoBuffer(filename, maxSize)
	if err != nil {
		wd, _ := os.Getwd()
		Log().Error("placeholder: failed to read file",
			zap.String("file", filename),
			zap.String("working_dir", wd),
			zap.Error(err))
		return nil, true
	}
	body = bytes.TrimSuffix(body, []byte("\n"))
	body = bytes.TrimSuffix(body, []byte("\r"))
	return string(body), true
}

// globalDefaultReplacementsProvider handles replacements
// that can be used in any context, such as system variables,
// time, or environment variables.
type globalDefaultReplacementProvider struct{}

func (f globalDefaultReplacementProvider) replace(key string) (any, bool) {
	// check environment variable
	const envPrefix = "env."
	if strings.HasPrefix(key, envPrefix) {
		return os.Getenv(key[len(envPrefix):]), true
	}

	switch key {
	case "system.hostname":
		// OK if there is an error; just return empty string
		name, _ := os.Hostname()
		return name, true
	case "system.slash":
		return string(filepath.Separator), true
	case "system.os":
		return runtime.GOOS, true