From fcdc2c54f9afe76a7fbd8af0981c76895bfcf68a Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 00:19:10 +0000 Subject: [PATCH] feat(dns): accept case-insensitive action arguments Co-Authored-By: Virgil --- action.go | 85 ++++++++++++++++++++++++++++++++----------------- service_test.go | 28 ++++++++++++++++ 2 files changed, 83 insertions(+), 30 deletions(-) diff --git a/action.go b/action.go index 6d50d22..4ef3f78 100644 --- a/action.go +++ b/action.go @@ -357,26 +357,44 @@ func stringActionValue(values map[string]any, key string) (string, error) { return "", errActionMissingValue } -func stringActionValueFromKeys(values map[string]any, keys ...string) (string, error) { - for _, key := range keys { - value, exists := values[key] - if !exists { - continue - } - - text, ok := value.(string) - if !ok { - return "", fmt.Errorf("%w: %s", errActionMissingValue, key) - } - - text = strings.TrimSpace(text) - if text == "" { - return "", errActionMissingValue - } - return text, nil +func lookupActionValue(values map[string]any, keys ...string) (any, string, bool) { + if values == nil { + return nil, "", false } - return "", errActionMissingValue + for _, key := range keys { + if value, exists := values[key]; exists { + return value, key, true + } + } + + for _, key := range keys { + for alias, value := range values { + if strings.EqualFold(alias, key) { + return value, alias, true + } + } + } + + return nil, "", false +} + +func stringActionValueFromKeys(values map[string]any, keys ...string) (string, error) { + value, key, found := lookupActionValue(values, keys...) + if !found { + return "", errActionMissingValue + } + text, ok := value.(string) + if !ok { + return "", fmt.Errorf("%w: %s", errActionMissingValue, key) + } + + text = strings.TrimSpace(text) + if text == "" { + return "", errActionMissingValue + } + + return text, nil } func stringActionValueOptional(values map[string]any, key string) (string, error) { @@ -395,18 +413,15 @@ func stringActionValueOptional(values map[string]any, key string) (string, error } func stringActionValueOptionalFromKeys(values map[string]any, keys ...string) (string, bool, error) { - for _, key := range keys { - raw, exists := values[key] - if !exists { - continue - } - value, ok := raw.(string) - if !ok { - return "", false, fmt.Errorf("%w: %s", errActionMissingValue, key) - } - return strings.TrimSpace(value), true, nil + value, key, found := lookupActionValue(values, keys...) + if !found { + return "", false, nil } - return "", false, nil + text, ok := value.(string) + if !ok { + return "", false, fmt.Errorf("%w: %s", errActionMissingValue, key) + } + return strings.TrimSpace(text), true, nil } func intActionValue(values map[string]any, key string) (int, error) { @@ -506,5 +521,15 @@ func intActionValueOptionalFromKeys(values map[string]any, keys ...string) (int, return value, true, nil } } - return 0, false, nil + + value, key, found := lookupActionValue(values, keys...) + if !found { + return 0, false, nil + } + intValue, err := intActionValue(map[string]any{key: value}, key) + if err != nil { + return 0, false, err + } + + return intValue, true, nil } diff --git a/service_test.go b/service_test.go index fdfa676..0593129 100644 --- a/service_test.go +++ b/service_test.go @@ -2692,6 +2692,34 @@ func TestServiceHandleActionServeDefaultsPortFromServiceConfiguration(t *testing _ = dnsServer.Close() } +func TestServiceHandleActionResolveAcceptsCaseInsensitiveNameArgument(t *testing.T) { + service := NewService(ServiceOptions{ + Records: map[string]NameRecords{ + "gateway.charon.lthn": { + A: []string{"10.10.10.10"}, + }, + }, + }) + + payload, ok, err := service.HandleAction(ActionResolve, map[string]any{ + "Name": "gateway.charon.lthn", + }) + if err != nil { + t.Fatalf("expected resolve action with case-insensitive key to succeed: %v", err) + } + if !ok { + t.Fatal("expected resolve action with case-insensitive key to succeed") + } + + result, ok := payload.(ResolveAddressResult) + if !ok { + t.Fatalf("expected ResolveAddressResult payload, got %T", payload) + } + if len(result.Addresses) != 1 || result.Addresses[0] != "10.10.10.10" { + t.Fatalf("unexpected resolve result from case-insensitive payload: %#v", result) + } +} + func TestServiceHandleActionServeHealthPortStartsRuntime(t *testing.T) { desiredHealthPort := pickFreeTCPPort(t) service := NewService(ServiceOptions{