github.com/moby/docker@v26.1.3+incompatible/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  	gddohttputil "github.com/golang/gddo/httputil"
    15  )
    16  
    17  // setContainerPathStatHeader encodes the stat to JSON, base64 encode, and place in a header.
    18  func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
    19  	statJSON, err := json.Marshal(stat)
    20  	if err != nil {
    21  		return err
    22  	}
    23  
    24  	header.Set(
    25  		"X-Docker-Container-Path-Stat",
    26  		base64.StdEncoding.EncodeToString(statJSON),
    27  	)
    28  
    29  	return nil
    30  }
    31  
    32  func (s *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    33  	v, err := httputils.ArchiveFormValues(r, vars)
    34  	if err != nil {
    35  		return err
    36  	}
    37  
    38  	stat, err := s.backend.ContainerStatPath(v.Name, v.Path)
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	return setContainerPathStatHeader(stat, w.Header())
    44  }
    45  
    46  func writeCompressedResponse(w http.ResponseWriter, r *http.Request, body io.Reader) error {
    47  	var cw io.Writer
    48  	switch gddohttputil.NegotiateContentEncoding(r, []string{"gzip", "deflate"}) {
    49  	case "gzip":
    50  		gw := gzip.NewWriter(w)
    51  		defer gw.Close()
    52  		cw = gw
    53  		w.Header().Set("Content-Encoding", "gzip")
    54  	case "deflate":
    55  		fw, err := flate.NewWriter(w, flate.DefaultCompression)
    56  		if err != nil {
    57  			return err
    58  		}
    59  		defer fw.Close()
    60  		cw = fw
    61  		w.Header().Set("Content-Encoding", "deflate")
    62  	default:
    63  		cw = w
    64  	}
    65  	_, err := io.Copy(cw, body)
    66  	return err
    67  }
    68  
    69  func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    70  	v, err := httputils.ArchiveFormValues(r, vars)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	tarArchive, stat, err := s.backend.ContainerArchivePath(v.Name, v.Path)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	defer tarArchive.Close()
    80  
    81  	if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
    82  		return err
    83  	}
    84  
    85  	w.Header().Set("Content-Type", "application/x-tar")
    86  	return writeCompressedResponse(w, r, tarArchive)
    87  }
    88  
    89  func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    90  	v, err := httputils.ArchiveFormValues(r, vars)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
    96  	copyUIDGID := httputils.BoolValue(r, "copyUIDGID")
    97  
    98  	return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
    99  }