api: remove plain-text error-responses (api < v1.24)
Commit 322e2a7d05
changed the format of errors
returned by the API to be in JSON format for API v1.24. Older versions of
the API returned errors in plain-text format.
API v1.23 and older are deprecated, so we can remove support for plain-text
error responses.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
b3a0ff9944
commit
ffd877f948
3 changed files with 12 additions and 70 deletions
|
@ -1,34 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/server/httpstatus"
|
|
||||||
"github.com/docker/docker/api/server/httputils"
|
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/versions"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// makeErrorHandler makes an HTTP handler that decodes a Docker error and
|
|
||||||
// returns it in the response.
|
|
||||||
func makeErrorHandler(err error) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
statusCode := httpstatus.FromError(err)
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
if apiVersionSupportsJSONErrors(vars["version"]) {
|
|
||||||
response := &types.ErrorResponse{
|
|
||||||
Message: err.Error(),
|
|
||||||
}
|
|
||||||
_ = httputils.WriteJSON(w, statusCode, response)
|
|
||||||
} else {
|
|
||||||
http.Error(w, status.Convert(err).Message(), statusCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiVersionSupportsJSONErrors(version string) bool {
|
|
||||||
const firstAPIVersionWithJSONErrors = "1.23"
|
|
||||||
return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
|
|
||||||
}
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/docker/api/server/middleware"
|
"github.com/docker/docker/api/server/middleware"
|
||||||
"github.com/docker/docker/api/server/router"
|
"github.com/docker/docker/api/server/router"
|
||||||
"github.com/docker/docker/api/server/router/debug"
|
"github.com/docker/docker/api/server/router/debug"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||||
|
@ -57,19 +58,13 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
|
||||||
if statusCode >= 500 {
|
if statusCode >= 500 {
|
||||||
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||||
}
|
}
|
||||||
makeErrorHandler(err)(w, r)
|
_ = httputils.WriteJSON(w, statusCode, &types.ErrorResponse{
|
||||||
|
Message: err.Error(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}), operation).ServeHTTP
|
}), operation).ServeHTTP
|
||||||
}
|
}
|
||||||
|
|
||||||
type pageNotFoundError struct{}
|
|
||||||
|
|
||||||
func (pageNotFoundError) Error() string {
|
|
||||||
return "page not found"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pageNotFoundError) NotFound() {}
|
|
||||||
|
|
||||||
// CreateMux returns a new mux with all the routers registered.
|
// CreateMux returns a new mux with all the routers registered.
|
||||||
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
||||||
m := mux.NewRouter()
|
m := mux.NewRouter()
|
||||||
|
@ -91,7 +86,12 @@ func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
||||||
m.Path("/debug" + r.Path()).Handler(f)
|
m.Path("/debug" + r.Path()).Handler(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
notFoundHandler := makeErrorHandler(pageNotFoundError{})
|
notFoundHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_ = httputils.WriteJSON(w, http.StatusNotFound, &types.ErrorResponse{
|
||||||
|
Message: "page not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
||||||
m.NotFoundHandler = notFoundHandler
|
m.NotFoundHandler = notFoundHandler
|
||||||
m.MethodNotAllowedHandler = notFoundHandler
|
m.MethodNotAllowedHandler = notFoundHandler
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -62,9 +61,9 @@ func (s *DockerAPISuite) TestAPIClientVersionOldNotSupported(c *testing.T) {
|
||||||
defer body.Close()
|
defer body.Close()
|
||||||
assert.Equal(c, resp.StatusCode, http.StatusBadRequest)
|
assert.Equal(c, resp.StatusCode, http.StatusBadRequest)
|
||||||
expected := fmt.Sprintf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", version, testEnv.DaemonVersion.MinAPIVersion)
|
expected := fmt.Sprintf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", version, testEnv.DaemonVersion.MinAPIVersion)
|
||||||
content, err := io.ReadAll(body)
|
b, err := request.ReadBody(body)
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
assert.Equal(c, strings.TrimSpace(string(content)), expected)
|
assert.Equal(c, getErrorMessage(c, b), expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerAPISuite) TestAPIErrorJSON(c *testing.T) {
|
func (s *DockerAPISuite) TestAPIErrorJSON(c *testing.T) {
|
||||||
|
@ -77,19 +76,6 @@ func (s *DockerAPISuite) TestAPIErrorJSON(c *testing.T) {
|
||||||
assert.Equal(c, getErrorMessage(c, b), runconfig.ErrEmptyConfig.Error())
|
assert.Equal(c, getErrorMessage(c, b), runconfig.ErrEmptyConfig.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerAPISuite) TestAPIErrorPlainText(c *testing.T) {
|
|
||||||
// Windows requires API 1.25 or later. This test is validating a behaviour which was present
|
|
||||||
// in v1.23, but changed in 1.24, hence not applicable on Windows. See apiVersionSupportsJSONErrors
|
|
||||||
testRequires(c, DaemonIsLinux)
|
|
||||||
httpResp, body, err := request.Post(testutil.GetContext(c), "/v1.23/containers/create", request.JSONBody(struct{}{}))
|
|
||||||
assert.NilError(c, err)
|
|
||||||
assert.Equal(c, httpResp.StatusCode, http.StatusBadRequest)
|
|
||||||
assert.Assert(c, strings.Contains(httpResp.Header.Get("Content-Type"), "text/plain"))
|
|
||||||
b, err := request.ReadBody(body)
|
|
||||||
assert.NilError(c, err)
|
|
||||||
assert.Equal(c, strings.TrimSpace(string(b)), runconfig.ErrEmptyConfig.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DockerAPISuite) TestAPIErrorNotFoundJSON(c *testing.T) {
|
func (s *DockerAPISuite) TestAPIErrorNotFoundJSON(c *testing.T) {
|
||||||
// 404 is a different code path to normal errors, so test separately
|
// 404 is a different code path to normal errors, so test separately
|
||||||
httpResp, body, err := request.Get(testutil.GetContext(c), "/notfound", request.JSON)
|
httpResp, body, err := request.Get(testutil.GetContext(c), "/notfound", request.JSON)
|
||||||
|
@ -100,13 +86,3 @@ func (s *DockerAPISuite) TestAPIErrorNotFoundJSON(c *testing.T) {
|
||||||
assert.NilError(c, err)
|
assert.NilError(c, err)
|
||||||
assert.Equal(c, getErrorMessage(c, b), "page not found")
|
assert.Equal(c, getErrorMessage(c, b), "page not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DockerAPISuite) TestAPIErrorNotFoundPlainText(c *testing.T) {
|
|
||||||
httpResp, body, err := request.Get(testutil.GetContext(c), "/v1.23/notfound", request.JSON)
|
|
||||||
assert.NilError(c, err)
|
|
||||||
assert.Equal(c, httpResp.StatusCode, http.StatusNotFound)
|
|
||||||
assert.Assert(c, strings.Contains(httpResp.Header.Get("Content-Type"), "text/plain"))
|
|
||||||
b, err := request.ReadBody(body)
|
|
||||||
assert.NilError(c, err)
|
|
||||||
assert.Equal(c, strings.TrimSpace(string(b)), "page not found")
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue