diff --git a/go.mod b/go.mod index 77fb014d..5b8c57f4 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/AdguardTeam/dnsproxy v0.48.3 - github.com/AdguardTeam/golibs v0.13.1 + github.com/AdguardTeam/golibs v0.13.2 github.com/AdguardTeam/urlfilter v0.16.1 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.6 diff --git a/go.sum b/go.sum index ff541d8d..7e93f138 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/AdguardTeam/dnsproxy v0.48.3 h1:h9xgDSmd1MqsPFNApyaPVXolmSTtzOWOcfWvP github.com/AdguardTeam/dnsproxy v0.48.3/go.mod h1:Y7g7jRTd/u7+KJ/QvnGI2PCE8vnisp6EsW47/Sz0DZw= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= -github.com/AdguardTeam/golibs v0.13.1 h1:x6ChoXk2jborbCWJ01TyBAEY3SilHts0SCG7yjnf6Sc= -github.com/AdguardTeam/golibs v0.13.1/go.mod h1:7ylQLv2Lqsc3UW3jHoITynYk6Y1tYtgEMkR09ppfsN8= +github.com/AdguardTeam/golibs v0.13.2 h1:BPASsyQKmb+b8VnvsNOHp7bKfcZl9Z+Z2UhPjOiupSc= +github.com/AdguardTeam/golibs v0.13.2/go.mod h1:7ylQLv2Lqsc3UW3jHoITynYk6Y1tYtgEMkR09ppfsN8= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/urlfilter v0.16.1 h1:ZPi0rjqo8cQf2FVdzo6cqumNoHZx2KPXj2yZa1A5BBw= github.com/AdguardTeam/urlfilter v0.16.1/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= diff --git a/internal/aghhttp/aghhttp.go b/internal/aghhttp/aghhttp.go index bde0112a..b5878f92 100644 --- a/internal/aghhttp/aghhttp.go +++ b/internal/aghhttp/aghhttp.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/AdguardTeam/AdGuardHome/internal/version" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" ) @@ -52,7 +53,7 @@ const textPlainDeprMsg = `using this api with the text/plain content-type is dep // deprecation and removal of a plain-text API if the request is made with the // "text/plain" content-type. func WriteTextPlainDeprecated(w http.ResponseWriter, r *http.Request) (isPlainText bool) { - if r.Header.Get(HdrNameContentType) != HdrValTextPlain { + if r.Header.Get(httphdr.ContentType) != HdrValTextPlain { return false } @@ -72,7 +73,7 @@ func WriteJSONResponse(w http.ResponseWriter, r *http.Request, resp any) (err er // redefine the status code. func WriteJSONResponseCode(w http.ResponseWriter, r *http.Request, code int, resp any) (err error) { w.WriteHeader(code) - w.Header().Set(HdrNameContentType, HdrValApplicationJSON) + w.Header().Set(httphdr.ContentType, HdrValApplicationJSON) err = json.NewEncoder(w).Encode(resp) if err != nil { Error(r, w, http.StatusInternalServerError, "encoding resp: %s", err) diff --git a/internal/aghhttp/header.go b/internal/aghhttp/header.go index 0bfbcff2..eff50473 100644 --- a/internal/aghhttp/header.go +++ b/internal/aghhttp/header.go @@ -1,22 +1,6 @@ package aghhttp -// HTTP Headers - -// HTTP header name constants. -// -// TODO(a.garipov): Remove unused. -const ( - HdrNameAcceptEncoding = "Accept-Encoding" - HdrNameAccessControlAllowOrigin = "Access-Control-Allow-Origin" - HdrNameAltSvc = "Alt-Svc" - HdrNameContentEncoding = "Content-Encoding" - HdrNameContentType = "Content-Type" - HdrNameOrigin = "Origin" - HdrNameServer = "Server" - HdrNameTrailer = "Trailer" - HdrNameUserAgent = "User-Agent" - HdrNameVary = "Vary" -) +// HTTP headers // HTTP header value constants. const ( diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 144568d3..622f7cb8 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -18,6 +18,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/miekg/dns" @@ -122,7 +123,7 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) { s.conf = tc.conf() s.handleGetConfig(w, nil) - cType := w.Header().Get(aghhttp.HdrNameContentType) + cType := w.Header().Get(httphdr.ContentType) assert.Equal(t, aghhttp.HdrValApplicationJSON, cType) assert.JSONEq(t, string(caseWant), w.Body.String()) }) diff --git a/internal/home/auth.go b/internal/home/auth.go index 14d2f52b..7881a413 100644 --- a/internal/home/auth.go +++ b/internal/home/auth.go @@ -16,6 +16,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/timeutil" @@ -379,9 +380,9 @@ func (a *Auth) newCookie(req loginJSON, addr string) (c *http.Cookie, err error) // TODO(a.garipov): Support header Forwarded from RFC 7329. func realIP(r *http.Request) (ip net.IP, err error) { proxyHeaders := []string{ - "CF-Connecting-IP", - "True-Client-IP", - "X-Real-IP", + httphdr.CFConnectingIP, + httphdr.TrueClientIP, + httphdr.XRealIP, } for _, h := range proxyHeaders { @@ -394,7 +395,7 @@ func realIP(r *http.Request) (ip net.IP, err error) { // If none of the above yielded any results, get the leftmost IP address // from the X-Forwarded-For header. - s := r.Header.Get("X-Forwarded-For") + s := r.Header.Get(httphdr.XForwardedFor) ipStrs := strings.SplitN(s, ", ", 2) ip = net.ParseIP(ipStrs[0]) if ip != nil { @@ -435,7 +436,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { if rateLimiter := Context.auth.raleLimiter; rateLimiter != nil { if left := rateLimiter.check(remoteAddr); left > 0 { - w.Header().Set("Retry-After", strconv.Itoa(int(left.Seconds()))) + w.Header().Set(httphdr.RetryAfter, strconv.Itoa(int(left.Seconds()))) aghhttp.Error(r, w, http.StatusTooManyRequests, "auth: blocked for %s", left) return @@ -463,9 +464,9 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { http.SetCookie(w, cookie) h := w.Header() - h.Set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate") - h.Set("Pragma", "no-cache") - h.Set("Expires", "0") + h.Set(httphdr.CacheControl, "no-store, no-cache, must-revalidate, proxy-revalidate") + h.Set(httphdr.Pragma, "no-cache") + h.Set(httphdr.Expires, "0") aghhttp.OK(w) } @@ -476,7 +477,7 @@ func handleLogout(w http.ResponseWriter, r *http.Request) { if err != nil { // The only error that is returned from r.Cookie is [http.ErrNoCookie]. // The user is already logged out. - respHdr.Set("Location", "/login.html") + respHdr.Set(httphdr.Location, "/login.html") w.WriteHeader(http.StatusFound) return @@ -494,8 +495,8 @@ func handleLogout(w http.ResponseWriter, r *http.Request) { SameSite: http.SameSiteLaxMode, } - respHdr.Set("Location", "/login.html") - respHdr.Set("Set-Cookie", c.String()) + respHdr.Set(httphdr.Location, "/login.html") + respHdr.Set(httphdr.SetCookie, c.String()) w.WriteHeader(http.StatusFound) } @@ -543,7 +544,7 @@ func optionalAuthThird(w http.ResponseWriter, r *http.Request) (mustAuth bool) { log.Debug("auth: redirected to login page by GL-Inet submodule") } else { log.Debug("auth: redirected to login page") - w.Header().Set("Location", "/login.html") + w.Header().Set(httphdr.Location, "/login.html") w.WriteHeader(http.StatusFound) } } else { @@ -569,7 +570,7 @@ func optionalAuth( // Redirect to the dashboard if already authenticated. res := Context.auth.checkSession(cookie.Value) if res == checkSessionOK { - w.Header().Set("Location", "/") + w.Header().Set(httphdr.Location, "/") w.WriteHeader(http.StatusFound) return diff --git a/internal/home/auth_test.go b/internal/home/auth_test.go index 46767f7d..379d3fc5 100644 --- a/internal/home/auth_test.go +++ b/internal/home/auth_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -135,11 +136,11 @@ func TestAuthHTTP(t *testing.T) { handlerCalled = false handler2(&w, &r) assert.Equal(t, http.StatusFound, w.statusCode) - assert.NotEmpty(t, w.hdr.Get("Location")) + assert.NotEmpty(t, w.hdr.Get(httphdr.Location)) assert.False(t, handlerCalled) // go to login page - loginURL := w.hdr.Get("Location") + loginURL := w.hdr.Get(httphdr.Location) r.URL = &url.URL{Path: loginURL} handlerCalled = false handler2(&w, &r) @@ -153,13 +154,13 @@ func TestAuthHTTP(t *testing.T) { // get / handler2 = optionalAuth(handler) w.hdr = make(http.Header) - r.Header.Set("Cookie", cookie.String()) + r.Header.Set(httphdr.Cookie, cookie.String()) r.URL = &url.URL{Path: "/"} handlerCalled = false handler2(&w, &r) assert.True(t, handlerCalled) - r.Header.Del("Cookie") + r.Header.Del(httphdr.Cookie) // get / with basic auth handler2 = optionalAuth(handler) @@ -169,28 +170,28 @@ func TestAuthHTTP(t *testing.T) { handlerCalled = false handler2(&w, &r) assert.True(t, handlerCalled) - r.Header.Del("Authorization") + r.Header.Del(httphdr.Authorization) // get login page with a valid cookie - we're redirected to / handler2 = optionalAuth(handler) w.hdr = make(http.Header) - r.Header.Set("Cookie", cookie.String()) + r.Header.Set(httphdr.Cookie, cookie.String()) r.URL = &url.URL{Path: loginURL} handlerCalled = false handler2(&w, &r) - assert.NotEmpty(t, w.hdr.Get("Location")) + assert.NotEmpty(t, w.hdr.Get(httphdr.Location)) assert.False(t, handlerCalled) - r.Header.Del("Cookie") + r.Header.Del(httphdr.Cookie) // get login page with an invalid cookie handler2 = optionalAuth(handler) w.hdr = make(http.Header) - r.Header.Set("Cookie", "bad") + r.Header.Set(httphdr.Cookie, "bad") r.URL = &url.URL{Path: loginURL} handlerCalled = false handler2(&w, &r) assert.True(t, handlerCalled) - r.Header.Del("Cookie") + r.Header.Del(httphdr.Cookie) Context.auth.Close() } @@ -213,7 +214,7 @@ func TestRealIP(t *testing.T) { }, { name: "success_proxy", header: http.Header{ - textproto.CanonicalMIMEHeaderKey("X-Real-IP"): []string{"1.2.3.5"}, + textproto.CanonicalMIMEHeaderKey(httphdr.XRealIP): []string{"1.2.3.5"}, }, remoteAddr: remoteAddr, wantErrMsg: "", @@ -221,7 +222,7 @@ func TestRealIP(t *testing.T) { }, { name: "success_proxy_multiple", header: http.Header{ - textproto.CanonicalMIMEHeaderKey("X-Forwarded-For"): []string{ + textproto.CanonicalMIMEHeaderKey(httphdr.XForwardedFor): []string{ "1.2.3.6, 1.2.3.5", }, }, diff --git a/internal/home/control.go b/internal/home/control.go index 6e79b8b1..3f654b3c 100644 --- a/internal/home/control.go +++ b/internal/home/control.go @@ -13,6 +13,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/AdGuardHome/internal/version" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" "github.com/NYTimes/gziphandler" @@ -229,7 +230,7 @@ func modifiesData(m string) (ok bool) { func ensureContentType(w http.ResponseWriter, r *http.Request) (ok bool) { const statusUnsup = http.StatusUnsupportedMediaType - cType := r.Header.Get(aghhttp.HdrNameContentType) + cType := r.Header.Get(httphdr.ContentType) if r.ContentLength == 0 { if cType == "" { return true @@ -337,7 +338,7 @@ func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) { // default is 24 hours. if serveHTTP3 { altSvc := fmt.Sprintf(`h3=":%d"`, portHTTPS) - respHdr.Set(aghhttp.HdrNameAltSvc, altSvc) + respHdr.Set(httphdr.AltSvc, altSvc) } if r.TLS == nil && web.forceHTTPS { @@ -367,8 +368,8 @@ func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) { Host: r.Host, } - respHdr.Set(aghhttp.HdrNameAccessControlAllowOrigin, originURL.String()) - respHdr.Set(aghhttp.HdrNameVary, aghhttp.HdrNameOrigin) + respHdr.Set(httphdr.AccessControlAllowOrigin, originURL.String()) + respHdr.Set(httphdr.Vary, httphdr.Origin) return true } diff --git a/internal/home/mobileconfig.go b/internal/home/mobileconfig.go index e2f7283f..8d9deb56 100644 --- a/internal/home/mobileconfig.go +++ b/internal/home/mobileconfig.go @@ -11,6 +11,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" "github.com/google/uuid" "howett.net/plist" @@ -170,7 +171,7 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) { return } - w.Header().Set("Content-Type", "application/xml") + w.Header().Set(httphdr.ContentType, "application/xml") const ( dohContDisp = `attachment; filename=doh.mobileconfig` @@ -182,7 +183,7 @@ func handleMobileConfig(w http.ResponseWriter, r *http.Request, dnsp string) { contDisp = dotContDisp } - w.Header().Set("Content-Disposition", contDisp) + w.Header().Set(httphdr.ContentDisposition, contDisp) _, _ = w.Write(mobileconfig) } diff --git a/internal/next/websvc/json.go b/internal/next/websvc/json.go index fa2010a8..f7622b63 100644 --- a/internal/next/websvc/json.go +++ b/internal/next/websvc/json.go @@ -8,6 +8,7 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" ) @@ -99,8 +100,8 @@ func writeJSONOKResponse(w http.ResponseWriter, r *http.Request, v any) { func writeJSONResponse(w http.ResponseWriter, r *http.Request, v any, code int) { // TODO(a.garipov): Put some of these to a middleware. h := w.Header() - h.Set(aghhttp.HdrNameContentType, aghhttp.HdrValApplicationJSON) - h.Set(aghhttp.HdrNameServer, aghhttp.UserAgent()) + h.Set(httphdr.ContentType, aghhttp.HdrValApplicationJSON) + h.Set(httphdr.Server, aghhttp.UserAgent()) w.WriteHeader(code) diff --git a/internal/next/websvc/middleware.go b/internal/next/websvc/middleware.go index c87c57d5..c5a5e999 100644 --- a/internal/next/websvc/middleware.go +++ b/internal/next/websvc/middleware.go @@ -1,13 +1,18 @@ package websvc -import "net/http" +import ( + "net/http" + + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" + "github.com/AdguardTeam/golibs/httphdr" +) // Middlewares // jsonMw sets the content type of the response to application/json. func jsonMw(h http.Handler) (wrapped http.HandlerFunc) { f := func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") + w.Header().Set(httphdr.ContentType, aghhttp.HdrValApplicationJSON) h.ServeHTTP(w, r) } diff --git a/scripts/translations/main.go b/scripts/translations/main.go index a555be19..683f2be7 100644 --- a/scripts/translations/main.go +++ b/scripts/translations/main.go @@ -20,9 +20,11 @@ import ( "sync" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/httphdr" "github.com/AdguardTeam/golibs/log" "golang.org/x/exp/maps" "golang.org/x/exp/slices" @@ -491,10 +493,10 @@ func prepareMultipartMsg( }() h := make(textproto.MIMEHeader) - h.Set("Content-Type", "application/json") + h.Set(httphdr.ContentType, aghhttp.HdrValApplicationJSON) d := fmt.Sprintf("form-data; name=%q; filename=%q", "file", defaultBaseFile) - h.Set("Content-Disposition", d) + h.Set(httphdr.ContentDisposition, d) fw, err = w.CreatePart(h) if err != nil { @@ -523,7 +525,7 @@ func send(uriStr, cType string, buf *bytes.Buffer) (err error) { return fmt.Errorf("bad request: %w", err) } - req.Header.Set("Content-Type", cType) + req.Header.Set(httphdr.ContentType, cType) resp, err := client.Do(req) if err != nil {