validators: add ValidatorHostPort

This commit is contained in:
Yousong Zhou
2020-01-10 21:33:12 +08:00
parent 0c00b3ac98
commit b41d2f7248
2 changed files with 211 additions and 0 deletions
+71
View File
@@ -26,6 +26,7 @@ import (
"net"
"reflect"
"regexp"
"strconv"
"strings"
"yunion.io/x/jsonutils"
@@ -642,6 +643,76 @@ func NewDomainNameValidator(key string) *ValidatorDomainName {
return v
}
type ValidatorHostPort struct {
ValidatorRegexp
optionalPort bool
Domain string
Port int
Value string
}
var regHostPort *regexp.Regexp
func init() {
// guard against surprise
exp := regutils.DOMAINNAME_REG.String()
if exp != "" && exp[len(exp)-1] == '$' {
exp = exp[:len(exp)-1]
}
exp += "(?::[0-9]{1,5})?"
regHostPort = regexp.MustCompile(exp)
}
func NewHostPortValidator(key string) *ValidatorHostPort {
v := &ValidatorHostPort{
ValidatorRegexp: *NewRegexpValidator(key, regHostPort),
}
v.SetParent(v)
return v
}
func (v *ValidatorHostPort) getValue() interface{} {
return v.Value
}
func (v *ValidatorHostPort) OptionalPort(optionalPort bool) *ValidatorHostPort {
v.optionalPort = optionalPort
return v
}
func (v *ValidatorHostPort) Validate(data *jsonutils.JSONDict) error {
err := v.ValidatorRegexp.Validate(data)
if err != nil {
return err
}
hostPort := v.ValidatorRegexp.Value
if hostPort == "" && (v.optional || v.allowEmpty) {
return nil
}
i := strings.IndexRune(hostPort, ':')
if i < 0 {
if v.optionalPort {
v.Value = hostPort
v.Domain = hostPort
return nil
}
return newInvalidValueError(v.Key, "port missing")
}
portStr := hostPort[i+1:]
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return newInvalidValueError(v.Key, "bad port integer: "+err.Error())
}
if port <= 0 {
return newInvalidValueError(v.Key, "negative port")
}
v.Value = hostPort
v.Domain = hostPort[:i]
v.Port = int(port)
return nil
}
type ValidatorURLPath struct {
ValidatorRegexp
}
@@ -52,6 +52,18 @@ func TestURLPathRegexp(t *testing.T) {
}
}
func TestRegHostPort(t *testing.T) {
inputs := []string{
"www.yunion.cn",
"www.yunion.cn:9000",
}
for _, in := range inputs {
if !regHostPort.Match([]byte(in)) {
t.Errorf("should match: %q", in)
}
}
}
type C struct {
Name string
In string
@@ -554,6 +566,134 @@ func TestRegexValidator(t *testing.T) {
}
}
func TestHostPortValidator(t *testing.T) {
type HostPortC struct {
*C
AllowEmpty bool
OptionalPort bool
}
cases := []*HostPortC{
{
C: &C{
Name: "missing non-optional",
In: `{}`,
Out: `{}`,
Err: ERR_MISSING_KEY,
ValueWant: "",
},
},
{
C: &C{
Name: "missing optional",
In: `{}`,
Out: `{}`,
Optional: true,
ValueWant: "",
},
},
{
C: &C{
Name: "missing with default",
In: `{}`,
Out: `{s: "example.com"}`,
Default: "example.com",
ValueWant: "example.com",
},
OptionalPort: true,
},
{
C: &C{
Name: "missing with default (has port)",
In: `{}`,
Out: `{s: "example.com:9000"}`,
Default: "example.com:9000",
ValueWant: "example.com:9000",
},
},
{
C: &C{
Name: "valid",
In: `{s: "a.example.com"}`,
Out: `{s: "a.example.com"}`,
ValueWant: "a.example.com",
},
OptionalPort: true,
},
{
C: &C{
Name: "valid (has port)",
In: `{s: "a.example.com:9000"}`,
Out: `{s: "a.example.com:9000"}`,
ValueWant: "a.example.com:9000",
},
},
{
C: &C{
Name: "valid (allow empty)",
In: `{s: ""}`,
Out: `{s: ""}`,
ValueWant: "",
},
AllowEmpty: true,
},
{
C: &C{
Name: "invalid (domain)",
In: `{s: "/.example.com:9000"}`,
Out: `{s: "/.example.com:9000"}`,
ValueWant: "",
Err: ERR_INVALID_VALUE,
},
},
{
C: &C{
Name: "invalid (port)",
In: `{s: "/.example.com:65536"}`,
Out: `{s: "/.example.com:65536"}`,
ValueWant: "",
Err: ERR_INVALID_VALUE,
},
},
{
C: &C{
Name: "invalid (no port)",
In: `{s: "a.example.com"}`,
Out: `{s: "a.example.com"}`,
ValueWant: "",
Err: ERR_INVALID_VALUE,
},
},
{
C: &C{
Name: "invalid (disallow empty)",
In: `{s: ""}`,
Out: `{s: ""}`,
ValueWant: "",
Err: ERR_INVALID_VALUE,
},
},
}
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
v := NewHostPortValidator("s")
if c.Default != nil {
i := c.Default.(string)
v.Default(i)
}
if c.Optional {
v.Optional(true)
}
if c.OptionalPort {
v.OptionalPort(true)
}
if c.AllowEmpty {
v.AllowEmpty(true)
}
testS(t, v, c.C)
})
}
}
func TestIPv4Validator(t *testing.T) {
var nilIP net.IP
localIP := net.IPv4(127, 0, 0, 1).To4()