Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/guide/ingress/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,15 @@ Custom attributes to LoadBalancers and TargetGroups can be controlled with follo
```
alb.ingress.kubernetes.io/listener-attributes.HTTP-80: routing.http.response.server.enabled=true
```
- Add Access-Control-Allow-Headers header value (with comma)
```
alb.ingress.kubernetes.io/listener-attributes.HTTPS-443: "routing.http.response.access_control_allow_headers.header_value=exampleValue\\,anotherExampleValue"
```
or
```
alb.ingress.kubernetes.io/listener-attributes.HTTPS-443: routing.http.response.access_control_allow_headers.header_value=exampleValue\,anotherExampleValue
```
both result Access-Control-Allow-Headers header value: exampleValue,anotherExampleValue
## Resource Tags
Expand Down
47 changes: 43 additions & 4 deletions pkg/annotations/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package annotations
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"strconv"
"strings"

"github.com/pkg/errors"
)

type ParseOptions struct {
Expand Down Expand Up @@ -151,15 +152,15 @@ func (p *suffixAnnotationParser) ParseStringMapAnnotation(annotation string, val
if !exists {
return false, nil
}
rawKVPairs := splitCommaSeparatedString(raw)
rawKVPairs := splitKeyValuePairs(raw)
keyValues := make(map[string]string)
for _, kvPair := range rawKVPairs {
parts := strings.SplitN(kvPair, "=", 2)
if len(parts) != 2 {
return false, errors.Errorf("failed to parse stringMap annotation, %v: %v", matchedKey, raw)
}
key := parts[0]
value := parts[1]
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
if len(key) == 0 {
return false, errors.Errorf("failed to parse stringMap annotation, %v: %v", matchedKey, raw)
}
Expand Down Expand Up @@ -212,3 +213,41 @@ func splitCommaSeparatedString(commaSeparatedString string) []string {
}
return result
}

// splitKeyValuePairs this function supports escaped comma
func splitKeyValuePairs(s string) []string {
var result []string
var currentString strings.Builder

for i := 0; i < len(s); i++ {
if s[i] == '\\' && i+1 < len(s) {
// Escape sequence - add the escaped character literally
currentString.WriteByte(s[i+1])
i++ // skip the escaped character
} else if s[i] == ',' {
// Check if next part contains '=' (a new key-value pair)
remaining := strings.TrimSpace(s[i+1:])
containsEqual := strings.Index(remaining, "=")
if containsEqual != -1 {
result = append(result, strings.TrimSpace(currentString.String()))
currentString.Reset()
} else if len(remaining) > 0 {
// There's content after comma but no '=' - this is malformed
// Add current content and the malformed part as separate items
result = append(result, strings.TrimSpace(currentString.String()))
result = append(result, remaining)
return result
} else {
// Empty after comma, add comma to current
currentString.WriteByte(s[i])
}
} else {
currentString.WriteByte(s[i])
}
}

if currentString.Len() > 0 {
result = append(result, strings.TrimSpace(currentString.String()))
}
return result
}
19 changes: 18 additions & 1 deletion pkg/annotations/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package annotations

import (
"errors"
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_annotationParser_ParseStringAnnotation(t *testing.T) {
Expand Down Expand Up @@ -278,6 +279,22 @@ func Test_serviceAnnotationParser_ParseStringMapAnnotation(t *testing.T) {
"key4/empty-value": "",
},
},
{
name: "multiple values",
prefix: "p.co",
suffix: "sfx",
annotations: map[string]string{
"first-value": "1",
"p.co/sfx": "key1=value1\\,valueOne, key2= value2, key3/with-slash=value3\\,valueThree, key4/empty-value=",
},
wantExist: true,
wantValue: map[string]string{
"key1": "value1,valueOne",
"key2": "value2",
"key3/with-slash": "value3,valueThree",
"key4/empty-value": "",
},
},
{
name: "values containing equals sign",
prefix: "prefix",
Expand Down
Loading