-
Notifications
You must be signed in to change notification settings - Fork 114
fix: reset previously set/removed values in per-backend header mutation #1387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
cc5c32e
19ecccc
31ce3b1
ba27892
04e1496
e0defcf
4d7bf86
b760c6e
5fea734
8daaed6
ccee34b
0fa251b
1e4ca5a
111db0c
1a31278
aae64fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,10 +12,11 @@ import ( | |
extprocv3 "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3" | ||
|
||
"github.com/envoyproxy/ai-gateway/internal/filterapi" | ||
"github.com/envoyproxy/ai-gateway/internal/internalapi" | ||
) | ||
|
||
type HeaderMutator struct { | ||
// getOrignalHeaders Callback to get removed sensitive headers from the router filter. | ||
// getOriginalHeaders Callback to get removed sensitive headers from the router filter. | ||
mathetake marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
originalHeaders map[string]string | ||
|
||
// headerMutations is a list of header mutations to apply. | ||
|
@@ -40,6 +41,9 @@ func (h *HeaderMutator) Mutate(headers map[string]string, onRetry bool) *extproc | |
if !skipRemove { | ||
for _, h := range h.headerMutations.Remove { | ||
key := strings.ToLower(h) | ||
if shouldIgnoreHeader(key) { | ||
continue | ||
} | ||
removedHeadersSet[key] = struct{}{} | ||
if _, ok := headers[key]; ok { | ||
// Do NOT delete from the local headers map so metrics can still read it. | ||
|
@@ -54,6 +58,9 @@ func (h *HeaderMutator) Mutate(headers map[string]string, onRetry bool) *extproc | |
if !skipSet { | ||
for _, h := range h.headerMutations.Set { | ||
key := strings.ToLower(h.Name) | ||
if shouldIgnoreHeader(key) { | ||
continue | ||
} | ||
setHeadersSet[key] = struct{}{} | ||
headers[key] = h.Value | ||
headerMutation.SetHeaders = append(headerMutation.SetHeaders, &corev3.HeaderValueOption{ | ||
|
@@ -62,21 +69,65 @@ func (h *HeaderMutator) Mutate(headers map[string]string, onRetry bool) *extproc | |
} | ||
} | ||
|
||
// Restore original headers on retry, only if not being removed, set or not already present. | ||
if onRetry && h.originalHeaders != nil { | ||
if onRetry { | ||
// Restore original headers on retry, only if not being removed, set or not already present. | ||
for h, v := range h.originalHeaders { | ||
key := strings.ToLower(h) | ||
if shouldIgnoreHeader(key) { | ||
continue | ||
} | ||
_, isRemoved := removedHeadersSet[key] | ||
_, isSet := setHeadersSet[key] | ||
_, exists := headers[key] | ||
if !isRemoved && !exists && !isSet { | ||
headers[h] = v | ||
setHeadersSet[key] = struct{}{} | ||
headerMutation.SetHeaders = append(headerMutation.SetHeaders, &corev3.HeaderValueOption{ | ||
Header: &corev3.HeaderValue{Key: h, RawValue: []byte(v)}, | ||
}) | ||
} | ||
} | ||
// 1. Remove any headers that were added in the previous attempt (not part of original headers and not being set now). | ||
// 2. Restore any original headers that were modified in the previous attempt (and not being set now). | ||
for key := range headers { | ||
key = strings.ToLower(key) | ||
|
||
if shouldIgnoreHeader(key) { | ||
continue | ||
} | ||
if _, set := setHeadersSet[key]; set { | ||
mathetake marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
continue | ||
} | ||
originalValue, exists := h.originalHeaders[key] | ||
if !exists { | ||
delete(headers, key) | ||
headerMutation.RemoveHeaders = append(headerMutation.RemoveHeaders, key) | ||
} else { | ||
// Restore original value. | ||
headers[key] = originalValue | ||
headerMutation.SetHeaders = append(headerMutation.SetHeaders, &corev3.HeaderValueOption{ | ||
Header: &corev3.HeaderValue{Key: key, RawValue: []byte(originalValue)}, | ||
mathetake marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}) | ||
} | ||
} | ||
} | ||
|
||
return headerMutation | ||
} | ||
|
||
// shouldIgnoreHeader returns true if the header key should be ignored for mutation. | ||
// | ||
// Skip Envoy AI Gateway headers since some of them are populated after the originalHeaders are captured. | ||
// This should be safe since these headers are managed by Envoy AI Gateway itself, not expected to be | ||
// modified by users via header mutation API. | ||
// | ||
// Also, skip Envoy pseudo-headers beginning with ':'. | ||
mathetake marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
func shouldIgnoreHeader(key string) bool { | ||
// Ignore Envoy pseudo-headers beginning with ':'. | ||
if strings.HasPrefix(key, ":") { | ||
return true | ||
} | ||
// Ignore internal headers beginning with Envoy AI Gateway prefix. | ||
if strings.HasPrefix(key, internalapi.EnvoyAIGatewayHeaderPrefix) { | ||
mathetake marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
return true | ||
} | ||
return false | ||
} | ||
mathetake marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this simply re-tests the headermutator internal so it's overlapping with the tests there, hence removed it.