Pull request: all: replace aghstrings with stringutil

Merge in DNS/adguard-home from add-stringutil to master

Squashed commit of the following:

commit 4ca9b29356de7d0a162b1e5a6496c691e9751f15
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jul 29 17:29:25 2021 +0300

    all: replace aghstrings with stringutil
This commit is contained in:
Ainar Garipov 2021-07-29 17:40:31 +03:00
parent 0030e31e33
commit 63ee95dfbe
27 changed files with 142 additions and 478 deletions

4
go.mod
View file

@ -4,14 +4,14 @@ go 1.16
require (
github.com/AdguardTeam/dnsproxy v0.39.0
github.com/AdguardTeam/golibs v0.8.0
github.com/AdguardTeam/golibs v0.8.4
github.com/AdguardTeam/urlfilter v0.14.6
github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.2.1
github.com/digineo/go-ipset/v2 v2.2.1
github.com/fsnotify/fsnotify v1.4.9
github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/go-cmp v0.5.5
github.com/google/renameio v1.0.1
github.com/insomniacslk/dhcp v0.0.0-20210310193751-cfd4d47082c2
github.com/kardianos/service v1.2.0

7
go.sum
View file

@ -9,14 +9,13 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk=
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
github.com/AdguardTeam/dnsproxy v0.38.3 h1:DvycTEOn2wuHmY+HE5XL4EnCV2EVbpREpbgZB06IJ0I=
github.com/AdguardTeam/dnsproxy v0.38.3/go.mod h1:aNXKNdTyKfgAG2OS712SYSaGIM9AasZsZxfiY4YiR/0=
github.com/AdguardTeam/dnsproxy v0.39.0 h1:5/PN2mpUeCTWtvqXUbSPTMJSOad4lJscPzm+C2f4jB4=
github.com/AdguardTeam/dnsproxy v0.39.0/go.mod h1:aNXKNdTyKfgAG2OS712SYSaGIM9AasZsZxfiY4YiR/0=
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.8.0 h1:rHo+yIgT2fivFG0yW2Cwk/DPc2+t/Aw6QvzPpiIFre0=
github.com/AdguardTeam/golibs v0.8.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/golibs v0.8.4 h1:jd6GwvQQtfSLOKn30qisDVujvas3q7Agjm3BOEqRWpQ=
github.com/AdguardTeam/golibs v0.8.4/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
github.com/AdguardTeam/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo=
github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
@ -30,7 +29,6 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/ameshkov/dnscrypt/v2 v2.1.3 h1:DG4Uf7LSDg6XDj9sp3maxh3Ur26jeGQaP5MeYosn6v0=
github.com/ameshkov/dnscrypt/v2 v2.1.3/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo=
github.com/ameshkov/dnscrypt/v2 v2.2.1 h1:+cApRxzeBZqjUNsN26TTz7r5A8U+buON3kJgIYE3QWQ=
github.com/ameshkov/dnscrypt/v2 v2.2.1/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo=
@ -109,7 +107,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joomcode/errorx v1.0.1/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ=
github.com/joomcode/errorx v1.0.3 h1:3e1mi0u7/HTPNdg6d6DYyKGBhA5l9XpsfuVE29NxnWw=

View file

@ -13,9 +13,9 @@ import (
"syscall"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
)
// ErrNoStaticIPInfo is returned by IfaceHasStaticIP when no information about
@ -371,14 +371,14 @@ func ReverseAddr(ip net.IP) (arpa string) {
strLen, suffix = arpaV4MaxLen, arpaV4Suffix[1:]
ip = ip4
writeByte = func(val byte) {
aghstrings.WriteToBuilder(b, strconv.Itoa(int(val)), dot)
stringutil.WriteToBuilder(b, strconv.Itoa(int(val)), dot)
}
} else if ip6 := ip.To16(); ip6 != nil {
strLen, suffix = arpaV6MaxLen, arpaV6Suffix[1:]
ip = ip6
writeByte = func(val byte) {
aghstrings.WriteToBuilder(
stringutil.WriteToBuilder(
b,
strconv.FormatUint(uint64(val&0xF), 16),
dot,
@ -395,7 +395,7 @@ func ReverseAddr(ip net.IP) (arpa string) {
for i := len(ip) - 1; i >= 0; i-- {
writeByte(ip[i])
}
aghstrings.WriteToBuilder(b, suffix)
stringutil.WriteToBuilder(b, suffix)
return b.String()
}

View file

@ -14,8 +14,8 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/google/renameio/maybe"
"golang.org/x/sys/unix"
)
@ -70,7 +70,7 @@ func (rc *recurrentChecker) checkFile(sourcePath, desired string) (
}
// handlePatterns parses the patterns and takes care of duplicates.
func (rc *recurrentChecker) handlePatterns(sourcesSet *aghstrings.Set, patterns []string) (
func (rc *recurrentChecker) handlePatterns(sourcesSet *stringutil.Set, patterns []string) (
subsources []string,
err error,
) {
@ -111,7 +111,7 @@ func (rc *recurrentChecker) check(desired string) (has bool, err error) {
var patterns, subsources []string
// The slice of sources is separate from the set of sources to keep the
// order in which the files are walked.
for sourcesSet := aghstrings.NewSet(rc.initPath); i < len(sources); i++ {
for sourcesSet := stringutil.NewSet(rc.initPath); i < len(sources); i++ {
patterns, has, err = rc.checkFile(sources[i], desired)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
@ -217,7 +217,7 @@ func ifacesStaticConfig(r io.Reader, ifaceName string) (subsources []string, has
s := bufio.NewScanner(r)
for s.Scan() {
line := strings.TrimSpace(s.Text())
if aghstrings.IsCommentOrEmpty(line) {
if len(line) == 0 || line[0] == '#' {
continue
}

View file

@ -11,8 +11,8 @@ import (
"sync"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/stringutil"
)
// defaultHostGen is the default method of generating host for Refresh.
@ -27,7 +27,7 @@ type systemResolvers struct {
hostGenFunc HostGenFunc
// addrs is the set that contains cached local resolvers' addresses.
addrs *aghstrings.Set
addrs *stringutil.Set
addrsLock sync.RWMutex
}
@ -64,7 +64,7 @@ func newSystemResolvers(refreshIvl time.Duration, hostGenFunc HostGenFunc) (sr S
PreferGo: true,
},
hostGenFunc: hostGenFunc,
addrs: aghstrings.NewSet(),
addrs: stringutil.NewSet(),
}
s.resolver.Dial = s.dialFunc

View file

@ -1,71 +0,0 @@
package aghstrings
// unit is a convenient alias for struct{}
type unit = struct{}
// Set is a set of strings.
type Set struct {
m map[string]unit
}
// NewSet returns a new string set containing strs.
func NewSet(strs ...string) (set *Set) {
set = &Set{
m: make(map[string]unit, len(strs)),
}
for _, s := range strs {
set.Add(s)
}
return set
}
// Add adds s to the set. Add panics if the set is a nil set, just like a nil
// map does.
func (set *Set) Add(s string) {
set.m[s] = unit{}
}
// Del deletes s from the set. Calling Del on a nil set has no effect, just
// like delete on an empty map doesn't.
func (set *Set) Del(s string) {
if set != nil {
delete(set.m, s)
}
}
// Has returns true if s is in the set. Calling Has on a nil set returns false,
// just like indexing on an empty map does.
func (set *Set) Has(s string) (ok bool) {
if set != nil {
_, ok = set.m[s]
}
return ok
}
// Len returns the length of the set. A nil set has a length of zero, just like
// an empty map.
func (set *Set) Len() (n int) {
if set == nil {
return 0
}
return len(set.m)
}
// Values returns all values in the set. The order of the values is undefined.
// Values returns nil if the set is nil.
func (set *Set) Values() (strs []string) {
if set == nil {
return nil
}
strs = make([]string, 0, len(set.m))
for s := range set.m {
strs = append(strs, s)
}
return strs
}

View file

@ -1,56 +0,0 @@
package aghstrings
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSet(t *testing.T) {
const s = "a"
t.Run("nil", func(t *testing.T) {
var set *Set
assert.NotPanics(t, func() {
set.Del(s)
})
assert.NotPanics(t, func() {
assert.False(t, set.Has(s))
})
assert.NotPanics(t, func() {
assert.Equal(t, 0, set.Len())
})
assert.NotPanics(t, func() {
assert.Nil(t, set.Values())
})
assert.Panics(t, func() {
set.Add(s)
})
})
t.Run("non_nil", func(t *testing.T) {
set := NewSet()
assert.Equal(t, 0, set.Len())
ok := set.Has(s)
assert.False(t, ok)
set.Add(s)
ok = set.Has(s)
assert.True(t, ok)
assert.Equal(t, []string{s}, set.Values())
set.Del(s)
ok = set.Has(s)
assert.False(t, ok)
set = NewSet(s)
assert.Equal(t, 1, set.Len())
})
}

View file

@ -1,103 +0,0 @@
// Package aghstrings contains utilities dealing with strings.
package aghstrings
import (
"strings"
)
// CloneSliceOrEmpty returns the copy of a or empty strings slice if a is nil.
func CloneSliceOrEmpty(a []string) (b []string) {
return append([]string{}, a...)
}
// CloneSlice returns the exact copy of a.
func CloneSlice(a []string) (b []string) {
if a == nil {
return nil
}
return CloneSliceOrEmpty(a)
}
// Coalesce returns the first non-empty string. It is named after the function
// COALESCE in SQL except that since strings in Go are non-nullable, it uses an
// empty string as a NULL value. If strs or all it's elements are empty, it
// returns an empty string.
func Coalesce(strs ...string) (res string) {
for _, s := range strs {
if s != "" {
return s
}
}
return ""
}
// FilterOut returns a copy of strs with all strings for which f returned true
// removed.
func FilterOut(strs []string, f func(s string) (ok bool)) (filtered []string) {
for _, s := range strs {
if !f(s) {
filtered = append(filtered, s)
}
}
return filtered
}
// InSlice checks if string is in the slice of strings.
func InSlice(strs []string, str string) (ok bool) {
for _, s := range strs {
if s == str {
return true
}
}
return false
}
// IsCommentOrEmpty returns true of the string starts with a "#" character or is
// an empty string.
func IsCommentOrEmpty(s string) (ok bool) {
return len(s) == 0 || s[0] == '#'
}
// SplitNext splits string by a byte and returns the first chunk skipping empty
// ones. Whitespaces are trimmed.
func SplitNext(s *string, sep rune) (chunk string) {
if s == nil {
return chunk
}
i := strings.IndexByte(*s, byte(sep))
if i == -1 {
chunk = *s
*s = ""
return strings.TrimSpace(chunk)
}
chunk = (*s)[:i]
*s = (*s)[i+1:]
var j int
var r rune
for j, r = range *s {
if r != sep {
break
}
}
*s = (*s)[j:]
return strings.TrimSpace(chunk)
}
// WriteToBuilder is a convenient wrapper for strings.(*Builder).WriteString
// that deals with multiple strings and ignores errors that are guaranteed to be
// nil.
func WriteToBuilder(b *strings.Builder, strs ...string) {
// TODO(e.burkov): Recover from panic?
for _, s := range strs {
_, _ = b.WriteString(s)
}
}

View file

@ -1,137 +0,0 @@
package aghstrings
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCloneSlice_family(t *testing.T) {
a := []string{"1", "2", "3"}
t.Run("cloneslice_simple", func(t *testing.T) {
assert.Equal(t, a, CloneSlice(a))
})
t.Run("cloneslice_nil", func(t *testing.T) {
assert.Nil(t, CloneSlice(nil))
})
t.Run("cloneslice_empty", func(t *testing.T) {
assert.Equal(t, []string{}, CloneSlice([]string{}))
})
t.Run("clonesliceorempty_nil", func(t *testing.T) {
assert.Equal(t, []string{}, CloneSliceOrEmpty(nil))
})
t.Run("clonesliceorempty_empty", func(t *testing.T) {
assert.Equal(t, []string{}, CloneSliceOrEmpty([]string{}))
})
t.Run("clonesliceorempty_sameness", func(t *testing.T) {
assert.Equal(t, CloneSlice(a), CloneSliceOrEmpty(a))
})
}
func TestCoalesce(t *testing.T) {
assert.Equal(t, "", Coalesce())
assert.Equal(t, "a", Coalesce("a"))
assert.Equal(t, "a", Coalesce("", "a"))
assert.Equal(t, "a", Coalesce("a", ""))
assert.Equal(t, "a", Coalesce("a", "b"))
}
func TestFilterOut(t *testing.T) {
strs := []string{
"1.2.3.4",
"",
"# 5.6.7.8",
}
want := []string{
"1.2.3.4",
}
got := FilterOut(strs, IsCommentOrEmpty)
assert.Equal(t, want, got)
}
func TestInSlice(t *testing.T) {
simpleStrs := []string{"1", "2", "3"}
testCases := []struct {
name string
str string
strs []string
want bool
}{{
name: "yes",
str: "2",
strs: simpleStrs,
want: true,
}, {
name: "no",
str: "4",
strs: simpleStrs,
want: false,
}, {
name: "nil",
str: "any",
strs: nil,
want: false,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, tc.want, InSlice(tc.strs, tc.str))
})
}
}
func TestSplitNext(t *testing.T) {
t.Run("ordinary", func(t *testing.T) {
s := " a,b , c "
require.Equal(t, "a", SplitNext(&s, ','))
require.Equal(t, "b", SplitNext(&s, ','))
require.Equal(t, "c", SplitNext(&s, ','))
assert.Empty(t, s)
})
t.Run("nil_source", func(t *testing.T) {
assert.Equal(t, "", SplitNext(nil, 's'))
})
}
func TestWriteToBuilder(t *testing.T) {
b := &strings.Builder{}
t.Run("single", func(t *testing.T) {
assert.NotPanics(t, func() { WriteToBuilder(b, t.Name()) })
assert.Equal(t, t.Name(), b.String())
})
b.Reset()
t.Run("several", func(t *testing.T) {
const (
_1 = "one"
_2 = "two"
_123 = _1 + _2
)
assert.NotPanics(t, func() { WriteToBuilder(b, _1, _2) })
assert.Equal(t, _123, b.String())
})
b.Reset()
t.Run("nothing", func(t *testing.T) {
assert.NotPanics(t, func() { WriteToBuilder(b) })
assert.Equal(t, "", b.String())
})
t.Run("nil_builder", func(t *testing.T) {
assert.Panics(t, func() { WriteToBuilder(nil, "a") })
})
}

View file

@ -12,9 +12,9 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/go-ping/ping"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv4/server4"
@ -32,7 +32,7 @@ type v4Server struct {
leasedOffsets *bitSet
// leaseHosts is the set of all hostnames of all known DHCP clients.
leaseHosts *aghstrings.Set
leaseHosts *stringutil.Set
// leases contains all dynamic and static leases.
leases []*Lease
@ -105,7 +105,7 @@ func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
}
s.leasedOffsets = newBitSet()
s.leaseHosts = aghstrings.NewSet()
s.leaseHosts = stringutil.NewSet()
s.leases = nil
for _, l := range leases {
@ -1017,7 +1017,7 @@ func (s *v4Server) Stop() (err error) {
func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
s := &v4Server{}
s.conf = conf
s.leaseHosts = aghstrings.NewSet()
s.leaseHosts = stringutil.NewSet()
// TODO(a.garipov): Don't use a disabled server in other places or just
// use an interface.

View file

@ -8,8 +8,8 @@ import (
"strings"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
)
@ -20,8 +20,8 @@ type accessCtx struct {
allowedIPs *aghnet.IPMap
blockedIPs *aghnet.IPMap
allowedClientIDs *aghstrings.Set
blockedClientIDs *aghstrings.Set
allowedClientIDs *stringutil.Set
blockedClientIDs *stringutil.Set
blockedHostsEng *urlfilter.DNSEngine
@ -40,7 +40,7 @@ func processAccessClients(
clientStrs []string,
ips *aghnet.IPMap,
nets *[]*net.IPNet,
clientIDs *aghstrings.Set,
clientIDs *stringutil.Set,
) (err error) {
for i, s := range clientStrs {
if ip := net.ParseIP(s); ip != nil {
@ -71,8 +71,8 @@ func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessCtx, err er
allowedIPs: aghnet.NewIPMap(0),
blockedIPs: aghnet.NewIPMap(0),
allowedClientIDs: aghstrings.NewSet(),
blockedClientIDs: aghstrings.NewSet(),
allowedClientIDs: stringutil.NewSet(),
blockedClientIDs: stringutil.NewSet(),
}
err = processAccessClients(allowed, a.allowedIPs, &a.allowedNets, a.allowedClientIDs)
@ -87,7 +87,7 @@ func newAccessCtx(allowed, blocked, blockedHosts []string) (a *accessCtx, err er
b := &strings.Builder{}
for _, h := range blockedHosts {
aghstrings.WriteToBuilder(b, strings.ToLower(h), "\n")
stringutil.WriteToBuilder(b, strings.ToLower(h), "\n")
}
lists := []filterlist.RuleList{
@ -174,9 +174,9 @@ func (s *Server) accessListJSON() (j accessListJSON) {
defer s.serverLock.RUnlock()
return accessListJSON{
AllowedClients: aghstrings.CloneSlice(s.conf.AllowedClients),
DisallowedClients: aghstrings.CloneSlice(s.conf.DisallowedClients),
BlockedHosts: aghstrings.CloneSlice(s.conf.BlockedHosts),
AllowedClients: stringutil.CloneSlice(s.conf.AllowedClients),
DisallowedClients: stringutil.CloneSlice(s.conf.DisallowedClients),
BlockedHosts: stringutil.CloneSlice(s.conf.BlockedHosts),
}
}

View file

@ -12,12 +12,12 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/ameshkov/dnscrypt/v2"
)
@ -327,17 +327,15 @@ func (s *Server) prepareUpstreamSettings() error {
if err != nil {
return err
}
d := string(data)
for len(d) != 0 {
s := aghstrings.SplitNext(&d, '\n')
upstreams = append(upstreams, s)
}
upstreams = stringutil.SplitTrimmed(string(data), "\n")
log.Debug("dns: using %d upstream servers from file %s", len(upstreams), s.conf.UpstreamDNSFileName)
} else {
upstreams = s.conf.UpstreamDNS
}
upstreams = aghstrings.FilterOut(upstreams, aghstrings.IsCommentOrEmpty)
upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty)
upstreamConfig, err := proxy.ParseUpstreamsConfig(
upstreams,
&upstream.Options{

View file

@ -6,11 +6,11 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
)
@ -518,7 +518,7 @@ func (s *Server) processUpstream(ctx *dnsContext) (rc resultCode) {
if d.Addr != nil && s.conf.GetCustomUpstreamByClient != nil {
// Use the clientID first, since it has a higher priority.
id := aghstrings.Coalesce(ctx.clientID, ipStringFromAddr(d.Addr))
id := stringutil.Coalesce(ctx.clientID, ipStringFromAddr(d.Addr))
upsConf, err := s.conf.GetCustomUpstreamByClient(id)
if err != nil {
log.Error("dns: getting custom upstreams for client %s: %s", id, err)

View file

@ -11,7 +11,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
@ -21,6 +20,7 @@ import (
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
)
@ -222,13 +222,13 @@ func (s *Server) WriteDiskConfig(c *FilteringConfig) {
sc := s.conf.FilteringConfig
*c = sc
c.RatelimitWhitelist = aghstrings.CloneSlice(sc.RatelimitWhitelist)
c.BootstrapDNS = aghstrings.CloneSlice(sc.BootstrapDNS)
c.AllowedClients = aghstrings.CloneSlice(sc.AllowedClients)
c.DisallowedClients = aghstrings.CloneSlice(sc.DisallowedClients)
c.BlockedHosts = aghstrings.CloneSlice(sc.BlockedHosts)
c.TrustedProxies = aghstrings.CloneSlice(sc.TrustedProxies)
c.UpstreamDNS = aghstrings.CloneSlice(sc.UpstreamDNS)
c.RatelimitWhitelist = stringutil.CloneSlice(sc.RatelimitWhitelist)
c.BootstrapDNS = stringutil.CloneSlice(sc.BootstrapDNS)
c.AllowedClients = stringutil.CloneSlice(sc.AllowedClients)
c.DisallowedClients = stringutil.CloneSlice(sc.DisallowedClients)
c.BlockedHosts = stringutil.CloneSlice(sc.BlockedHosts)
c.TrustedProxies = stringutil.CloneSlice(sc.TrustedProxies)
c.UpstreamDNS = stringutil.CloneSlice(sc.UpstreamDNS)
}
// RDNSSettings returns the copy of actual RDNS configuration.
@ -236,7 +236,7 @@ func (s *Server) RDNSSettings() (localPTRResolvers []string, resolveClients, res
s.serverLock.RLock()
defer s.serverLock.RUnlock()
return aghstrings.CloneSlice(s.conf.LocalPTRResolvers),
return stringutil.CloneSlice(s.conf.LocalPTRResolvers),
s.conf.ResolveClients,
s.conf.UsePrivateRDNS
}
@ -398,13 +398,13 @@ func (s *Server) filterOurDNSAddrs(addrs []string) (filtered []string, err error
return nil, err
}
ourAddrsSet := aghstrings.NewSet(ourAddrs...)
ourAddrsSet := stringutil.NewSet(ourAddrs...)
// TODO(e.burkov): The approach of subtracting sets of strings is not
// really applicable here since in case of listening on all network
// interfaces we should check the whole interface's network to cut off
// all the loopback addresses as well.
return aghstrings.FilterOut(addrs, ourAddrsSet.Has), nil
return stringutil.FilterOut(addrs, ourAddrsSet.Has), nil
}
// setupResolvers initializes the resolvers for local addresses. For internal

View file

@ -10,11 +10,11 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
)
@ -51,9 +51,9 @@ func (s *Server) getDNSConfig() dnsConfig {
s.serverLock.RLock()
defer s.serverLock.RUnlock()
upstreams := aghstrings.CloneSliceOrEmpty(s.conf.UpstreamDNS)
upstreams := stringutil.CloneSliceOrEmpty(s.conf.UpstreamDNS)
upstreamFile := s.conf.UpstreamDNSFileName
bootstraps := aghstrings.CloneSliceOrEmpty(s.conf.BootstrapDNS)
bootstraps := stringutil.CloneSliceOrEmpty(s.conf.BootstrapDNS)
protectionEnabled := s.conf.ProtectionEnabled
blockingMode := s.conf.BlockingMode
blockingIPv4 := s.conf.BlockingIPv4
@ -68,7 +68,7 @@ func (s *Server) getDNSConfig() dnsConfig {
cacheOptimistic := s.conf.CacheOptimistic
resolveClients := s.conf.ResolveClients
usePrivateRDNS := s.conf.UsePrivateRDNS
localPTRUpstreams := aghstrings.CloneSliceOrEmpty(s.conf.LocalPTRResolvers)
localPTRUpstreams := stringutil.CloneSliceOrEmpty(s.conf.LocalPTRResolvers)
var upstreamMode string
if s.conf.FastestAddr {
upstreamMode = "fastest_addr"
@ -341,13 +341,20 @@ type upstreamJSON struct {
PrivateUpstreams []string `json:"private_upstream"`
}
// IsCommentOrEmpty returns true of the string starts with a "#" character or is
// an empty string. This function is useful for filtering out non-upstream
// lines from upstream configs.
func IsCommentOrEmpty(s string) (ok bool) {
return len(s) == 0 || s[0] == '#'
}
// ValidateUpstreams validates each upstream and returns an error if any
// upstream is invalid or if there are no default upstreams specified.
//
// TODO(e.burkov): Move into aghnet or even into dnsproxy.
func ValidateUpstreams(upstreams []string) (err error) {
// No need to validate comments
upstreams = aghstrings.FilterOut(upstreams, aghstrings.IsCommentOrEmpty)
upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty)
// Consider this case valid because defaultDNS will be used
if len(upstreams) == 0 {
@ -529,7 +536,7 @@ func checkPrivateUpstreamExc(u upstream.Upstream) (err error) {
}
func checkDNS(input string, bootstrap []string, timeout time.Duration, ef excFunc) (err error) {
if aghstrings.IsCommentOrEmpty(input) {
if IsCommentOrEmpty(input) {
return nil
}

View file

@ -241,6 +241,12 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) {
}
}
func TestIsCommentOrEmpty(t *testing.T) {
assert.True(t, IsCommentOrEmpty(""))
assert.True(t, IsCommentOrEmpty("# comment"))
assert.False(t, IsCommentOrEmpty("1.2.3.4"))
}
// TODO(a.garipov): Rewrite to check the actual error messages.
func TestValidateUpstream(t *testing.T) {
testCases := []struct {

View file

@ -14,10 +14,10 @@ import (
"sync/atomic"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/AdguardTeam/urlfilter"
"github.com/AdguardTeam/urlfilter/filterlist"
"github.com/AdguardTeam/urlfilter/rules"
@ -497,7 +497,7 @@ func (d *DNSFilter) processRewrites(host string, qtype uint16) (res Result) {
res.Reason = Rewritten
}
cnames := aghstrings.NewSet()
cnames := stringutil.NewSet()
origHost := host
for len(rr) != 0 && rr[0].Type == dns.TypeCNAME {
log.Debug("rewrite: CNAME for %s is %s", host, rr[0].Answer)

View file

@ -13,10 +13,10 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
"golang.org/x/net/publicsuffix"
)
@ -186,16 +186,16 @@ func (c *sbCtx) getQuestion() string {
for hash := range c.hashToHost {
// TODO(e.burkov, a.garipov): Find out and document why exactly
// this slice.
aghstrings.WriteToBuilder(b, hex.EncodeToString(hash[0:2]), ".")
stringutil.WriteToBuilder(b, hex.EncodeToString(hash[0:2]), ".")
}
if c.svc == "SafeBrowsing" {
aghstrings.WriteToBuilder(b, sbTXTSuffix)
stringutil.WriteToBuilder(b, sbTXTSuffix)
return b.String()
}
aghstrings.WriteToBuilder(b, pcTXTSuffix)
stringutil.WriteToBuilder(b, pcTXTSuffix)
return b.String()
}

View file

@ -12,7 +12,6 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
@ -21,6 +20,7 @@ import (
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
)
const clientsUpdatePeriod = 10 * time.Minute
@ -86,7 +86,7 @@ type clientsContainer struct {
lock sync.Mutex
allTags *aghstrings.Set
allTags *stringutil.Set
// dhcpServer is used for looking up clients IP addresses by MAC addresses
dhcpServer *dhcpd.Server
@ -114,7 +114,7 @@ func (clients *clientsContainer) Init(
clients.idIndex = make(map[string]*Client)
clients.ipToRC = aghnet.NewIPMap(0)
clients.allTags = aghstrings.NewSet(clientTags...)
clients.allTags = stringutil.NewSet(clientTags...)
clients.dhcpServer = dhcpServer
clients.etcHosts = etcHosts
@ -221,10 +221,10 @@ func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) {
UseGlobalBlockedServices: !cli.UseOwnBlockedServices,
}
cy.Tags = aghstrings.CloneSlice(cli.Tags)
cy.IDs = aghstrings.CloneSlice(cli.IDs)
cy.BlockedServices = aghstrings.CloneSlice(cli.BlockedServices)
cy.Upstreams = aghstrings.CloneSlice(cli.Upstreams)
cy.Tags = stringutil.CloneSlice(cli.Tags)
cy.IDs = stringutil.CloneSlice(cli.IDs)
cy.BlockedServices = stringutil.CloneSlice(cli.BlockedServices)
cy.Upstreams = stringutil.CloneSlice(cli.Upstreams)
*objects = append(*objects, cy)
}
@ -328,10 +328,10 @@ func (clients *clientsContainer) Find(id string) (c *Client, ok bool) {
return nil, false
}
c.IDs = aghstrings.CloneSlice(c.IDs)
c.Tags = aghstrings.CloneSlice(c.Tags)
c.BlockedServices = aghstrings.CloneSlice(c.BlockedServices)
c.Upstreams = aghstrings.CloneSlice(c.Upstreams)
c.IDs = stringutil.CloneSlice(c.IDs)
c.Tags = stringutil.CloneSlice(c.Tags)
c.BlockedServices = stringutil.CloneSlice(c.BlockedServices)
c.Upstreams = stringutil.CloneSlice(c.Upstreams)
return c, true
}
@ -349,7 +349,7 @@ func (clients *clientsContainer) findUpstreams(
return nil, nil
}
upstreams := aghstrings.FilterOut(c.Upstreams, aghstrings.IsCommentOrEmpty)
upstreams := stringutil.FilterOut(c.Upstreams, dnsforward.IsCommentOrEmpty)
if len(upstreams) == 0 {
return nil, nil
}

View file

@ -6,12 +6,12 @@ import (
"net/http"
"strings"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
)
// TODO(a.garipov): Get rid of a global variable?
var allowedLanguages = aghstrings.NewSet(
var allowedLanguages = stringutil.NewSet(
"be",
"bg",
"cs",

View file

@ -9,12 +9,12 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -86,7 +86,7 @@ func TestRDNS_Begin(t *testing.T) {
list: map[string]*Client{},
idIndex: tc.cliIDIndex,
ipToRC: aghnet.NewIPMap(0),
allTags: aghstrings.NewSet(),
allTags: stringutil.NewSet(),
},
}
ipCache.Clear()
@ -206,7 +206,7 @@ func TestRDNS_WorkerLoop(t *testing.T) {
list: map[string]*Client{},
idIndex: map[string]*Client{},
ipToRC: aghnet.NewIPMap(0),
allTags: aghstrings.NewSet(),
allTags: stringutil.NewSet(),
}
ch := make(chan net.IP)
rdns := &RDNS{

View file

@ -14,7 +14,6 @@ import (
"net/http"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"sync"
@ -22,6 +21,7 @@ import (
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/google/go-cmp/cmp"
"golang.org/x/sys/cpu"
)
@ -270,8 +270,9 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
}
status = validateCertificates(string(data.CertificateChainData), string(data.PrivateKeyData), data.ServerName)
restartHTTPS := false
t.confLock.Lock()
if !reflect.DeepEqual(t.conf, data) {
if !cmp.Equal(t.conf, data) {
log.Printf("tls config settings have changed, will restart HTTPS server")
restartHTTPS = true
}

View file

@ -10,10 +10,10 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/cache"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
)
const (
@ -107,7 +107,7 @@ func whoisParse(data string) (m strmap) {
v = trimValue(v)
case "descr", "netname":
k = "orgname"
v = aghstrings.Coalesce(orgname, v)
v = stringutil.Coalesce(orgname, v)
orgname = v
case "whois":
k = "whois"

View file

@ -9,9 +9,9 @@ import (
"strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/jsonutil"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/stringutil"
"golang.org/x/net/idna"
)
@ -160,7 +160,7 @@ func (l *queryLog) parseSearchCriterion(q url.Values, name string, ct criterionT
asciiVal = ""
}
case ctFilteringStatus:
if !aghstrings.InSlice(filteringStatusValues, val) {
if !stringutil.InSlice(filteringStatusValues, val) {
return false, sc, fmt.Errorf("invalid value %s", val)
}
default:

View file

@ -8,7 +8,7 @@ import (
"strconv"
"strings"
"github.com/AdguardTeam/AdGuardHome/internal/aghstrings"
"github.com/AdguardTeam/golibs/stringutil"
)
// Channel constants.
@ -93,16 +93,16 @@ func fmtModule(m *debug.Module) (formatted string) {
b := &strings.Builder{}
aghstrings.WriteToBuilder(b, m.Path)
stringutil.WriteToBuilder(b, m.Path)
if ver := m.Version; ver != "" {
sep := modInfoAtSep
if ver == "(devel)" {
sep = modInfoDevSep
}
aghstrings.WriteToBuilder(b, sep, ver)
stringutil.WriteToBuilder(b, sep, ver)
}
if sum := m.Sum; sum != "" {
aghstrings.WriteToBuilder(b, modInfoSumLeft, sum, modInfoSumRight)
stringutil.WriteToBuilder(b, modInfoSumLeft, sum, modInfoSumRight)
}
return b.String()
@ -142,7 +142,7 @@ const (
func Verbose() (v string) {
b := &strings.Builder{}
aghstrings.WriteToBuilder(
stringutil.WriteToBuilder(
b,
vFmtAGHHdr,
nl,
@ -156,15 +156,15 @@ func Verbose() (v string) {
runtime.Version(),
)
if buildtime != "" {
aghstrings.WriteToBuilder(b, nl, vFmtTimeHdr, buildtime)
stringutil.WriteToBuilder(b, nl, vFmtTimeHdr, buildtime)
}
aghstrings.WriteToBuilder(b, nl, vFmtGOOSHdr, nl, vFmtGOARCHHdr)
stringutil.WriteToBuilder(b, nl, vFmtGOOSHdr, nl, vFmtGOARCHHdr)
if goarm != "" {
aghstrings.WriteToBuilder(b, nl, vFmtGOARMHdr, "v", goarm)
stringutil.WriteToBuilder(b, nl, vFmtGOARMHdr, "v", goarm)
} else if gomips != "" {
aghstrings.WriteToBuilder(b, nl, vFmtGOMIPSHdr, gomips)
stringutil.WriteToBuilder(b, nl, vFmtGOMIPSHdr, gomips)
}
aghstrings.WriteToBuilder(b, nl, vFmtRaceHdr, strconv.FormatBool(isRace))
stringutil.WriteToBuilder(b, nl, vFmtRaceHdr, strconv.FormatBool(isRace))
info, ok := debug.ReadBuildInfo()
if !ok {
@ -175,10 +175,10 @@ func Verbose() (v string) {
return b.String()
}
aghstrings.WriteToBuilder(b, nl, vFmtDepsHdr)
stringutil.WriteToBuilder(b, nl, vFmtDepsHdr)
for _, dep := range info.Deps {
if depStr := fmtModule(dep); depStr != "" {
aghstrings.WriteToBuilder(b, nltb, depStr)
stringutil.WriteToBuilder(b, nltb, depStr)
}
}

View file

@ -4,29 +4,32 @@ set -e -f -u
# Show all temporary todos to the programmer but don't fail the commit
# if there are any, because the commit could be in a temporary branch.
git grep -e 'TODO.*!!' -- ':!HACKING.md' ':!scripts/hooks/pre-commit' | cat || :
git grep -e 'TODO.*!!' -- ':!scripts/hooks/pre-commit' | cat || :
verbose="${VERBOSE:-0}"
readonly verbose
if [ "$( git diff --cached --name-only -- 'client/*.js' )" ]
then
make js-lint js-test
make VERBOSE="$verbose" js-lint js-test
fi
if [ "$( git diff --cached --name-only -- 'client2/*.js' 'client2/*.ts' 'client2/*.tsx' )" ]
then
make js-beta-lint js-beta-test
make VERBOSE="$verbose" js-beta-lint js-beta-test
fi
if [ "$( git diff --cached --name-only -- '*.go' '*.mod' '*.sh' 'Makefile' )" ]
then
make go-os-check go-lint go-test
make VERBOSE="$verbose" go-os-check go-lint go-test
fi
if [ "$( git diff --cached --name-only -- '*.md' '*.yaml' '*.yml' )" ]
then
make txt-lint
make VERBOSE="$verbose" txt-lint
fi
if [ "$( git diff --cached --name-only -- './openapi/openapi.yaml' )" ]
then
make openapi-lint
make VERBOSE="$verbose" openapi-lint
fi

View file

@ -73,11 +73,31 @@ esac
# Simple Analyzers
# blocklist_imports is a simple check against unwanted packages. Package
# io/ioutil is soft-deprecated. Packages errors and log are replaced by our own
# packages in the github.com/AdguardTeam/golibs module.
# blocklist_imports is a simple check against unwanted packages. The following
# packages are banned:
#
# * Package io/ioutil is soft-deprecated.
#
# * Packages errors and log are replaced by our own packages in the
# github.com/AdguardTeam/golibs module.
#
# * Package reflect is often an overkill, and for deep comparisons there are
# much better functions in module github.com/google/go-cmp. Which is
# already our indirect dependency and which may or may not enter the stdlib
# at some point.
#
# See https://github.com/golang/go/issues/45200.
#
# * Package unsafe is… unsafe.
#
blocklist_imports() {
git grep -F -e '"errors"' -e '"io/ioutil"' -e '"log"' -- '*.go' || exit 0;
git grep\
-e '[[:space:]]"errors"$'\
-e '[[:space:]]"io/ioutil"$'\
-e '[[:space:]]"log"$'\
-e '[[:space:]]"reflect"$'\
-e '[[:space:]]"unsafe"$'\
-- '*.go' || exit 0;
}
# method_const is a simple check against the usage of some raw strings and
@ -181,8 +201,7 @@ gocyclo --over 17 ./internal/dhcpd/ ./internal/dnsforward/\
# Apply stricter standards to new or vetted code
gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
./internal/aghstrings/ ./internal/aghtest/ ./internal/tools/\
./internal/version/ ./main.go
./internal/aghtest/ ./internal/tools/ ./internal/version/ ./main.go
gosec --quiet $go_files