ronantakizawa/codereview-bench huggingface dataset:
Repository: caddyserver/caddy
File: modules/caddyhttp/reverseproxy/httptransport.go (Go)

Code before:
			if err != nil {
				return nil, fmt.Errorf("parsing CA certificate: %v", err)
			}
			rootPool.AddCert(caCert)
		}
		for _, pemFile := range t.RootCAPEMFiles {
			pemData, err := os.ReadFile(pemFile)
			if err != nil {
				return nil, fmt.Errorf("failed reading ca cert: %v", err)
			}
			rootPool.AppendCertsFromPEM(pemData)
		}
		cfg.RootCAs = rootPool
	}

	if t.CARaw != nil {
		if len(t.RootCAPool) > 0 || len(t.RootCAPEMFiles) > 0 {
			return nil, fmt.Errorf("Conflicting config for Root CA pool")
		}
		caRaw, err := ctx.LoadModule(t, "CARaw")
		if err != nil {
			return nil, fmt.Errorf("failed to load ca module: %v", err)
		}
		ca, ok := caRaw.(caddytls.CA)
		if !ok {
			return nil, fmt.Errorf("CARaw module '%s' is not a certificate pool provider", ca)
		}
		cfg.RootCAs = ca.CertPool()
	}

	// Renegotiation
	switch t.Renegotiation {
	case "never", "":
		cfg.Renegotiation = tls.RenegotiateNever
	case "once":
		cfg.Renegotiation = tls.RenegotiateOnceAsClient
	case "freely":
		cfg.Renegotiation = tls.RenegotiateFreelyAsClient
	default:
		return nil, fmt.Errorf("invalid TLS renegotiation level: %v", t.Renegotiation)
	}

	// override for the server name used verify the TLS handshake
	cfg.ServerName = t.ServerName

	// throw all security out the window
	cfg.InsecureSkipVerify = t.InsecureSkipVerify

	curvesAdded := make(map[tls.CurveID]struct{})
	for _, curveName := range t.Curves {
		curveID := caddytls.SupportedCurves[curveName]

Review comment (suggestion):
Use `'ca'` instead of `CARaw` because the user does not know the field name inside the struct.

Code after:
		rootPool := x509.NewCertPool()
		for _, encodedCACert := range t.RootCAPool {
			caCert, err := decodeBase64DERCert(encodedCACert)
			if err != nil {
				return nil, fmt.Errorf("parsing CA certificate: %v", err)
			}
			rootPool.AddCert(caCert)
		}
		for _, pemFile := range t.RootCAPEMFiles {
			pemData, err := os.ReadFile(pemFile)
			if err != nil {
				return nil, fmt.Errorf("failed reading ca cert: %v", err)
			}
			rootPool.AppendCertsFromPEM(pemData)
		}
		cfg.RootCAs = rootPool
	}

	if t.CARaw != nil {
		if len(t.RootCAPool) > 0 || len(t.RootCAPEMFiles) > 0 {
			return nil, fmt.Errorf("conflicting config for Root CA pool")
		}
		caRaw, err := ctx.LoadModule(t, "CARaw")
		if err != nil {
			return nil, fmt.Errorf("failed to load ca module: %v", err)
		}
		ca, ok := caRaw.(caddytls.CA)
		if !ok {
			return nil, fmt.Errorf("CA module '%s' is not a certificate pool provider", ca)
		}
		cfg.RootCAs = ca.CertPool()
	}

	// Renegotiation
	switch t.Renegotiation {
	case "never", "":
		cfg.Renegotiation = tls.RenegotiateNever
	case "once":
		cfg.Renegotiation = tls.RenegotiateOnceAsClient
	case "freely":
		cfg.Renegotiation = tls.RenegotiateFreelyAsClient
	default:
		return nil, fmt.Errorf("invalid TLS renegotiation level: %v", t.Renegotiation)
	}

	// override for the server name used verify the TLS handshake
	cfg.ServerName = t.ServerName

	// throw all security out the window
	cfg.InsecureSkipVerify = t.InsecureSkipVerify
Repository: caddyserver/caddy
File: modules/caddyhttp/reverseproxy/caddyfile.go (Go)

Code before:
			h.MaxConnsPerHost = num

		case "tls_trust_pool":
			if !d.NextArg() {
				return d.ArgErr()
			}
			modStem := d.Val()
			modID := "tls.ca_pool.source." + modStem
			unm, err := caddyfile.UnmarshalModule(d, modID)
			if err != nil {
				return err
			}
			ca, ok := unm.(caddytls.CA)
			if !ok {
				return d.Errf("module %s is not a caddytls.CA", modID)
			}
			if h.TLS == nil {
				h.TLS = new(TLSConfig)
			}
			if len(h.TLS.RootCAPEMFiles) != 0 {
				return d.Err("cannot specify both 'tls_trust_pool' and 'tls_trusted_ca_certs'")
			}
			h.TLS.CARaw = caddyconfig.JSONModuleObject(ca, "provider", modStem, nil)

		default:
			return d.Errf("unrecognized subdirective %s", d.Val())
		}
	}
	return nil
}

func parseCopyResponseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
	crh := new(CopyResponseHandler)
	err := crh.UnmarshalCaddyfile(h.Dispenser)
	if err != nil {
		return nil, err
	}
	return crh, nil
}

// UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
//
//	copy_response [<matcher>] [<status>] {
//	    status <status>
//	}
func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume directive name

	args := d.RemainingArgs()
	if len(args) == 1 {
		if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {

Review comment (suggestion):
I think we should return an error if `h.TLS.CARaw` is not nil because it means they've specified it twice.

Code after:
			h.MaxConnsPerHost = num

		case "tls_trust_pool":
			if !d.NextArg() {
				return d.ArgErr()
			}
			modStem := d.Val()
			modID := "tls.ca_pool.source." + modStem
			unm, err := caddyfile.UnmarshalModule(d, modID)
			if err != nil {
				return err
			}
			ca, ok := unm.(caddytls.CA)
			if !ok {
				return d.Errf("module %s is not a caddytls.CA", modID)
			}
			if h.TLS == nil {
				h.TLS = new(TLSConfig)
			}
			if len(h.TLS.RootCAPEMFiles) != 0 {
				return d.Err("cannot specify both 'tls_trust_pool' and 'tls_trusted_ca_certs'")
			}
			if h.TLS.CARaw != nil {
				return d.Err("cannot specify \"tls_trust_pool\" twice in caddyfile")
			}
			h.TLS.CARaw = caddyconfig.JSONModuleObject(ca, "provider", modStem, nil)

		default:
			return d.Errf("unrecognized subdirective %s", d.Val())
		}
	}
	return nil
}

func parseCopyResponseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
	crh := new(CopyResponseHandler)
	err := crh.UnmarshalCaddyfile(h.Dispenser)
	if err != nil {
		return nil, err
	}
	return crh, nil
}

// UnmarshalCaddyfile sets up the handler from Caddyfile tokens. Syntax:
//
//	copy_response [<matcher>] [<status>] {
//	    status <status>
//	}
func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume directive name
Repository: caddyserver/caddy
File: caddyconfig/httpcaddyfile/builtins.go (Go)

Code before:
			if h.NextArg() {
				return nil, h.ArgErr()
			}

		case "include":
			if !parseAsGlobalOption {
				return nil, h.Err("include is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Include = append(cl.Include, h.Val())
			}

		case "exclude":
			if !parseAsGlobalOption {
				return nil, h.Err("exclude is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Exclude = append(cl.Exclude, h.Val())
			}
		case "no_hostname":
			noLoggerNames = true

		default:
			return nil, h.Errf("unrecognized subdirective: %s", h.Val())
		}
	}

	var val namedCustomLog
	val.hostnames = customHostnames
	val.noLoggerNames = noLoggerNames
	isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))

	// Skip handling of empty logging configs

	if parseAsGlobalOption {
		// Use indicated name for global log options
		val.name = logName
	} else {
		if logName != "" {
			val.name = logName
		} else if !isEmptyConfig {
			// Construct a log name for server log streams
			logCounter, ok := h.State["logCounter"].(int)
			if !ok {
				logCounter = 0
			}
			val.name = fmt.Sprintf("log%d", logCounter)
			logCounter++
			h.State["logCounter"] = logCounter
		}
		if val.name != "" {

Review comment (suggestion):
Newline before the case to separate it visually

```suggestion

		case "no_hostname":
```

Code after:
		case "level":
			if !h.NextArg() {
				return nil, h.ArgErr()
			}
			cl.Level = h.Val()
			if h.NextArg() {
				return nil, h.ArgErr()
			}

		case "include":
			if !parseAsGlobalOption {
				return nil, h.Err("include is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Include = append(cl.Include, h.Val())
			}

		case "exclude":
			if !parseAsGlobalOption {
				return nil, h.Err("exclude is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Exclude = append(cl.Exclude, h.Val())
			}

		case "no_hostname":
			if h.NextArg() {
				return nil, h.ArgErr()
			}
			noHostname = true

		default:
			return nil, h.Errf("unrecognized subdirective: %s", h.Val())
		}
	}

	var val namedCustomLog
	val.hostnames = customHostnames
	val.noHostname = noHostname
	isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))

	// Skip handling of empty logging configs

	if parseAsGlobalOption {
		// Use indicated name for global log options
		val.name = logName
	} else {
		if logName != "" {
			val.name = logName
		} else if !isEmptyConfig {
			// Construct a log name for server log streams
Repository: caddyserver/caddy
File: caddyconfig/httpcaddyfile/builtins.go (Go)

Code before:
		case "include":
			if !parseAsGlobalOption {
				return nil, h.Err("include is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Include = append(cl.Include, h.Val())
			}

		case "exclude":
			if !parseAsGlobalOption {
				return nil, h.Err("exclude is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Exclude = append(cl.Exclude, h.Val())
			}
		case "no_hostname":
			noLoggerNames = true

		default:
			return nil, h.Errf("unrecognized subdirective: %s", h.Val())
		}
	}

	var val namedCustomLog
	val.hostnames = customHostnames
	val.noLoggerNames = noLoggerNames
	isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))

	// Skip handling of empty logging configs

	if parseAsGlobalOption {
		// Use indicated name for global log options
		val.name = logName
	} else {
		if logName != "" {
			val.name = logName
		} else if !isEmptyConfig {
			// Construct a log name for server log streams
			logCounter, ok := h.State["logCounter"].(int)
			if !ok {
				logCounter = 0
			}
			val.name = fmt.Sprintf("log%d", logCounter)
			logCounter++
			h.State["logCounter"] = logCounter
		}
		if val.name != "" {
			cl.Include = []string{"http.log.access." + val.name}
		}
	}
	if !isEmptyConfig {

Review comment (suggestion):
Throw an error if an arg is specified

```suggestion
			if h.NextArg() {
				return nil, h.ArgErr()
			}
			noLoggerNames = true
```

Code after:
			cl.Level = h.Val()
			if h.NextArg() {
				return nil, h.ArgErr()
			}

		case "include":
			if !parseAsGlobalOption {
				return nil, h.Err("include is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Include = append(cl.Include, h.Val())
			}

		case "exclude":
			if !parseAsGlobalOption {
				return nil, h.Err("exclude is not allowed in the log directive")
			}
			for h.NextArg() {
				cl.Exclude = append(cl.Exclude, h.Val())
			}

		case "no_hostname":
			if h.NextArg() {
				return nil, h.ArgErr()
			}
			noHostname = true

		default:
			return nil, h.Errf("unrecognized subdirective: %s", h.Val())
		}
	}

	var val namedCustomLog
	val.hostnames = customHostnames
	val.noHostname = noHostname
	isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))

	// Skip handling of empty logging configs

	if parseAsGlobalOption {
		// Use indicated name for global log options
		val.name = logName
	} else {
		if logName != "" {
			val.name = logName
		} else if !isEmptyConfig {
			// Construct a log name for server log streams
			logCounter, ok := h.State["logCounter"].(int)
			if !ok {
				logCounter = 0
			}
Repository: caddyserver/caddy
File: caddyconfig/httpcaddyfile/builtins.go (Go)

Code before:
}

// parseLogSkip parses the log_skip directive. Syntax:
//
//	log_skip [<matcher>]
func parseLogSkip(h Helper) (caddyhttp.MiddlewareHandler, error) {
	h.Next() // consume directive name

	// "skip_log" is deprecated, replaced by "log_skip"
	if h.Val() == "skip_log" {
		caddy.Log().Named("config.adapter.caddyfile").Warn("the 'skip_log' directive is deprecated, please use 'log_skip' instead!")
	}

	if h.NextArg() {
		return nil, h.ArgErr()
	}
	return caddyhttp.VarsMiddleware{"log_skip": true}, nil
}

// parseLogName parses the log_name directive. Syntax:
//
// log_name <names...>
func parseLogName(h Helper) (caddyhttp.MiddlewareHandler, error) {
	h.Next()
	access_logger_names := h.RemainingArgs()
	return caddyhttp.VarsMiddleware{"access_logger_names": access_logger_names}, nil
}


Review comment (suggestion):
I think this should use the `AccessLoggerNameVarKey` const here

Code after:
}

// parseLogSkip parses the log_skip directive. Syntax:
//
//	log_skip [<matcher>]
func parseLogSkip(h Helper) (caddyhttp.MiddlewareHandler, error) {
	h.Next() // consume directive name

	// "skip_log" is deprecated, replaced by "log_skip"
	if h.Val() == "skip_log" {
		caddy.Log().Named("config.adapter.caddyfile").Warn("the 'skip_log' directive is deprecated, please use 'log_skip' instead!")
	}

	if h.NextArg() {
		return nil, h.ArgErr()
	}
	return caddyhttp.VarsMiddleware{"log_skip": true}, nil
}

// parseLogName parses the log_name directive. Syntax:
//
//	log_name <names...>
func parseLogName(h Helper) (caddyhttp.MiddlewareHandler, error) {
	h.Next() // consume directive name
	return caddyhttp.VarsMiddleware{
		caddyhttp.AccessLoggerNameVarKey: h.RemainingArgs(),
	}, nil
}
Repository: caddyserver/caddy
File: caddyconfig/caddyfile/parse.go (Go)

Code before:
		if err != nil {
			return err
		}
		// Just as we need to track which file the token comes from, we need to
		// keep track of which snippet the token comes from. This is helpful
		// in tracking import cycles across files/snippets by namespacing them.
		// Without this, we end up with false-positives in cycle-detection.
		for k, v := range tokens {
			v.snippetName = name
			tokens[k] = v
		}
		p.definedSnippets[name] = tokens
		// empty block keys so we don't save this block as a real server.
		p.block.Keys = nil
		return nil
	}

	return p.blockContents()
}

func (p *parser) addresses() error {
	var expectingAnother bool

	for {
		tkn := p.Val()
		token := p.Token()
		// special case: import directive replaces tokens during parse-time
		if tkn == "import" && p.isNewLine() {
			err := p.doImport(0)
			if err != nil {
				return err
			}
			continue
		}

		// Open brace definitely indicates end of addresses
		if tkn == "{" {
			if expectingAnother {
				return p.Errf("Expected another address but had '%s' - check for extra comma", tkn)
			}
			// Mark this server block as being defined with braces.
			// This is used to provide a better error message when
			// the user may have tried to define two server blocks
			// without having used braces, which are required in
			// that case.
			p.block.HasBraces = true
			break
		}

		// Users commonly forget to place a space between the address and the '{'
		if strings.HasSuffix(tkn, "{") {

Review comment (suggestion):
I think we should rename `tkn` to "value" or something, just to differentiate it from `token`. Kinda confusing that they have different types with essentially the same name.

Code after:
		if err != nil {
			return err
		}
		// Just as we need to track which file the token comes from, we need to
		// keep track of which snippet the token comes from. This is helpful
		// in tracking import cycles across files/snippets by namespacing them.
		// Without this, we end up with false-positives in cycle-detection.
		for k, v := range tokens {
			v.snippetName = name
			tokens[k] = v
		}
		p.definedSnippets[name] = tokens
		// empty block keys so we don't save this block as a real server.
		p.block.Keys = nil
		return nil
	}

	return p.blockContents()
}

func (p *parser) addresses() error {
	var expectingAnother bool

	for {
		value := p.Val()
		token := p.Token()

		// special case: import directive replaces tokens during parse-time
		if value == "import" && p.isNewLine() {
			err := p.doImport(0)
			if err != nil {
				return err
			}
			continue
		}

		// Open brace definitely indicates end of addresses
		if value == "{" {
			if expectingAnother {
				return p.Errf("Expected another address but had '%s' - check for extra comma", value)
			}
			// Mark this server block as being defined with braces.
			// This is used to provide a better error message when
			// the user may have tried to define two server blocks
			// without having used braces, which are required in
			// that case.
			p.block.HasBraces = true
			break
		}

		// Users commonly forget to place a space between the address and the '{'
Repository: caddyserver/caddy
File: caddyconfig/caddyfile/parse.go (Go)

Code before:
	return blocks, nil
}

func (p *parser) parseOne() error {
	p.block = ServerBlock{}
	return p.begin()
}

func (p *parser) begin() error {
	if len(p.tokens) == 0 {
		return nil
	}

	err := p.addresses()
	if err != nil {
		return err
	}

	if p.eof {
		// this happens if the Caddyfile consists of only
		// a line of addresses and nothing else
		return nil
	}

	if ok, name := p.isNamedRoute(); ok {
		// named routes only have one key, the route name
		p.block.IsNamedRoute = true

		// we just need a dummy leading token to ease parsing later
		nameToken := p.Token()
		nameToken.Text = name
		p.block.Keys = []Token{nameToken}
		// get all the tokens from the block, including the braces
		tokens, err := p.blockTokens(true)
		if err != nil {
			return err
		}
		tokens = append([]Token{nameToken}, tokens...)
		p.block.Segments = []Segment{tokens}
		return nil
	}

	if ok, name := p.isSnippet(); ok {
		if p.definedSnippets == nil {
			p.definedSnippets = map[string][]Token{}
		}
		if _, found := p.definedSnippets[name]; found {
			return p.Errf("redeclaration of previously declared snippet %s", name)
		}
		// consume all tokens til matched close brace
		tokens, err := p.blockTokens(false)

Review comment (suggestion):
This comment is confusing now because it's not attached to the correct line. I suggest moving the `nameToken` stuff here up above this comment, and then put the `.Keys` line just below this comment like it was before.

Code after:
	return blocks, nil
}

func (p *parser) parseOne() error {
	p.block = ServerBlock{}
	return p.begin()
}

func (p *parser) begin() error {
	if len(p.tokens) == 0 {
		return nil
	}

	err := p.addresses()
	if err != nil {
		return err
	}

	if p.eof {
		// this happens if the Caddyfile consists of only
		// a line of addresses and nothing else
		return nil
	}

	if ok, name := p.isNamedRoute(); ok {
		// we just need a dummy leading token to ease parsing later
		nameToken := p.Token()
		nameToken.Text = name

		// named routes only have one key, the route name
		p.block.Keys = []Token{nameToken}
		p.block.IsNamedRoute = true

		// get all the tokens from the block, including the braces
		tokens, err := p.blockTokens(true)
		if err != nil {
			return err
		}
		tokens = append([]Token{nameToken}, tokens...)
		p.block.Segments = []Segment{tokens}
		return nil
	}

	if ok, name := p.isSnippet(); ok {
		if p.definedSnippets == nil {
			p.definedSnippets = map[string][]Token{}
		}
		if _, found := p.definedSnippets[name]; found {
			return p.Errf("redeclaration of previously declared snippet %s", name)
		}
		// consume all tokens til matched close brace
Repository: caddyserver/caddy
File: modules/caddyhttp/rewrite/rewrite.go (Go)

Code before:

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

	for _, deleteParam := range q.Delete {
		param := repl.ReplaceAll(deleteParam, "")
		delete(query, param)
	}

	for _, setParam := range q.Set {
		key := repl.ReplaceAll(setParam.Key, "")
		val := repl.ReplaceAll(setParam.Val, "")
		query[key] = []string{val}
	}

	r.URL.RawQuery = query.Encode()
}

type queryOpsArguments struct {
	Key string `json:"key,omitempty"`
	Val string `json:"val,omitempty"`
}

// Interface guard
var _ caddyhttp.MiddlewareHandler = (*Rewrite)(nil)


Review comment (suggestion):
I think maybe if the key is empty it should do nothing. I don't think it's valid to have an empty query key? Need to check the HTTP spec to make sure but I'm pretty sure it's invalid.

I think it might also be invalid to have `=` in the key, but maybe Go encodes that? Can cover with a test.

Code after:
}

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)
	}

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

	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 {
		param := repl.ReplaceAll(deleteParam, "")
		if param == "" {
			continue
		}
		delete(query, param)
	}

	r.URL.RawQuery = query.Encode()
}

type queryOpsArguments struct {
	// A key in the query string. Note that query string keys may appear multiple times.
	Key string `json:"key,omitempty"`

	// The value for the given operation; for add and set, this is
	// simply the value of the query, and for rename this is the
	// query key to rename to.
Repository: caddyserver/caddy
File: modules/caddyhttp/rewrite/rewrite.go (Go)

Code before:
	for _, setParam := range q.Set {
		key := repl.ReplaceAll(setParam.Key, "")
		if key == "" {
			continue
		}
		val := repl.ReplaceAll(setParam.Val, "")
		query[key] = []string{val}
	}

	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)
	}

	r.URL.RawQuery = query.Encode()
}

type queryOpsArguments struct {
	Key string `json:"key,omitempty"`
	Val string `json:"val,omitempty"`
}

// Interface guard
var _ caddyhttp.MiddlewareHandler = (*Rewrite)(nil)


Review comment (suggestion):
```suggestion
	// A key in the query string. Note that query string keys may appear multiple times.
	Key string `json:"key,omitempty"`
```

Code after:
		query[key] = []string{val}
	}

	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 {
		param := repl.ReplaceAll(deleteParam, "")
		if param == "" {
			continue
		}
		delete(query, param)
	}

	r.URL.RawQuery = query.Encode()
}

type queryOpsArguments struct {
	// A key in the query string. Note that query string keys may appear multiple times.
	Key string `json:"key,omitempty"`

	// The value for the given operation; for add and set, this is
	// simply the value of the query, and for rename this is the
	// query key to rename to.
	Val string `json:"val,omitempty"`
}

// Interface guard
var _ caddyhttp.MiddlewareHandler = (*Rewrite)(nil)