copy.go 3.5 KB

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