copy.go 2.6 KB

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