mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
REFACTOR: Pave args (not validate) (#3045)
This commit is contained in:
parent
0ed31efdc9
commit
95c7a70434
|
@ -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
50
pkg/rtypecontrol/pave.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue