mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
validators: add ValidatorHostPort
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user