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 }