diff --git a/internal/aghhttp/aghhttp.go b/internal/aghhttp/aghhttp.go index f03ebf7d..bde0112a 100644 --- a/internal/aghhttp/aghhttp.go +++ b/internal/aghhttp/aghhttp.go @@ -62,9 +62,16 @@ func WriteTextPlainDeprecated(w http.ResponseWriter, r *http.Request) (isPlainTe } // WriteJSONResponse sets the content-type header in w.Header() to -// "application/json", encodes resp to w, calls Error on any returned error, and -// returns it as well. +// "application/json", writes a header with a "200 OK" status, encodes resp to +// w, calls [Error] on any returned error, and returns it as well. func WriteJSONResponse(w http.ResponseWriter, r *http.Request, resp any) (err error) { + return WriteJSONResponseCode(w, r, http.StatusOK, resp) +} + +// WriteJSONResponseCode is like [WriteJSONResponse] but adds the ability to +// 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) err = json.NewEncoder(w).Encode(resp) if err != nil { diff --git a/internal/dhcpd/http_unix.go b/internal/dhcpd/http_unix.go index de06431f..ab3ce318 100644 --- a/internal/dhcpd/http_unix.go +++ b/internal/dhcpd/http_unix.go @@ -78,18 +78,7 @@ func (s *server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) { status.Leases = s.Leases(LeasesDynamic) status.StaticLeases = s.Leases(LeasesStatic) - w.Header().Set("Content-Type", "application/json") - - err := json.NewEncoder(w).Encode(status) - if err != nil { - aghhttp.Error( - r, - w, - http.StatusInternalServerError, - "Unable to marshal DHCP status json: %s", - err, - ) - } + _ = aghhttp.WriteJSONResponse(w, r, status) } func (s *server) enableDHCP(ifaceName string) (code int, err error) { diff --git a/internal/dhcpd/http_windows.go b/internal/dhcpd/http_windows.go index 5f7f73c1..fda72d48 100644 --- a/internal/dhcpd/http_windows.go +++ b/internal/dhcpd/http_windows.go @@ -3,11 +3,10 @@ package dhcpd import ( - "encoding/json" "net/http" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghos" - "github.com/AdguardTeam/golibs/log" ) // jsonError is a generic JSON error response. @@ -25,15 +24,9 @@ type jsonError struct { // TODO(a.garipov): Either take the logger from the server after we've // refactored logging or make this not a method of *Server. func (s *server) notImplemented(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusNotImplemented) - - err := json.NewEncoder(w).Encode(&jsonError{ + _ = aghhttp.WriteJSONResponseCode(w, r, http.StatusNotImplemented, &jsonError{ Message: aghos.Unsupported("dhcp").Error(), }) - if err != nil { - log.Debug("writing 501 json response: %s", err) - } } // registerHandlers sets the handlers for DHCP HTTP API that always respond with diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index 489def36..b32cb01e 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -453,13 +453,7 @@ func (d *DNSFilter) ApplyBlockedServices(setts *Settings, list []string) { } func (d *DNSFilter) handleBlockedServicesAvailableServices(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(serviceIDs) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "encoding available services: %s", err) - - return - } + _ = aghhttp.WriteJSONResponse(w, r, serviceIDs) } func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Request) { @@ -467,13 +461,7 @@ func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Req list := d.Config.BlockedServices d.confLock.RUnlock() - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(list) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "encoding services: %s", err) - - return - } + _ = aghhttp.WriteJSONResponse(w, r, list) } func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Request) { diff --git a/internal/filtering/http.go b/internal/filtering/http.go index 50890f93..5c311c43 100644 --- a/internal/filtering/http.go +++ b/internal/filtering/http.go @@ -301,14 +301,7 @@ func (d *DNSFilter) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques return } - w.Header().Set("Content-Type", "application/json") - - err = json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) - - return - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } type filterJSON struct { @@ -361,17 +354,7 @@ func (d *DNSFilter) handleFilteringStatus(w http.ResponseWriter, r *http.Request resp.UserRules = d.UserRules d.filtersMu.RUnlock() - jsonVal, err := json.Marshal(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) - - return - } - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(jsonVal) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "http write: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } // Set filtering configuration @@ -473,11 +456,7 @@ func (d *DNSFilter) handleCheckHost(w http.ResponseWriter, r *http.Request) { } } - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "encoding response: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } // RegisterFilteringHandlers - register handlers diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index 8f0d5ebf..2c09728f 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -240,13 +240,7 @@ func (d *DNSFilter) handleRewriteList(w http.ResponseWriter, r *http.Request) { } d.confLock.Unlock() - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(arr) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) - - return - } + _ = aghhttp.WriteJSONResponse(w, r, arr) } func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) { diff --git a/internal/filtering/safebrowsing.go b/internal/filtering/safebrowsing.go index fe844977..c6b7c34c 100644 --- a/internal/filtering/safebrowsing.go +++ b/internal/filtering/safebrowsing.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "encoding/binary" "encoding/hex" - "encoding/json" "fmt" "net" "net/http" @@ -381,17 +380,13 @@ func (d *DNSFilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Req } func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(&struct { + resp := &struct { Enabled bool `json:"enabled"` }{ Enabled: d.Config.SafeBrowsingEnabled, - }) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) - - return } + + _ = aghhttp.WriteJSONResponse(w, r, resp) } func (d *DNSFilter) handleParentalEnable(w http.ResponseWriter, r *http.Request) { @@ -405,13 +400,11 @@ func (d *DNSFilter) handleParentalDisable(w http.ResponseWriter, r *http.Request } func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(&struct { + resp := &struct { Enabled bool `json:"enabled"` }{ Enabled: d.Config.ParentalEnabled, - }) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) } + + _ = aghhttp.WriteJSONResponse(w, r, resp) } diff --git a/internal/filtering/safesearch.go b/internal/filtering/safesearch.go index df2d2108..8b3dcb9b 100644 --- a/internal/filtering/safesearch.go +++ b/internal/filtering/safesearch.go @@ -5,7 +5,6 @@ import ( "context" "encoding/binary" "encoding/gob" - "encoding/json" "fmt" "net" "net/http" @@ -146,21 +145,13 @@ func (d *DNSFilter) handleSafeSearchDisable(w http.ResponseWriter, r *http.Reque } func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(&struct { + resp := &struct { Enabled bool `json:"enabled"` }{ Enabled: d.Config.SafeSearchEnabled, - }) - if err != nil { - aghhttp.Error( - r, - w, - http.StatusInternalServerError, - "Unable to write response json: %s", - err, - ) } + + _ = aghhttp.WriteJSONResponse(w, r, resp) } var safeSearchDomains = map[string]string{ diff --git a/internal/querylog/http.go b/internal/querylog/http.go index 11f62d0d..1fab138e 100644 --- a/internal/querylog/http.go +++ b/internal/querylog/http.go @@ -1,7 +1,6 @@ package querylog import ( - "encoding/json" "fmt" "net" "net/http" @@ -48,24 +47,7 @@ func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) { // convert log entries to JSON data := l.entriesToJSON(entries, oldest) - jsonVal, err := json.Marshal(data) - if err != nil { - aghhttp.Error( - r, - w, - http.StatusInternalServerError, - "Couldn't marshal data into json: %s", - err, - ) - - return - } - - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(jsonVal) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, data) } func (l *queryLog) handleQueryLogClear(_ http.ResponseWriter, _ *http.Request) { @@ -74,23 +56,13 @@ func (l *queryLog) handleQueryLogClear(_ http.ResponseWriter, _ *http.Request) { // Get configuration func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) { - resp := qlogConfig{} - resp.Enabled = l.conf.Enabled - resp.Interval = l.conf.RotationIvl.Hours() / 24 - resp.AnonymizeClientIP = l.conf.AnonymizeClientIP - - jsonVal, err := json.Marshal(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) - - return + resp := qlogConfig{ + Enabled: l.conf.Enabled, + Interval: l.conf.RotationIvl.Hours() / 24, + AnonymizeClientIP: l.conf.AnonymizeClientIP, } - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(jsonVal) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "http write: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } // AnonymizeIP masks ip to anonymize the client if the ip is a valid one. diff --git a/internal/stats/http.go b/internal/stats/http.go index ae980bf3..b06a7cdc 100644 --- a/internal/stats/http.go +++ b/internal/stats/http.go @@ -55,12 +55,7 @@ func (s *StatsCtx) handleStats(w http.ResponseWriter, r *http.Request) { return } - w.Header().Set("Content-Type", "application/json") - - err := json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } // configResp is the response to the GET /control/stats_info. @@ -71,13 +66,7 @@ type configResp struct { // handleStatsInfo handles requests to the GET /control/stats_info endpoint. func (s *StatsCtx) handleStatsInfo(w http.ResponseWriter, r *http.Request) { resp := configResp{IntervalDays: atomic.LoadUint32(&s.limitHours) / 24} - - w.Header().Set("Content-Type", "application/json") - - err := json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) - } + _ = aghhttp.WriteJSONResponse(w, r, resp) } // handleStatsConfig handles requests to the POST /control/stats_config