github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/api/server/router/container/copy.go (about)

     1  package container // import "github.com/docker/docker/api/server/router/container"
     2  
     3  import (
     4  	"compress/flate"
     5  	"compress/gzip"
     6  	"context"
     7  	"encoding/base64"
     8  	"encoding/json"
     9  	"errors"
    10  	"io"
    11  	"net/http"
    12  
    13  	"github.com/docker/docker/api/server/httputils"
    14  	"github.com/docker/docker/api/types"
    15  	"github.com/docker/docker/api/types/versions"
    16  	"github.com/docker/docker/errdefs"
    17  	gddohttputil "github.com/golang/gddo/httputil"
    18  )
    19  
    20  type pathError struct{}
    21  
    22  func (pathError) Error() string {
    23  	return "Path cannot be empty"
    24  }
    25  
    26  func (pathError) InvalidParameter() {}
    27  
    28  // postContainersCopy is deprecated in favor of getContainersArchive.
    29  func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    30  	// Deprecated since 1.8, Errors out since 1.12
    31  	version := httputils.VersionFromContext(ctx)
    32  	if versions.GreaterThanOrEqualTo(version, "1.24") {
    33  		w.WriteHeader(http.StatusNotFound)
    34  		return nil
    35  	}
    36  	if err := httputils.CheckForJSON(r); err != nil {
    37  		return err
    38  	}
    39  
    40  	cfg := types.CopyConfig{}
    41  	if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
    42  		if err == io.EOF {
    43  			return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
    44  		}
    45  		return errdefs.InvalidParameter(err)
    46  	}
    47  
    48  	if cfg.Resource == "" {
    49  		return pathError{}
    50  	}
    51  
    52  	data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
    53  	if err != nil {
    54  		return err
    55  	}
    56  	defer data.Close()
    57  
    58  	w.Header().Set("Content-Type", "application/x-tar")
    59  	_, err = io.Copy(w, data)
    60  	return err
    61  }
    62  
    63  // // Encode the stat to JSON, base64 encode, and place in a header.
    64  func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
    65  	statJSON, err := json.Marshal(stat)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	header.Set(
    71  		"X-Docker-Container-Path-Stat",
    72  		base64.StdEncoding.EncodeToString(statJSON),
    73  	)
    74  
    75  	return nil
    76  }
    77  
    78  func (s *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    79  	v, err := httputils.ArchiveFormValues(r, vars)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	stat, err := s.backend.ContainerStatPath(v.Name, v.Path)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	return setContainerPathStatHeader(stat, w.Header())
    90  }
    91  
    92  func writeCompressedResponse(w http.ResponseWriter, r *http.Request, body io.Reader) error {
    93  	var cw io.Writer
    94  	switch gddohttputil.NegotiateContentEncoding(r, []string{"gzip", "deflate"}) {
    95  	case "gzip":
    96  		gw := gzip.NewWriter(w)
    97  		defer gw.Close()
    98  		cw = gw
    99  		w.Header().Set("Content-Encoding", "gzip")
   100  	case "deflate":
   101  		fw, err := flate.NewWriter(w, flate.DefaultCompression)
   102  		if err != nil {
   103  			return err
   104  		}
   105  		defer fw.Close()
   106  		cw = fw
   107  		w.Header().Set("Content-Encoding", "deflate")
   108  	default:
   109  		cw = w
   110  	}
   111  	_, err := io.Copy(cw, body)
   112  	return err
   113  }
   114  
   115  func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   116  	v, err := httputils.ArchiveFormValues(r, vars)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	tarArchive, stat, err := s.backend.ContainerArchivePath(v.Name, v.Path)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	defer tarArchive.Close()
   126  
   127  	if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
   128  		return err
   129  	}
   130  
   131  	w.Header().Set("Content-Type", "application/x-tar")
   132  	return writeCompressedResponse(w, r, tarArchive)
   133  }
   134  
   135  func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   136  	v, err := httputils.ArchiveFormValues(r, vars)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
   142  	copyUIDGID := httputils.BoolValue(r, "copyUIDGID")
   143  
   144  	return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
   145  }