mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-24 14:05:45 +03:00
Pull request 2297: AG-20945-filter-storage
Squashed commit of the following: commit2611fd5781
Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Fri Nov 1 16:29:06 2024 +0300 dnsforward: imp test commit5efcfda937
Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Fri Nov 1 15:54:18 2024 +0300 rulelist: imp docs, tests commit7a759c4699
Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Fri Nov 1 14:36:08 2024 +0300 all: add filtering storage; upd golibs
This commit is contained in:
parent
1d2026bf7e
commit
47dfa44cf6
27 changed files with 279 additions and 89 deletions
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.23.2
|
||||||
require (
|
require (
|
||||||
// TODO(a.garipov): Update when v0.73.3 is released.
|
// TODO(a.garipov): Update when v0.73.3 is released.
|
||||||
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3
|
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3
|
||||||
github.com/AdguardTeam/golibs v0.30.0
|
github.com/AdguardTeam/golibs v0.30.1
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0
|
github.com/AdguardTeam/urlfilter v0.20.0
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
github.com/ameshkov/dnscrypt/v2 v2.3.0
|
github.com/ameshkov/dnscrypt/v2 v2.3.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,7 +1,7 @@
|
||||||
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3 h1:IGXwBjdKDzUm007QzZyxSllMnkbdXe7K79x7JWcBW/E=
|
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3 h1:IGXwBjdKDzUm007QzZyxSllMnkbdXe7K79x7JWcBW/E=
|
||||||
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3/go.mod h1:356iHROxo+SOdBVifp1MXEh6qHyydtzGCcsQMfx+ZVs=
|
github.com/AdguardTeam/dnsproxy v0.73.3-0.20241004151328-c7c7b977a2a3/go.mod h1:356iHROxo+SOdBVifp1MXEh6qHyydtzGCcsQMfx+ZVs=
|
||||||
github.com/AdguardTeam/golibs v0.30.0 h1:3pTdW1B9GZgqARrA5BvmYlAaEG1zAHI/ReikCDxrhiE=
|
github.com/AdguardTeam/golibs v0.30.1 h1:/yv7dq2h7WXw/jTDxkE3FP9zHerRT+i03PZRHJX4fPU=
|
||||||
github.com/AdguardTeam/golibs v0.30.0/go.mod h1:vjw1OVZG6BYyoqGRY88U4LCJLOMfhBFhU0UJBdaSAuQ=
|
github.com/AdguardTeam/golibs v0.30.1/go.mod h1:FkwcNQEJoGsgDGXcalrVa/4gWbE68KsmE2guXWtBQUE=
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
github.com/AdguardTeam/urlfilter v0.20.0 h1:X32qiuVCVd8WDYCEsbdZKfXMzwdVqrdulamtUi4rmzs=
|
||||||
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
github.com/AdguardTeam/urlfilter v0.20.0/go.mod h1:gjrywLTxfJh6JOkwi9SU+frhP7kVVEZ5exFGkR99qpk=
|
||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
|
|
|
@ -14,12 +14,6 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTP scheme constants.
|
|
||||||
const (
|
|
||||||
SchemeHTTP = "http"
|
|
||||||
SchemeHTTPS = "https"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterFunc is the function that sets the handler to handle the URL for the
|
// RegisterFunc is the function that sets the handler to handle the URL for the
|
||||||
// method.
|
// method.
|
||||||
//
|
//
|
||||||
|
|
|
@ -592,6 +592,8 @@ func TestSafeSearch(t *testing.T) {
|
||||||
r, _, errExch := client.Exchange(req, addr)
|
r, _, errExch := client.Exchange(req, addr)
|
||||||
if assert.NoError(c, errExch) {
|
if assert.NoError(c, errExch) {
|
||||||
once.Do(func() { reply = r })
|
once.Do(func() { reply = r })
|
||||||
|
} else {
|
||||||
|
t.Logf("got error: %v", errExch)
|
||||||
}
|
}
|
||||||
}, testTimeout*10, testTimeout)
|
}, testTimeout*10, testTimeout)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -33,7 +33,7 @@ func serveHTTPLocally(t *testing.T, h http.Handler) (urlStr string) {
|
||||||
require.IsType(t, (*net.TCPAddr)(nil), addr)
|
require.IsType(t, (*net.TCPAddr)(nil), addr)
|
||||||
|
|
||||||
return (&url.URL{
|
return (&url.URL{
|
||||||
Scheme: aghhttp.SchemeHTTP,
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
}).String()
|
}).String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,19 +42,14 @@ func (d *DNSFilter) validateFilterURL(urlStr string) (err error) {
|
||||||
|
|
||||||
u, err := url.ParseRequestURI(urlStr)
|
u, err := url.ParseRequestURI(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't wrap the error since it's informative enough as is.
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s := u.Scheme; s != aghhttp.SchemeHTTP && s != aghhttp.SchemeHTTPS {
|
err = urlutil.ValidateHTTPURL(u)
|
||||||
return &url.Error{
|
if err != nil {
|
||||||
Op: "Check scheme",
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
URL: urlStr,
|
return err
|
||||||
Err: fmt.Errorf("only %v allowed", []string{
|
|
||||||
aghhttp.SchemeHTTP,
|
|
||||||
aghhttp.SchemeHTTPS,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -3,11 +3,12 @@ package rulelist
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/urlfilter"
|
"github.com/AdguardTeam/urlfilter"
|
||||||
"github.com/AdguardTeam/urlfilter/filterlist"
|
"github.com/AdguardTeam/urlfilter/filterlist"
|
||||||
"github.com/c2h5oh/datasize"
|
"github.com/c2h5oh/datasize"
|
||||||
|
@ -18,6 +19,9 @@ import (
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Merge with [TextEngine] in some way?
|
// TODO(a.garipov): Merge with [TextEngine] in some way?
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
|
// logger is used to log the operation of the engine and its refreshes.
|
||||||
|
logger *slog.Logger
|
||||||
|
|
||||||
// mu protects engine and storage.
|
// mu protects engine and storage.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): See if anything else should be protected.
|
// TODO(a.garipov): See if anything else should be protected.
|
||||||
|
@ -29,8 +33,7 @@ type Engine struct {
|
||||||
// storage is the filtering-rule storage. It is saved here to close it.
|
// storage is the filtering-rule storage. It is saved here to close it.
|
||||||
storage *filterlist.RuleStorage
|
storage *filterlist.RuleStorage
|
||||||
|
|
||||||
// name is the human-readable name of the engine, like "allowed", "blocked",
|
// name is the human-readable name of the engine.
|
||||||
// or "custom".
|
|
||||||
name string
|
name string
|
||||||
|
|
||||||
// filters is the data about rule filters in this engine.
|
// filters is the data about rule filters in this engine.
|
||||||
|
@ -40,12 +43,15 @@ type Engine struct {
|
||||||
// EngineConfig is the configuration for rule-list filtering engines created by
|
// EngineConfig is the configuration for rule-list filtering engines created by
|
||||||
// combining refreshable filters.
|
// combining refreshable filters.
|
||||||
type EngineConfig struct {
|
type EngineConfig struct {
|
||||||
// Name is the human-readable name of this engine, like "allowed",
|
// Logger is used to log the operation of the engine. It must not be nil.
|
||||||
// "blocked", or "custom".
|
Logger *slog.Logger
|
||||||
|
|
||||||
|
// name is the human-readable name of the engine; see [EngineNameAllow] and
|
||||||
|
// similar constants.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Filters is the data about rule lists in this engine. There must be no
|
// Filters is the data about rule lists in this engine. There must be no
|
||||||
// other references to the elements of this slice.
|
// other references to the items of this slice. Each item must not be nil.
|
||||||
Filters []*Filter
|
Filters []*Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +59,7 @@ type EngineConfig struct {
|
||||||
// refreshed, so a refresh should be performed before use.
|
// refreshed, so a refresh should be performed before use.
|
||||||
func NewEngine(c *EngineConfig) (e *Engine) {
|
func NewEngine(c *EngineConfig) (e *Engine) {
|
||||||
return &Engine{
|
return &Engine{
|
||||||
|
logger: c.Logger,
|
||||||
mu: &sync.RWMutex{},
|
mu: &sync.RWMutex{},
|
||||||
name: c.Name,
|
name: c.Name,
|
||||||
filters: c.Filters,
|
filters: c.Filters,
|
||||||
|
@ -85,7 +92,7 @@ func (e *Engine) FilterRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
// currentEngine returns the current filtering engine.
|
// currentEngine returns the current filtering engine.
|
||||||
func (e *Engine) currentEngine() (enging *urlfilter.DNSEngine) {
|
func (e *Engine) currentEngine() (engine *urlfilter.DNSEngine) {
|
||||||
e.mu.RLock()
|
e.mu.RLock()
|
||||||
defer e.mu.RUnlock()
|
defer e.mu.RUnlock()
|
||||||
|
|
||||||
|
@ -96,7 +103,7 @@ func (e *Engine) currentEngine() (enging *urlfilter.DNSEngine) {
|
||||||
// parseBuf, cli, cacheDir, and maxSize are used for updates of rule-list
|
// parseBuf, cli, cacheDir, and maxSize are used for updates of rule-list
|
||||||
// filters; see [Filter.Refresh].
|
// filters; see [Filter.Refresh].
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Unexport and test in an internal test or through enigne
|
// TODO(a.garipov): Unexport and test in an internal test or through engine
|
||||||
// tests.
|
// tests.
|
||||||
func (e *Engine) Refresh(
|
func (e *Engine) Refresh(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@ -115,20 +122,20 @@ func (e *Engine) Refresh(
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(filtersToRefresh) == 0 {
|
if len(filtersToRefresh) == 0 {
|
||||||
log.Info("filtering: updating engine %q: no rule-list filters", e.name)
|
e.logger.InfoContext(ctx, "updating: no rule-list filters")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
engRefr := &engineRefresh{
|
engRefr := &engineRefresh{
|
||||||
|
logger: e.logger,
|
||||||
httpCli: cli,
|
httpCli: cli,
|
||||||
cacheDir: cacheDir,
|
cacheDir: cacheDir,
|
||||||
engineName: e.name,
|
|
||||||
parseBuf: parseBuf,
|
parseBuf: parseBuf,
|
||||||
maxSize: maxSize,
|
maxSize: maxSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleLists, errs := engRefr.process(ctx, e.filters)
|
ruleLists, errs := engRefr.process(ctx, filtersToRefresh)
|
||||||
if isOneTimeoutError(errs) {
|
if isOneTimeoutError(errs) {
|
||||||
// Don't wrap the error since it's informative enough as is.
|
// Don't wrap the error since it's informative enough as is.
|
||||||
return err
|
return err
|
||||||
|
@ -141,14 +148,14 @@ func (e *Engine) Refresh(
|
||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.resetStorage(storage)
|
e.resetStorage(ctx, storage)
|
||||||
|
|
||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetStorage sets e.storage and e.engine and closes the previous storage.
|
// resetStorage sets e.storage and e.engine and closes the previous storage.
|
||||||
// Errors from closing the previous storage are logged.
|
// Errors from closing the previous storage are logged.
|
||||||
func (e *Engine) resetStorage(storage *filterlist.RuleStorage) {
|
func (e *Engine) resetStorage(ctx context.Context, storage *filterlist.RuleStorage) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
@ -161,7 +168,7 @@ func (e *Engine) resetStorage(storage *filterlist.RuleStorage) {
|
||||||
|
|
||||||
err := prevStorage.Close()
|
err := prevStorage.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("filtering: engine %q: closing old storage: %s", e.name, err)
|
e.logger.WarnContext(ctx, "closing old storage", slogutil.KeyError, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +186,9 @@ func isOneTimeoutError(errs []error) (ok bool) {
|
||||||
|
|
||||||
// engineRefresh represents a single ongoing engine refresh.
|
// engineRefresh represents a single ongoing engine refresh.
|
||||||
type engineRefresh struct {
|
type engineRefresh struct {
|
||||||
|
logger *slog.Logger
|
||||||
httpCli *http.Client
|
httpCli *http.Client
|
||||||
cacheDir string
|
cacheDir string
|
||||||
engineName string
|
|
||||||
parseBuf []byte
|
parseBuf []byte
|
||||||
maxSize datasize.ByteSize
|
maxSize datasize.ByteSize
|
||||||
}
|
}
|
||||||
|
@ -216,12 +223,12 @@ func (r *engineRefresh) process(
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
|
|
||||||
// Also log immediately, since the update can take a lot of time.
|
// Also log immediately, since the update can take a lot of time.
|
||||||
log.Error(
|
r.logger.ErrorContext(
|
||||||
"filtering: updating engine %q: rule list %s from url %q: %s\n",
|
ctx,
|
||||||
r.engineName,
|
"updating rule list",
|
||||||
f.uid,
|
"uid", f.uid,
|
||||||
f.url,
|
"url", f.url,
|
||||||
err,
|
slogutil.KeyError, err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,17 +244,17 @@ func (r *engineRefresh) processFilter(ctx context.Context, f *Filter) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
if prevChecksum == parseRes.Checksum {
|
if prevChecksum == parseRes.Checksum {
|
||||||
log.Info("filtering: engine %q: filter %q: no change", r.engineName, f.uid)
|
r.logger.InfoContext(ctx, "no change in filter", "uid", f.uid)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(
|
r.logger.InfoContext(
|
||||||
"filtering: updated engine %q: filter %q: %d bytes, %d rules",
|
ctx,
|
||||||
r.engineName,
|
"filter updated",
|
||||||
f.uid,
|
"uid", f.uid,
|
||||||
parseRes.BytesWritten,
|
"bytes", parseRes.BytesWritten,
|
||||||
parseRes.RulesCount,
|
"rules", parseRes.RulesCount,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||||
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/AdguardTeam/urlfilter"
|
"github.com/AdguardTeam/urlfilter"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
@ -13,6 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEngine_Refresh(t *testing.T) {
|
func TestEngine_Refresh(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
cacheDir := t.TempDir()
|
cacheDir := t.TempDir()
|
||||||
|
|
||||||
fileURL, srvURL := newFilterLocations(t, cacheDir, testRuleTextBlocked, testRuleTextBlocked2)
|
fileURL, srvURL := newFilterLocations(t, cacheDir, testRuleTextBlocked, testRuleTextBlocked2)
|
||||||
|
@ -21,6 +24,7 @@ func TestEngine_Refresh(t *testing.T) {
|
||||||
httpFlt := newFilter(t, srvURL, "HTTP Filter")
|
httpFlt := newFilter(t, srvURL, "HTTP Filter")
|
||||||
|
|
||||||
eng := rulelist.NewEngine(&rulelist.EngineConfig{
|
eng := rulelist.NewEngine(&rulelist.EngineConfig{
|
||||||
|
Logger: slogutil.NewDiscardLogger(),
|
||||||
Name: "Engine",
|
Name: "Engine",
|
||||||
Filters: []*rulelist.Filter{fileFlt, httpFlt},
|
Filters: []*rulelist.Filter{fileFlt, httpFlt},
|
||||||
})
|
})
|
||||||
|
|
|
@ -105,7 +105,7 @@ func NewFilter(c *FilterConfig) (f *Filter, err error) {
|
||||||
// buffer used to parse information from the data. cli and maxSize are only
|
// buffer used to parse information from the data. cli and maxSize are only
|
||||||
// used when f is a URL-based list.
|
// used when f is a URL-based list.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Unexport and test in an internal test or through enigne
|
// TODO(a.garipov): Unexport and test in an internal test or through engine
|
||||||
// tests.
|
// tests.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Consider not returning parseRes.
|
// TODO(a.garipov): Consider not returning parseRes.
|
||||||
|
|
|
@ -8,12 +8,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFilter_Refresh(t *testing.T) {
|
func TestFilter_Refresh(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
cacheDir := t.TempDir()
|
cacheDir := t.TempDir()
|
||||||
uid := rulelist.MustNewUID()
|
uid := rulelist.MustNewUID()
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ func TestFilter_Refresh(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
name: "file",
|
name: "file",
|
||||||
url: &url.URL{
|
url: &url.URL{
|
||||||
Scheme: "file",
|
Scheme: urlutil.SchemeFile,
|
||||||
Path: fileURL.Path,
|
Path: fileURL.Path,
|
||||||
},
|
},
|
||||||
wantNewErrMsg: "",
|
wantNewErrMsg: "",
|
||||||
|
@ -49,6 +52,8 @@ func TestFilter_Refresh(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
f, err := rulelist.NewFilter(&rulelist.FilterConfig{
|
f, err := rulelist.NewFilter(&rulelist.FilterConfig{
|
||||||
URL: tc.url,
|
URL: tc.url,
|
||||||
Name: tc.name,
|
Name: tc.name,
|
||||||
|
|
|
@ -71,3 +71,10 @@ var _ fmt.Stringer = UID{}
|
||||||
func (id UID) String() (s string) {
|
func (id UID) String() (s string) {
|
||||||
return uuid.UUID(id).String()
|
return uuid.UUID(id).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common engine names.
|
||||||
|
const (
|
||||||
|
EngineNameAllow = "allow"
|
||||||
|
EngineNameBlock = "block"
|
||||||
|
EngineNameCustom = "custom"
|
||||||
|
)
|
||||||
|
|
|
@ -6,20 +6,16 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
testutil.DiscardLogOutput(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// testTimeout is the common timeout for tests.
|
// testTimeout is the common timeout for tests.
|
||||||
const testTimeout = 1 * time.Second
|
const testTimeout = 1 * time.Second
|
||||||
|
|
||||||
|
@ -31,6 +27,7 @@ const testTitle = "Test Title"
|
||||||
|
|
||||||
// Common rule texts for tests.
|
// Common rule texts for tests.
|
||||||
const (
|
const (
|
||||||
|
testRuleTextAllowed = "||allowed.example^\n"
|
||||||
testRuleTextBadTab = "||bad-tab-and-comment.example^\t# A comment.\n"
|
testRuleTextBadTab = "||bad-tab-and-comment.example^\t# A comment.\n"
|
||||||
testRuleTextBlocked = "||blocked.example^\n"
|
testRuleTextBlocked = "||blocked.example^\n"
|
||||||
testRuleTextBlocked2 = "||blocked-2.example^\n"
|
testRuleTextBlocked2 = "||blocked-2.example^\n"
|
||||||
|
@ -79,8 +76,16 @@ func newFilterLocations(
|
||||||
fileData string,
|
fileData string,
|
||||||
httpData string,
|
httpData string,
|
||||||
) (fileURL, srvURL *url.URL) {
|
) (fileURL, srvURL *url.URL) {
|
||||||
filePath := filepath.Join(cacheDir, "initial.txt")
|
t.Helper()
|
||||||
err := os.WriteFile(filePath, []byte(fileData), 0o644)
|
|
||||||
|
f, err := os.CreateTemp(cacheDir, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = f.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
filePath := f.Name()
|
||||||
|
err = os.WriteFile(filePath, []byte(fileData), 0o644)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
||||||
|
@ -88,7 +93,7 @@ func newFilterLocations(
|
||||||
})
|
})
|
||||||
|
|
||||||
fileURL = &url.URL{
|
fileURL = &url.URL{
|
||||||
Scheme: "file",
|
Scheme: urlutil.SchemeFile,
|
||||||
Path: filePath,
|
Path: filePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
112
internal/filtering/rulelist/storage.go
Normal file
112
internal/filtering/rulelist/storage.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package rulelist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
|
"github.com/c2h5oh/datasize"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Storage contains the main filtering engines, including the allowlist, the
|
||||||
|
// blocklist, and the user's custom filtering rules.
|
||||||
|
type Storage struct {
|
||||||
|
// refreshMu makes sure that only one update takes place at a time.
|
||||||
|
refreshMu *sync.Mutex
|
||||||
|
|
||||||
|
allow *Engine
|
||||||
|
block *Engine
|
||||||
|
custom *TextEngine
|
||||||
|
httpCli *http.Client
|
||||||
|
cacheDir string
|
||||||
|
parseBuf []byte
|
||||||
|
maxSize datasize.ByteSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageConfig is the configuration for the filtering-engine storage.
|
||||||
|
type StorageConfig struct {
|
||||||
|
// Logger is used to log the operation of the storage. It must not be nil.
|
||||||
|
Logger *slog.Logger
|
||||||
|
|
||||||
|
// HTTPClient is the HTTP client used to perform updates of rule lists.
|
||||||
|
// It must not be nil.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// CacheDir is the path to the directory used to cache rule-list files.
|
||||||
|
// It must be set.
|
||||||
|
CacheDir string
|
||||||
|
|
||||||
|
// AllowFilters are the filtering-rule lists used to exclude domain names
|
||||||
|
// from the filtering. Each item must not be nil.
|
||||||
|
AllowFilters []*Filter
|
||||||
|
|
||||||
|
// BlockFilters are the filtering-rule lists used to block domain names.
|
||||||
|
// Each item must not be nil.
|
||||||
|
BlockFilters []*Filter
|
||||||
|
|
||||||
|
// CustomRules contains custom rules of the user. They have priority over
|
||||||
|
// both allow- and blacklist rules.
|
||||||
|
CustomRules []string
|
||||||
|
|
||||||
|
// MaxRuleListTextSize is the maximum size of a rule-list file. It must be
|
||||||
|
// greater than zero.
|
||||||
|
MaxRuleListTextSize datasize.ByteSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStorage creates a new filtering-engine storage. The engines are not
|
||||||
|
// refreshed, so a refresh should be performed before use.
|
||||||
|
func NewStorage(c *StorageConfig) (s *Storage, err error) {
|
||||||
|
custom, err := NewTextEngine(&TextEngineConfig{
|
||||||
|
Name: EngineNameCustom,
|
||||||
|
Rules: c.CustomRules,
|
||||||
|
ID: URLFilterIDCustom,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating custom engine: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Storage{
|
||||||
|
refreshMu: &sync.Mutex{},
|
||||||
|
allow: NewEngine(&EngineConfig{
|
||||||
|
Logger: c.Logger.With("engine", EngineNameAllow),
|
||||||
|
Name: EngineNameAllow,
|
||||||
|
Filters: c.AllowFilters,
|
||||||
|
}),
|
||||||
|
block: NewEngine(&EngineConfig{
|
||||||
|
Logger: c.Logger.With("engine", EngineNameBlock),
|
||||||
|
Name: EngineNameBlock,
|
||||||
|
Filters: c.BlockFilters,
|
||||||
|
}),
|
||||||
|
custom: custom,
|
||||||
|
httpCli: c.HTTPClient,
|
||||||
|
cacheDir: c.CacheDir,
|
||||||
|
parseBuf: make([]byte, DefaultRuleBufSize),
|
||||||
|
maxSize: c.MaxRuleListTextSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the underlying rule-list engines.
|
||||||
|
func (s *Storage) Close() (err error) {
|
||||||
|
// Don't wrap the errors since they are informative enough as is.
|
||||||
|
return errors.Join(
|
||||||
|
s.allow.Close(),
|
||||||
|
s.block.Close(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh updates all engines in s.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Refresh allow and block separately?
|
||||||
|
func (s *Storage) Refresh(ctx context.Context) (err error) {
|
||||||
|
s.refreshMu.Lock()
|
||||||
|
defer s.refreshMu.Unlock()
|
||||||
|
|
||||||
|
// Don't wrap the errors since they are informative enough as is.
|
||||||
|
return errors.Join(
|
||||||
|
s.allow.Refresh(ctx, s.parseBuf, s.httpCli, s.cacheDir, s.maxSize),
|
||||||
|
s.block.Refresh(ctx, s.parseBuf, s.httpCli, s.cacheDir, s.maxSize),
|
||||||
|
)
|
||||||
|
}
|
49
internal/filtering/rulelist/storage_test.go
Normal file
49
internal/filtering/rulelist/storage_test.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package rulelist_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering/rulelist"
|
||||||
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
|
"github.com/c2h5oh/datasize"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStorage_Refresh(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cacheDir := t.TempDir()
|
||||||
|
|
||||||
|
allowedFileURL, _ := newFilterLocations(t, cacheDir, testRuleTextAllowed, "")
|
||||||
|
allowedFlt := newFilter(t, allowedFileURL, "Allowed 1")
|
||||||
|
|
||||||
|
blockedFileURL, _ := newFilterLocations(t, cacheDir, testRuleTextBlocked, "")
|
||||||
|
blockedFlt := newFilter(t, blockedFileURL, "Blocked 1")
|
||||||
|
|
||||||
|
strg, err := rulelist.NewStorage(&rulelist.StorageConfig{
|
||||||
|
Logger: slogutil.NewDiscardLogger(),
|
||||||
|
HTTPClient: &http.Client{
|
||||||
|
Timeout: testTimeout,
|
||||||
|
},
|
||||||
|
CacheDir: cacheDir,
|
||||||
|
AllowFilters: []*rulelist.Filter{
|
||||||
|
allowedFlt,
|
||||||
|
},
|
||||||
|
BlockFilters: []*rulelist.Filter{
|
||||||
|
blockedFlt,
|
||||||
|
},
|
||||||
|
CustomRules: []string{
|
||||||
|
testRuleTextBlocked2,
|
||||||
|
},
|
||||||
|
MaxRuleListTextSize: 1 * datasize.KB,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
testutil.CleanupAndRequireSuccess(t, strg.Close)
|
||||||
|
|
||||||
|
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||||
|
err = strg.Refresh(ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -20,15 +20,15 @@ type TextEngine struct {
|
||||||
// storage is the filtering-rule storage. It is saved here to close it.
|
// storage is the filtering-rule storage. It is saved here to close it.
|
||||||
storage *filterlist.RuleStorage
|
storage *filterlist.RuleStorage
|
||||||
|
|
||||||
// name is the human-readable name of the engine, like "custom".
|
// name is the human-readable name of the engine.
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TextEngineConfig is the configuration for a rule-list filtering engine
|
// TextEngineConfig is the configuration for a rule-list filtering engine
|
||||||
// created from a filtering rule text.
|
// created from a filtering rule text.
|
||||||
type TextEngineConfig struct {
|
type TextEngineConfig struct {
|
||||||
// Name is the human-readable name of this engine, like "allowed",
|
// name is the human-readable name of the engine; see [EngineNameAllow] and
|
||||||
// "blocked", or "custom".
|
// similar constants.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Rules is the text of the filtering rules for this engine.
|
// Rules is the text of the filtering rules for this engine.
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTextEngine(t *testing.T) {
|
func TestNewTextEngine(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
eng, err := rulelist.NewTextEngine(&rulelist.TextEngineConfig{
|
eng, err := rulelist.NewTextEngine(&rulelist.TextEngineConfig{
|
||||||
Name: "RulesEngine",
|
Name: "RulesEngine",
|
||||||
Rules: []string{
|
Rules: []string{
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/httphdr"
|
"github.com/AdguardTeam/golibs/httphdr"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -376,7 +377,7 @@ func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (proceed bool)
|
||||||
//
|
//
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin.
|
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin.
|
||||||
originURL := &url.URL{
|
originURL := &url.URL{
|
||||||
Scheme: aghhttp.SchemeHTTP,
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: r.Host,
|
Host: r.Host,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +396,7 @@ func httpsURL(u *url.URL, host string, portHTTPS uint16) (redirectURL *url.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &url.URL{
|
return &url.URL{
|
||||||
Scheme: aghhttp.SchemeHTTPS,
|
Scheme: urlutil.SchemeHTTPS,
|
||||||
Host: hostPort,
|
Host: hostPort,
|
||||||
Path: u.Path,
|
Path: u.Path,
|
||||||
RawQuery: u.RawQuery,
|
RawQuery: u.RawQuery,
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/ameshkov/dnscrypt/v2"
|
"github.com/ameshkov/dnscrypt/v2"
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
@ -371,7 +372,7 @@ func getDNSEncryption() (de dnsEncryption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
de.https = (&url.URL{
|
de.https = (&url.URL{
|
||||||
Scheme: "https",
|
Scheme: urlutil.SchemeHTTPS,
|
||||||
Host: addr,
|
Host: addr,
|
||||||
Path: "/dns-query",
|
Path: "/dns-query",
|
||||||
}).String()
|
}).String()
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
|
||||||
|
@ -42,6 +41,7 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/AdguardTeam/golibs/osutil"
|
"github.com/AdguardTeam/golibs/osutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -605,7 +605,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) {
|
||||||
fatalOnError(errors.Annotate(err, "getting executable path: %w"))
|
fatalOnError(errors.Annotate(err, "getting executable path: %w"))
|
||||||
|
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "https",
|
Scheme: urlutil.SchemeHTTPS,
|
||||||
// TODO(a.garipov): Make configurable.
|
// TODO(a.garipov): Make configurable.
|
||||||
Host: "static.adtidy.org",
|
Host: "static.adtidy.org",
|
||||||
Path: path.Join("adguardhome", version.Channel(), "version.json"),
|
Path: path.Join("adguardhome", version.Channel(), "version.json"),
|
||||||
|
@ -936,12 +936,12 @@ func printHTTPAddresses(proto string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
port := config.HTTPConfig.Address.Port()
|
port := config.HTTPConfig.Address.Port()
|
||||||
if proto == aghhttp.SchemeHTTPS {
|
if proto == urlutil.SchemeHTTPS {
|
||||||
port = tlsConf.PortHTTPS
|
port = tlsConf.PortHTTPS
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(e.burkov): Inspect and perhaps merge with the previous condition.
|
// TODO(e.burkov): Inspect and perhaps merge with the previous condition.
|
||||||
if proto == aghhttp.SchemeHTTPS && tlsConf.ServerName != "" {
|
if proto == urlutil.SchemeHTTPS && tlsConf.ServerName != "" {
|
||||||
printWebAddrs(proto, tlsConf.ServerName, tlsConf.PortHTTPS)
|
printWebAddrs(proto, tlsConf.ServerName, tlsConf.PortHTTPS)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/httphdr"
|
"github.com/AdguardTeam/golibs/httphdr"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"howett.net/plist"
|
"howett.net/plist"
|
||||||
)
|
)
|
||||||
|
@ -84,7 +84,7 @@ func encodeMobileConfig(d *dnsSettings, clientID string) ([]byte, error) {
|
||||||
case dnsProtoHTTPS:
|
case dnsProtoHTTPS:
|
||||||
dspName = fmt.Sprintf("%s DoH", d.ServerName)
|
dspName = fmt.Sprintf("%s DoH", d.ServerName)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: aghhttp.SchemeHTTPS,
|
Scheme: urlutil.SchemeHTTPS,
|
||||||
Host: d.ServerName,
|
Host: d.ServerName,
|
||||||
Path: path.Join("/dns-query", clientID),
|
Path: path.Join("/dns-query", clientID),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/kardianos/service"
|
"github.com/kardianos/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ AdGuard Home is successfully installed and will automatically start on boot.
|
||||||
There are a few more things that must be configured before you can use it.
|
There are a few more things that must be configured before you can use it.
|
||||||
Click on the link below and follow the Installation Wizard steps to finish setup.
|
Click on the link below and follow the Installation Wizard steps to finish setup.
|
||||||
AdGuard Home is now available at the following addresses:`)
|
AdGuard Home is now available at the following addresses:`)
|
||||||
printHTTPAddresses(aghhttp.SchemeHTTP)
|
printHTTPAddresses(urlutil.SchemeHTTP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/updater"
|
"github.com/AdguardTeam/AdGuardHome/internal/updater"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/AdguardTeam/golibs/netutil/httputil"
|
"github.com/AdguardTeam/golibs/netutil/httputil"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
"github.com/quic-go/quic-go/http3"
|
"github.com/quic-go/quic-go/http3"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
|
@ -192,7 +192,7 @@ func (web *webAPI) start() {
|
||||||
|
|
||||||
// this loop is used as an ability to change listening host and/or port
|
// this loop is used as an ability to change listening host and/or port
|
||||||
for !web.httpsServer.inShutdown {
|
for !web.httpsServer.inShutdown {
|
||||||
printHTTPAddresses(aghhttp.SchemeHTTP)
|
printHTTPAddresses(urlutil.SchemeHTTP)
|
||||||
errs := make(chan error, 2)
|
errs := make(chan error, 2)
|
||||||
|
|
||||||
// Use an h2c handler to support unencrypted HTTP/2, e.g. for proxies.
|
// Use an h2c handler to support unencrypted HTTP/2, e.g. for proxies.
|
||||||
|
@ -286,7 +286,7 @@ func (web *webAPI) tlsServerLoop() {
|
||||||
WriteTimeout: web.conf.WriteTimeout,
|
WriteTimeout: web.conf.WriteTimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
printHTTPAddresses(aghhttp.SchemeHTTPS)
|
printHTTPAddresses(urlutil.SchemeHTTPS)
|
||||||
|
|
||||||
if web.conf.serveHTTP3 {
|
if web.conf.serveHTTP3 {
|
||||||
go web.mustStartHTTP3(addr)
|
go web.mustStartHTTP3(addr)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -49,7 +50,7 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) {
|
||||||
|
|
||||||
_, addr := newTestServer(t, confMgr)
|
_, addr := newTestServer(t, confMgr)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
Path: websvc.PathV1SettingsDNS,
|
Path: websvc.PathV1SettingsDNS,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -45,7 +46,7 @@ func TestService_HandlePatchSettingsHTTP(t *testing.T) {
|
||||||
|
|
||||||
_, addr := newTestServer(t, confMgr)
|
_, addr := newTestServer(t, confMgr)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
Path: websvc.PathV1SettingsHTTP,
|
Path: websvc.PathV1SettingsHTTP,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -69,7 +70,7 @@ func TestService_HandleGetSettingsAll(t *testing.T) {
|
||||||
|
|
||||||
_, addr := newTestServer(t, confMgr)
|
_, addr := newTestServer(t, confMgr)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
Path: websvc.PathV1SettingsAll,
|
Path: websvc.PathV1SettingsAll,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +18,7 @@ func TestService_handleGetV1SystemInfo(t *testing.T) {
|
||||||
confMgr := newConfigManager()
|
confMgr := newConfigManager()
|
||||||
_, addr := newTestServer(t, confMgr)
|
_, addr := newTestServer(t, confMgr)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
Path: websvc.PathV1SystemInfo,
|
Path: websvc.PathV1SystemInfo,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil/fakefs"
|
"github.com/AdguardTeam/golibs/testutil/fakefs"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -181,7 +182,7 @@ func TestService_Start_getHealthCheck(t *testing.T) {
|
||||||
confMgr := newConfigManager()
|
confMgr := newConfigManager()
|
||||||
_, addr := newTestServer(t, confMgr)
|
_, addr := newTestServer(t, confMgr)
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "http",
|
Scheme: urlutil.SchemeHTTP,
|
||||||
Host: addr.String(),
|
Host: addr.String(),
|
||||||
Path: websvc.PathHealthCheck,
|
Path: websvc.PathHealthCheck,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue