1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/api/server/router/container/copy.go

146 lines
3.7 KiB
Go
Raw Normal View History

package container // import "github.com/docker/docker/api/server/router/container"
import (
"compress/flate"
"compress/gzip"
"context"
"encoding/base64"
"encoding/json"
API: properly handle invalid JSON to return a 400 status The API did not treat invalid JSON payloads as a 400 error, as a result returning a 500 error; Before this change, an invalid JSON body would return a 500 error; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 500 Internal Server Error < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:55:20 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.54.0 > Accept: */* > Content-Type: application/json > < HTTP/1.1 500 Internal Server Error < Api-Version: 1.38 < Content-Length: 18 < Content-Type: application/json < Date: Mon, 05 Nov 2018 12:00:18 GMT < Docker-Experimental: true < Ostype: linux < Server: Docker/18.06.1-ce (linux) < {"message":"EOF"} ``` After this change, a 400 is returned; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:57:15 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:59:22 GMT < Content-Length: 49 < {"message":"got EOF while reading request body"} ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-05 14:50:33 +01:00
"errors"
"io"
"net/http"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/versions"
API: properly handle invalid JSON to return a 400 status The API did not treat invalid JSON payloads as a 400 error, as a result returning a 500 error; Before this change, an invalid JSON body would return a 500 error; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 500 Internal Server Error < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:55:20 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.54.0 > Accept: */* > Content-Type: application/json > < HTTP/1.1 500 Internal Server Error < Api-Version: 1.38 < Content-Length: 18 < Content-Type: application/json < Date: Mon, 05 Nov 2018 12:00:18 GMT < Docker-Experimental: true < Ostype: linux < Server: Docker/18.06.1-ce (linux) < {"message":"EOF"} ``` After this change, a 400 is returned; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:57:15 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:59:22 GMT < Content-Length: 49 < {"message":"got EOF while reading request body"} ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-05 14:50:33 +01:00
"github.com/docker/docker/errdefs"
gddohttputil "github.com/golang/gddo/httputil"
)
type pathError struct{}
func (pathError) Error() string {
return "Path cannot be empty"
}
func (pathError) InvalidParameter() {}
// postContainersCopy is deprecated in favor of getContainersArchive.
func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
// Deprecated since 1.8, Errors out since 1.12
version := httputils.VersionFromContext(ctx)
if versions.GreaterThanOrEqualTo(version, "1.24") {
w.WriteHeader(http.StatusNotFound)
return nil
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
cfg := types.CopyConfig{}
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
API: properly handle invalid JSON to return a 400 status The API did not treat invalid JSON payloads as a 400 error, as a result returning a 500 error; Before this change, an invalid JSON body would return a 500 error; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 500 Internal Server Error < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:55:20 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.54.0 > Accept: */* > Content-Type: application/json > < HTTP/1.1 500 Internal Server Error < Api-Version: 1.38 < Content-Length: 18 < Content-Type: application/json < Date: Mon, 05 Nov 2018 12:00:18 GMT < Docker-Experimental: true < Ostype: linux < Server: Docker/18.06.1-ce (linux) < {"message":"EOF"} ``` After this change, a 400 is returned; ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" \ -d '{invalid json' ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > Content-Length: 13 > * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:57:15 GMT < Content-Length: 79 < {"message":"invalid character 'i' looking for beginning of object key string"} ``` Empty request: ```bash curl -v \ --unix-socket /var/run/docker.sock \ -X POST \ "http://localhost/v1.30/networks/create" \ -H "Content-Type: application/json" ``` ``` > POST /v1.30/networks/create HTTP/1.1 > Host: localhost > User-Agent: curl/7.52.1 > Accept: */* > Content-Type: application/json > < HTTP/1.1 400 Bad Request < Api-Version: 1.40 < Content-Type: application/json < Docker-Experimental: false < Ostype: linux < Server: Docker/dev (linux) < Date: Mon, 05 Nov 2018 11:59:22 GMT < Content-Length: 49 < {"message":"got EOF while reading request body"} ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2018-11-05 14:50:33 +01:00
if err == io.EOF {
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
}
return errdefs.InvalidParameter(err)
}
if cfg.Resource == "" {
return pathError{}
}
data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
if err != nil {
return err
}
defer data.Close()
w.Header().Set("Content-Type", "application/x-tar")
_, err = io.Copy(w, data)
return err
}
// // Encode the stat to JSON, base64 encode, and place in a header.
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
statJSON, err := json.Marshal(stat)
if err != nil {
return err
}
header.Set(
"X-Docker-Container-Path-Stat",
base64.StdEncoding.EncodeToString(statJSON),
)
return nil
}
func (s *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := httputils.ArchiveFormValues(r, vars)
if err != nil {
return err
}
stat, err := s.backend.ContainerStatPath(v.Name, v.Path)
if err != nil {
return err
}
return setContainerPathStatHeader(stat, w.Header())
}
func writeCompressedResponse(w http.ResponseWriter, r *http.Request, body io.Reader) error {
var cw io.Writer
switch gddohttputil.NegotiateContentEncoding(r, []string{"gzip", "deflate"}) {
case "gzip":
gw := gzip.NewWriter(w)
defer gw.Close()
cw = gw
w.Header().Set("Content-Encoding", "gzip")
case "deflate":
fw, err := flate.NewWriter(w, flate.DefaultCompression)
if err != nil {
return err
}
defer fw.Close()
cw = fw
w.Header().Set("Content-Encoding", "deflate")
default:
cw = w
}
_, err := io.Copy(cw, body)
return err
}
func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := httputils.ArchiveFormValues(r, vars)
if err != nil {
return err
}
tarArchive, stat, err := s.backend.ContainerArchivePath(v.Name, v.Path)
if err != nil {
return err
}
defer tarArchive.Close()
if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
return err
}
w.Header().Set("Content-Type", "application/x-tar")
return writeCompressedResponse(w, r, tarArchive)
}
func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := httputils.ArchiveFormValues(r, vars)
if err != nil {
return err
}
noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
copyUIDGID := httputils.BoolValue(r, "copyUIDGID")
return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
}