2021-12-16 17:54:59 +00:00
|
|
|
// Package aghhttp provides some common methods to work with HTTP.
|
|
|
|
package aghhttp
|
|
|
|
|
|
|
|
import (
|
2022-09-29 17:04:26 +01:00
|
|
|
"encoding/json"
|
2021-12-16 17:54:59 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
|
2022-09-29 17:04:26 +01:00
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
2021-12-16 17:54:59 +00:00
|
|
|
"github.com/AdguardTeam/golibs/log"
|
|
|
|
)
|
|
|
|
|
2022-09-23 11:23:35 +01:00
|
|
|
// HTTP scheme constants.
|
|
|
|
const (
|
|
|
|
SchemeHTTP = "http"
|
|
|
|
SchemeHTTPS = "https"
|
|
|
|
)
|
|
|
|
|
2022-08-04 17:05:28 +01:00
|
|
|
// RegisterFunc is the function that sets the handler to handle the URL for the
|
|
|
|
// method.
|
|
|
|
//
|
|
|
|
// TODO(e.burkov, a.garipov): Get rid of it.
|
|
|
|
type RegisterFunc func(method, url string, handler http.HandlerFunc)
|
|
|
|
|
2021-12-16 17:54:59 +00:00
|
|
|
// OK responds with word OK.
|
|
|
|
func OK(w http.ResponseWriter) {
|
|
|
|
if _, err := io.WriteString(w, "OK\n"); err != nil {
|
|
|
|
log.Error("couldn't write body: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error writes formatted message to w and also logs it.
|
2022-08-03 12:36:18 +01:00
|
|
|
func Error(r *http.Request, w http.ResponseWriter, code int, format string, args ...any) {
|
2021-12-16 17:54:59 +00:00
|
|
|
text := fmt.Sprintf(format, args...)
|
2022-09-30 12:41:25 +01:00
|
|
|
log.Error("%s %s %s: %s", r.Method, r.Host, r.URL, text)
|
2021-12-16 17:54:59 +00:00
|
|
|
http.Error(w, text, code)
|
|
|
|
}
|
2022-09-29 17:04:26 +01:00
|
|
|
|
|
|
|
// UserAgent returns the ID of the service as a User-Agent string. It can also
|
|
|
|
// be used as the value of the Server HTTP header.
|
|
|
|
func UserAgent() (ua string) {
|
|
|
|
return fmt.Sprintf("AdGuardHome/%s", version.Version())
|
|
|
|
}
|
|
|
|
|
|
|
|
// textPlainDeprMsg is the message returned to API users when they try to use
|
|
|
|
// an API that used to accept "text/plain" but doesn't anymore.
|
|
|
|
const textPlainDeprMsg = `using this api with the text/plain content-type is deprecated; ` +
|
|
|
|
`use application/json`
|
|
|
|
|
|
|
|
// WriteTextPlainDeprecated responds to the request with a message about
|
|
|
|
// 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 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
Error(r, w, http.StatusUnsupportedMediaType, textPlainDeprMsg)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteJSONResponse sets the content-type header in w.Header() to
|
2022-10-04 12:35:10 +01:00
|
|
|
// "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.
|
2022-09-29 17:04:26 +01:00
|
|
|
func WriteJSONResponse(w http.ResponseWriter, r *http.Request, resp any) (err error) {
|
2022-10-04 12:35:10 +01:00
|
|
|
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)
|
2022-09-29 17:04:26 +01:00
|
|
|
w.Header().Set(HdrNameContentType, HdrValApplicationJSON)
|
|
|
|
err = json.NewEncoder(w).Encode(resp)
|
|
|
|
if err != nil {
|
|
|
|
Error(r, w, http.StatusInternalServerError, "encoding resp: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|