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

Code before:

func applyQueryOps(h httpcaddyfile.Helper, qo *queryOps, args []string) error {
	key := args[0]
	switch {
	case strings.HasPrefix(key, "-"):
		if len(args) != 1 {
			return h.ArgErr()
		}
		qo.Delete = append(qo.Delete, strings.TrimLeft(key, "-"))

	case strings.HasPrefix(key, "+"):
		if len(args) != 2 {
			return h.ArgErr()
		}
		param := strings.TrimLeft(key, "+")
		qo.Add = append(qo.Add, queryOpsArguments{Key: param, Val: args[1]})

	case strings.Contains(key, ">"):
		if len(args) != 1 {
			return h.ArgErr()
		}
		renameValKey := strings.Split(key, ">")
		qo.Rename = append(qo.Rename, queryOpsArguments{Key: renameValKey[0], Val: renameValKey[1]})

	case len(args) == 3:
		qo.Replace = append(qo.Replace, queryOpsReplacement{Key: key, Search: args[1], Replace: args[2]})

	default:
		if len(args) != 2 {
			return h.ArgErr()
		}
		qo.Set = append(qo.Set, queryOpsArguments{Key: key, Val: args[1]})
	}
	return nil
}

// parseCaddyfileHandlePath parses the handle_path directive. Syntax:
//
//	handle_path [<matcher>] {
//	    <directives...>
//	}
//
// Only path matchers (with a `/` prefix) are supported as this is a shortcut
// for the handle directive with a strip_prefix rewrite.
func parseCaddyfileHandlePath(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
	h.Next() // consume directive name

	// there must be a path matcher
	if !h.NextArg() {
		return nil, h.ArgErr()
	}

Review comment (suggestion):
I don't remember how we did it for header replacement, did we have `SearchRegexp` support from Caddyfile? If not, I think what we should do is allow `~` as a prefix to the search string, and if so it becomes a regexp. That's the way we did it for the `map` directive: https://caddyserver.com/docs/caddyfile/directives/map#syntax. Maybe we can apply that to the header replacements Caddyfile parsing too.

Code after:

func applyQueryOps(h httpcaddyfile.Helper, qo *queryOps, args []string) error {
	key := args[0]
	switch {
	case strings.HasPrefix(key, "-"):
		if len(args) != 1 {
			return h.ArgErr()
		}
		qo.Delete = append(qo.Delete, strings.TrimLeft(key, "-"))

	case strings.HasPrefix(key, "+"):
		if len(args) != 2 {
			return h.ArgErr()
		}
		param := strings.TrimLeft(key, "+")
		qo.Add = append(qo.Add, queryOpsArguments{Key: param, Val: args[1]})

	case strings.Contains(key, ">"):
		if len(args) != 1 {
			return h.ArgErr()
		}
		renameValKey := strings.Split(key, ">")
		qo.Rename = append(qo.Rename, queryOpsArguments{Key: renameValKey[0], Val: renameValKey[1]})

	case len(args) == 3:
		qo.Replace = append(qo.Replace, &queryOpsReplacement{Key: key, SearchRegexp: args[1], Replace: args[2]})

	default:
		if len(args) != 2 {
			return h.ArgErr()
		}
		qo.Set = append(qo.Set, queryOpsArguments{Key: key, Val: args[1]})
	}
	return nil
}

// parseCaddyfileHandlePath parses the handle_path directive. Syntax:
//
//	handle_path [<matcher>] {
//	    <directives...>
//	}
//
// Only path matchers (with a `/` prefix) are supported as this is a shortcut
// for the handle directive with a strip_prefix rewrite.
func parseCaddyfileHandlePath(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
	h.Next() // consume directive name

	// there must be a path matcher
	if !h.NextArg() {
		return nil, h.ArgErr()
	}