REFACTOR: Pave args (not validate) (#3045)

This commit is contained in:
Tom Limoncelli 2024-07-09 21:44:38 -04:00 committed by GitHub
parent 0ed31efdc9
commit 95c7a70434
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 83 additions and 90 deletions

View file

@ -152,7 +152,7 @@ type RecordConfig struct {
// When these are used, .target is set to a human-readable version (only to be used for display purposes).
type CloudflareSingleRedirectConfig struct {
//
Code int `json:"code,omitempty"` // 301 or 302
Code uint16 `json:"code,omitempty"` // 301 or 302
// PR == PageRule
PRDisplay string `json:"pr_display,omitempty"` // How is this displayed to the user
PRWhen string `json:"pr_when,omitempty"`

50
pkg/rtypecontrol/pave.go Normal file
View file

@ -0,0 +1,50 @@
package rtypecontrol
import (
"fmt"
"strconv"
)
// PaveArgs converts each arg to its desired type, or returns an error if conversion fails or if the number of arguments is wrong.
// argTypes is a string where each rune specifies the desired type of the arg in the same position:
// 'i': uinet16 (will convert strings, truncate floats, etc)
// 's': Valid only if string.
func PaveArgs(args []any, argTypes string) error {
if len(args) != len(argTypes) {
return fmt.Errorf("wrong number of arguments. Expected %v, got %v", len(argTypes), len(args))
}
for i, at := range argTypes {
arg := args[i]
switch at {
case 'i': // uint16
if s, ok := arg.(string); ok { // Is this a string-encoded int?
ni, err := strconv.Atoi(s)
if err != nil {
return fmt.Errorf("value %q is not a number (uint16 wanted)", arg)
}
args[i] = uint16(ni)
} else if _, ok := arg.(float64); ok {
args[i] = uint16(arg.(float64))
} else if _, ok := arg.(uint16); ok {
args[i] = arg.(uint16)
} else if _, ok := arg.(int); ok {
args[i] = uint16(arg.(int))
} else {
return fmt.Errorf("value %q is type %T, expected uint16", arg, arg)
}
case 's':
if _, ok := arg.(string); ok {
args[i] = arg.(string)
} else {
args[i] = fmt.Sprintf("%v", arg)
}
}
}
return nil
}

View file

@ -2,7 +2,7 @@ package rtypecontrol
import "testing"
func TestValidateArgs(t *testing.T) {
func TestPaveArgs(t *testing.T) {
tests := []struct {
name string
dataArgs []any
@ -19,23 +19,35 @@ func TestValidateArgs(t *testing.T) {
name: "int to string",
dataArgs: []any{100},
dataRule: "s",
wantErr: true,
wantErr: false,
},
{
name: "int",
dataArgs: []any{int(1)},
name: "uint16",
dataArgs: []any{uint16(1)},
dataRule: "i",
wantErr: false,
},
{
name: "string to int",
name: "float to uint16",
dataArgs: []any{float64(2)},
dataRule: "i",
wantErr: false,
},
{
name: "int uint16",
dataArgs: []any{int(3)},
dataRule: "i",
wantErr: false,
},
{
name: "string to uint16",
dataArgs: []any{"111"},
dataRule: "i",
wantErr: false,
},
{
name: "txt to int",
name: "txt to uint16",
dataArgs: []any{"one"},
dataRule: "i",
wantErr: true,
@ -43,8 +55,8 @@ func TestValidateArgs(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := CheckArgTypes(tt.dataArgs, tt.dataRule); (err != nil) != tt.wantErr {
t.Errorf("ValidateArgs() error = %v, wantErr %v", err, tt.wantErr)
if err := PaveArgs(tt.dataArgs, tt.dataRule); (err != nil) != tt.wantErr {
t.Errorf("PaveArgs() error = %v, wantErr %v", err, tt.wantErr)
}
})
}

View file

@ -1,43 +0,0 @@
package rtypecontrol
import (
"fmt"
"strconv"
)
// CheckArgTypes validates that the items in args are of appropriate types. argTypes is a string: "ssi" means the args should be string, string, int.
// 's': Valid only if string.
// 'i': Valid only if int, float64, or a string that Atoi() can convert to an int.
func CheckArgTypes(args []any, argTypes string) error {
if len(args) != len(argTypes) {
return fmt.Errorf("wrong number of arguments. Expected %v, got %v", len(argTypes), len(args))
}
for i, at := range argTypes {
arg := args[i]
switch at {
case 'i':
if s, ok := arg.(string); ok { // Is this a string-encoded int?
ni, err := strconv.Atoi(s)
if err != nil {
return fmt.Errorf("value %q is type %T, expected INT", arg, arg)
}
args[i] = ni
} else if _, ok := arg.(float64); ok {
args[i] = int(arg.(float64))
} else if _, ok := arg.(int); !ok {
return fmt.Errorf("value %q is type %T, expected INT", arg, arg)
}
case 's':
if _, ok := arg.(string); !ok {
return fmt.Errorf("value %q is type %T, expected STRING", arg, arg)
}
}
}
return nil
}

View file

@ -568,7 +568,7 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
if !c.manageRedirects && !c.manageSingleRedirects {
return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records")
}
code := 301
code := uint16(301)
if rec.Type == "CF_TEMP_REDIRECT" {
code = 302
}
@ -844,13 +844,13 @@ func uint16Zero(value interface{}) uint16 {
return 0
}
// intZero converts value to int or returns 0.
func intZero(value interface{}) int {
// intZero converts value to uint16 or returns 0.
func intZero(value interface{}) uint16 {
switch v := value.(type) {
case float64:
return int(v)
return uint16(v)
case int:
return v
return uint16(v)
case nil:
}
return 0

View file

@ -306,7 +306,7 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo
// Extract the valuables from the rule, use it to make the sr:
srWhen := pr.Expression
srThen := pr.ActionParameters.FromValue.TargetURL.Expression
code := int(pr.ActionParameters.FromValue.StatusCode)
code := uint16(pr.ActionParameters.FromValue.StatusCode)
sr := cfsingleredirect.FromAPIData(srWhen, srThen, code)
//sr.SRRRuleList = rulelist
//printer.Printf("DEBUG: DESCRIPTION = %v\n", pr.Description)
@ -475,15 +475,6 @@ func (c *cloudflareProvider) updatePageRule(recordID, domainID string, cfr model
}
func (c *cloudflareProvider) createPageRule(domainID string, cfr models.CloudflareSingleRedirectConfig) error {
//printer.Printf("DEBUG: called createPageRule(%s, %+v)\n", domainID, cfr)
// from to priority code
// parts := strings.Split(target, ",")
// priority, _ := strconv.Atoi(parts[2])
// code, _ := strconv.Atoi(parts[3])
// printer.Printf("DEBUG: pr.PageRule target = %v\n", target)
// printer.Printf("DEBUG: pr.PageRule target = %v\n", parts[0])
// printer.Printf("DEBUG: pr.PageRule url = %v\n", parts[1])
// printer.Printf("DEBUG: pr.PageRule code = %v\n", code)
priority := cfr.PRPriority
code := cfr.Code
prWhen := cfr.PRWhen
@ -570,5 +561,5 @@ type pageRuleConstraint struct {
type pageRuleFwdInfo struct {
URL string `json:"url"`
StatusCode int `json:"status_code"`
StatusCode uint16 `json:"status_code"`
}

View file

@ -2,7 +2,6 @@ package cfsingleredirect
import (
"fmt"
"strconv"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/rtypecontrol"
@ -14,34 +13,18 @@ func init() {
func FromRaw(rc *models.RecordConfig, items []any) error {
var err error
// Validate types.
if err := rtypecontrol.CheckArgTypes(items, "siss"); err != nil {
if err := rtypecontrol.PaveArgs(items, "siss"); err != nil {
return err
}
// Unpack the args:
var name, when, then string
var code int
var code uint16
name = items[0].(string)
ucode := items[1]
switch v := ucode.(type) {
case int:
code = v
case float64:
code = int(v)
case string:
code, err = strconv.Atoi(v)
if err != nil {
return err
}
default:
return fmt.Errorf("code %q unexpected type %T", ucode, v)
}
code = items[1].(uint16)
if code != 301 && code != 302 {
return fmt.Errorf("code (%03d) is not 301 or 302", code)
}

View file

@ -9,7 +9,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models"
)
func FromUserInput(target string, code int, priority int) (*models.CloudflareSingleRedirectConfig, error) {
func FromUserInput(target string, code uint16, priority int) (*models.CloudflareSingleRedirectConfig, error) {
// target: matcher,replacement,priority,code
// target: cable.slackoverflow.com/*,https://change.cnn.com/$1,1,302

View file

@ -6,7 +6,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models"
)
func FromAPIData(sm, sr string, code int) *models.CloudflareSingleRedirectConfig {
func FromAPIData(sm, sr string, code uint16) *models.CloudflareSingleRedirectConfig {
r := &models.CloudflareSingleRedirectConfig{
PRWhen: "UNKNOWABLE",
PRThen: "UNKNOWABLE",