Repository: caddyserver/caddy
File: modules/caddyhttp/rewrite/rewrite.go (Go)

Code before:
func (rep regexReplacer) do(r *http.Request, repl *caddy.Replacer) {
	if rep.Find == "" || rep.re == nil {
		return
	}
	replace := repl.ReplaceAll(rep.Replace, "")
	changePath(r, func(pathOrRawPath string) string {
		return rep.re.ReplaceAllString(pathOrRawPath, replace)
	})
}

func changePath(req *http.Request, newVal func(pathOrRawPath string) string) {
	req.URL.RawPath = newVal(req.URL.EscapedPath())
	if p, err := url.PathUnescape(req.URL.RawPath); err == nil && p != "" {
		req.URL.Path = p
	} else {
		req.URL.Path = newVal(req.URL.Path)
	}
	// RawPath is only set if it's different from the normalized Path (std lib)
	if req.URL.RawPath == req.URL.Path {
		req.URL.RawPath = ""
	}
}

// queryOps describes the operations to perform on a query like add, delete and replace fields
type queryOps struct {
	// Adds query parameters; does not replace any existing header fields.
	Add []queryOpsArguments `json:"add,omitempty"`

	// Sets query parameters; replaces existing header fields.
	Set []queryOpsArguments `json:"set,omitempty"`

	// Renames query keys
	Rename []queryOpsArguments `json:"rename,omitempty"`

	// Names of query parameters to delete
	Delete []string `json:"delete,omitempty"`
}

func (q *queryOps) do(r *http.Request, repl *caddy.Replacer) {
	query := r.URL.Query()

	for _, addParam := range q.Add {
		key := repl.ReplaceAll(addParam.Key, "")
		if key == "" {
			continue
		}
		val := repl.ReplaceAll(addParam.Val, "")
		query[key] = append(query[key], val)
	}

	for _, deleteParam := range q.Delete {

Review comment (suggestion):
```suggestion
	// Adds query parameters; does not overwrite an existing query field,
	// and only appends an additional value for that key if any already exist.
```

Code after:
	if rep.Find == "" || rep.re == nil {
		return
	}
	replace := repl.ReplaceAll(rep.Replace, "")
	changePath(r, func(pathOrRawPath string) string {
		return rep.re.ReplaceAllString(pathOrRawPath, replace)
	})
}

func changePath(req *http.Request, newVal func(pathOrRawPath string) string) {
	req.URL.RawPath = newVal(req.URL.EscapedPath())
	if p, err := url.PathUnescape(req.URL.RawPath); err == nil && p != "" {
		req.URL.Path = p
	} else {
		req.URL.Path = newVal(req.URL.Path)
	}
	// RawPath is only set if it's different from the normalized Path (std lib)
	if req.URL.RawPath == req.URL.Path {
		req.URL.RawPath = ""
	}
}

// queryOps describes the operations to perform on query keys: add, set, rename and delete.
type queryOps struct {
	// Renames a query key from Key to Val, without affecting the value.
	Rename []queryOpsArguments `json:"rename,omitempty"`

	// Sets query parameters; overwrites a query key with the given value.
	Set []queryOpsArguments `json:"set,omitempty"`

	// Adds query parameters; does not overwrite an existing query field,
	// and only appends an additional value for that key if any already exist.
	Add []queryOpsArguments `json:"add,omitempty"`

	// Deletes a given query key by name.
	Delete []string `json:"delete,omitempty"`
}

func (q *queryOps) do(r *http.Request, repl *caddy.Replacer) {
	query := r.URL.Query()

	for _, renameParam := range q.Rename {
		key := repl.ReplaceAll(renameParam.Key, "")
		val := repl.ReplaceAll(renameParam.Val, "")
		if key == "" || val == "" {
			continue
		}
		query[val] = query[key]
		delete(query, key)
	}