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