mirror of
https://github.com/moby/moby.git
synced 2025-04-18 20:44:11 +03:00
In situations where an empty ID was passed, the client would construct an invalid API endpoint URL, which either resulted in the "not found" handler being hit (resulting in a "page not found" error), or even the wrong endpoint being hit if the client follows redirects. For example, `/containers/<empty id>/json` (inspect) redirects to `/containers/json` (docker ps)) Given that empty IDs should never be expected (especially if they're part of the API URL path), we can validate these and return early. Its worth noting that a few methods already had an error in place; those methods were related to the situation mentioned above, where (e.g.) an "inspect" would redirect to a "list" endpoint. The existing errors, for convenience, mimicked a "not found" error; this patch changes such errors to an "Invalid Parameter" instead, which is more correct, but it could be a breaking change for some edge cases where users parsed the output; git grep 'objectNotFoundError{' client/config_inspect.go: return swarm.Config{}, nil, objectNotFoundError{object: "config", id: id} client/container_inspect.go: return container.InspectResponse{}, nil, objectNotFoundError{object: "container", id: containerID} client/container_inspect.go: return container.InspectResponse{}, objectNotFoundError{object: "container", id: containerID} client/distribution_inspect.go: return distributionInspect, objectNotFoundError{object: "distribution", id: imageRef} client/image_inspect.go: return image.InspectResponse{}, nil, objectNotFoundError{object: "image", id: imageID} client/network_inspect.go: return network.Inspect{}, nil, objectNotFoundError{object: "network", id: networkID} client/node_inspect.go: return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID} client/plugin_inspect.go: return nil, nil, objectNotFoundError{object: "plugin", id: name} client/secret_inspect.go: return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id} client/service_inspect.go: return swarm.Service{}, nil, objectNotFoundError{object: "service", id: serviceID} client/task_inspect.go: return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID} client/volume_inspect.go: return volume.Volume{}, nil, objectNotFoundError{object: "volume", id: volumeID} Two such errors are still left, as "ID or name" would probably be confusing, but perhaps we can use a more generic error to include those as well (e.g. "invalid <object> reference: value is empty"); client/distribution_inspect.go: return distributionInspect, objectNotFoundError{object: "distribution", id: imageRef} client/image_inspect.go: return image.InspectResponse{}, nil, objectNotFoundError{object: "image", id: imageID} Before this patch: docker container start "" Error response from daemon: page not found Error: failed to start containers: docker container start " " Error response from daemon: No such container: Error: failed to start containers: With this patch: docker container start "" invalid container name or ID: value is empty Error: failed to start containers: docker container start " " invalid container name or ID: value is empty Error: failed to start containers: Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
package client // import "github.com/docker/docker/client"
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types/registry"
|
|
"github.com/docker/docker/errdefs"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func TestPluginPushError(t *testing.T) {
|
|
client := &Client{
|
|
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
|
}
|
|
|
|
_, err := client.PluginPush(context.Background(), "plugin_name", "")
|
|
assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
|
|
|
|
_, err = client.PluginPush(context.Background(), "", "")
|
|
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
|
|
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
|
|
|
_, err = client.PluginPush(context.Background(), " ", "")
|
|
assert.Check(t, is.ErrorType(err, errdefs.IsInvalidParameter))
|
|
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
|
}
|
|
|
|
func TestPluginPush(t *testing.T) {
|
|
expectedURL := "/plugins/plugin_name"
|
|
|
|
client := &Client{
|
|
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
|
if !strings.HasPrefix(req.URL.Path, expectedURL) {
|
|
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
|
|
}
|
|
if req.Method != http.MethodPost {
|
|
return nil, fmt.Errorf("expected POST method, got %s", req.Method)
|
|
}
|
|
auth := req.Header.Get(registry.AuthHeader)
|
|
if auth != "authtoken" {
|
|
return nil, fmt.Errorf("invalid auth header: expected 'authtoken', got %s", auth)
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(bytes.NewReader([]byte(""))),
|
|
}, nil
|
|
}),
|
|
}
|
|
|
|
_, err := client.PluginPush(context.Background(), "plugin_name", "authtoken")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|