github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/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 }