Pull request: home: imp whois parse

Updates #2646.

Squashed commit of the following:

commit 0a5ff6ae74c532a296c0594a598a99c7cfaccf8c
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 20 14:07:08 2021 +0300

    home: imp code

commit 2af0f463a77b81e827d9faca079a19c5437e1cd9
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu May 20 13:48:08 2021 +0300

    home: imp whois parse
This commit is contained in:
Ainar Garipov 2021-05-20 14:22:06 +03:00
parent 21972e49cb
commit 9c60aef637
2 changed files with 135 additions and 46 deletions

View File

@ -10,7 +10,6 @@ import (
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/cache" "github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
) )
@ -66,55 +65,71 @@ func trimValue(s string) string {
return s[:maxValueLength-3] + "..." return s[:maxValueLength-3] + "..."
} }
// Parse plain-text data from the response // coalesceStr returns the first non-empty string.
func whoisParse(data string) map[string]string { //
m := map[string]string{} // TODO(a.garipov): Move to aghstrings?
descr := "" func coalesceStr(strs ...string) (res string) {
netname := "" for _, s := range strs {
for len(data) != 0 { if s != "" {
ln := aghstrings.SplitNext(&data, '\n') return s
if len(ln) == 0 || ln[0] == '#' || ln[0] == '%' { }
}
return ""
}
// isWhoisComment returns true if the string is empty or is a WHOIS comment.
func isWhoisComment(s string) (ok bool) {
return len(s) == 0 || s[0] == '#' || s[0] == '%'
}
// strmap is an alias for convenience.
type strmap = map[string]string
// whoisParse parses a subset of plain-text data from the WHOIS response into
// a string map.
func whoisParse(data string) (m strmap) {
m = strmap{}
var orgname string
lines := strings.Split(data, "\n")
for _, l := range lines {
if isWhoisComment(l) {
continue continue
} }
kv := strings.SplitN(ln, ":", 2) kv := strings.SplitN(l, ":", 2)
if len(kv) != 2 { if len(kv) != 2 {
continue continue
} }
k := strings.TrimSpace(kv[0])
k = strings.ToLower(k) k := strings.ToLower(strings.TrimSpace(kv[0]))
v := strings.TrimSpace(kv[1]) v := strings.TrimSpace(kv[1])
if v == "" {
continue
}
switch k { switch k {
case "org-name": case "orgname", "org-name":
m["orgname"] = trimValue(v) k = "orgname"
case "city", "country", "orgname": v = trimValue(v)
m[k] = trimValue(v) orgname = v
case "descr": case "city", "country":
if len(descr) == 0 { v = trimValue(v)
descr = v case "descr", "netname":
} k = "orgname"
case "netname": v = coalesceStr(orgname, v)
netname = v orgname = v
case "whois": // "whois: whois.arin.net" case "whois":
m["whois"] = v k = "whois"
case "referralserver": // "ReferralServer: whois://whois.ripe.net" case "referralserver":
if strings.HasPrefix(v, "whois://") { k = "whois"
m["whois"] = v[len("whois://"):] v = strings.TrimPrefix(v, "whois://")
} default:
} continue
} }
_, ok := m["orgname"] m[k] = v
if !ok {
// Set orgname from either descr or netname for the frontent.
//
// TODO(a.garipov): Perhaps don't do that in the V1 HTTP API?
if descr != "" {
m["orgname"] = trimValue(descr)
} else if netname != "" {
m["orgname"] = trimValue(netname)
}
} }
return m return m

View File

@ -76,3 +76,77 @@ func TestWhois(t *testing.T) {
assert.Equal(t, "Imagiland", m["country"]) assert.Equal(t, "Imagiland", m["country"])
assert.Equal(t, "Nonreal", m["city"]) assert.Equal(t, "Nonreal", m["city"])
} }
func TestWhoisParse(t *testing.T) {
const (
city = "Nonreal"
country = "Imagiland"
orgname = "FakeOrgLLC"
whois = "whois.example.net"
)
testCases := []struct {
want strmap
name string
in string
}{{
want: strmap{},
name: "empty",
in: ``,
}, {
want: strmap{},
name: "comments",
in: "%\n#",
}, {
want: strmap{},
name: "no_colon",
in: "city",
}, {
want: strmap{},
name: "no_value",
in: "city:",
}, {
want: strmap{"city": city},
name: "city",
in: `city: ` + city,
}, {
want: strmap{"country": country},
name: "country",
in: `country: ` + country,
}, {
want: strmap{"orgname": orgname},
name: "orgname",
in: `orgname: ` + orgname,
}, {
want: strmap{"orgname": orgname},
name: "orgname_hyphen",
in: `org-name: ` + orgname,
}, {
want: strmap{"orgname": orgname},
name: "orgname_descr",
in: `descr: ` + orgname,
}, {
want: strmap{"orgname": orgname},
name: "orgname_netname",
in: `netname: ` + orgname,
}, {
want: strmap{"whois": whois},
name: "whois",
in: `whois: ` + whois,
}, {
want: strmap{"whois": whois},
name: "referralserver",
in: `referralserver: whois://` + whois,
}, {
want: strmap{},
name: "other",
in: `other: value`,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got := whoisParse(tc.in)
assert.Equal(t, tc.want, got)
})
}
}