Skip to content

Commit db9cc91

Browse files
author
Josh Hawn
committed
api/server: StatPath, ArchivePath, ExtractToDir
Adds http handlers for new API endpoints: GET ContainersArchivePath Return a Tar Archive of the contents at the specified location in a container. Deprecates POST ContainersCopy. Use a HEAD request to stat the resource. PUT ContainersExtractToDir Extract the Tar Archive from the request body to the directory at the specified location inside a container. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
1 parent c32dde5 commit db9cc91

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

api/server/server.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht
13091309
return nil
13101310
}
13111311

1312+
// postContainersCopy is deprecated in favor of getContainersArchivePath.
13121313
func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
13131314
if vars == nil {
13141315
return fmt.Errorf("Missing parameter")
@@ -1348,6 +1349,104 @@ func (s *Server) postContainersCopy(version version.Version, w http.ResponseWrit
13481349
return nil
13491350
}
13501351

1352+
// // Encode the stat to JSON, base64 encode, and place in a header.
1353+
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
1354+
statJSON, err := json.Marshal(stat)
1355+
if err != nil {
1356+
return err
1357+
}
1358+
1359+
header.Set(
1360+
"X-Docker-Container-Path-Stat",
1361+
base64.StdEncoding.EncodeToString(statJSON),
1362+
)
1363+
1364+
return nil
1365+
}
1366+
1367+
func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1368+
if vars == nil {
1369+
return fmt.Errorf("Missing parameter")
1370+
}
1371+
if err := parseForm(r); err != nil {
1372+
return err
1373+
}
1374+
1375+
name := vars["name"]
1376+
path := r.Form.Get("path")
1377+
1378+
switch {
1379+
case name == "":
1380+
return fmt.Errorf("bad parameter: 'name' cannot be empty")
1381+
case path == "":
1382+
return fmt.Errorf("bad parameter: 'path' cannot be empty")
1383+
}
1384+
1385+
stat, err := s.daemon.ContainerStatPath(name, path)
1386+
if err != nil {
1387+
return err
1388+
}
1389+
1390+
return setContainerPathStatHeader(stat, w.Header())
1391+
}
1392+
1393+
func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1394+
if vars == nil {
1395+
return fmt.Errorf("Missing parameter")
1396+
}
1397+
if err := parseForm(r); err != nil {
1398+
return err
1399+
}
1400+
1401+
name := vars["name"]
1402+
path := r.Form.Get("path")
1403+
1404+
switch {
1405+
case name == "":
1406+
return fmt.Errorf("bad parameter: 'name' cannot be empty")
1407+
case path == "":
1408+
return fmt.Errorf("bad parameter: 'path' cannot be empty")
1409+
}
1410+
1411+
tarArchive, stat, err := s.daemon.ContainerArchivePath(name, path)
1412+
if err != nil {
1413+
return err
1414+
}
1415+
defer tarArchive.Close()
1416+
1417+
if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
1418+
return err
1419+
}
1420+
1421+
w.Header().Set("Content-Type", "application/x-tar")
1422+
_, err = io.Copy(w, tarArchive)
1423+
1424+
return err
1425+
}
1426+
1427+
func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
1428+
if vars == nil {
1429+
return fmt.Errorf("Missing parameter")
1430+
}
1431+
if err := parseForm(r); err != nil {
1432+
return err
1433+
}
1434+
1435+
name := vars["name"]
1436+
path := r.Form.Get("path")
1437+
1438+
noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
1439+
1440+
switch {
1441+
case name == "":
1442+
return fmt.Errorf("bad parameter: 'name' cannot be empty")
1443+
case path == "":
1444+
return fmt.Errorf("bad parameter: 'path' cannot be empty")
1445+
}
1446+
1447+
return s.daemon.ContainerExtractToDir(name, path, noOverwriteDirNonDir, r.Body)
1448+
}
1449+
13511450
func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
13521451
if err := parseForm(r); err != nil {
13531452
return err
@@ -1536,6 +1635,9 @@ func createRouter(s *Server) *mux.Router {
15361635
ProfilerSetup(r, "/debug/")
15371636
}
15381637
m := map[string]map[string]HttpApiFunc{
1638+
"HEAD": {
1639+
"/containers/{name:.*}/archive": s.headContainersArchive,
1640+
},
15391641
"GET": {
15401642
"/_ping": s.ping,
15411643
"/events": s.getEvents,
@@ -1557,6 +1659,7 @@ func createRouter(s *Server) *mux.Router {
15571659
"/containers/{name:.*}/stats": s.getContainersStats,
15581660
"/containers/{name:.*}/attach/ws": s.wsContainersAttach,
15591661
"/exec/{id:.*}/json": s.getExecByID,
1662+
"/containers/{name:.*}/archive": s.getContainersArchive,
15601663
},
15611664
"POST": {
15621665
"/auth": s.postAuth,
@@ -1582,6 +1685,9 @@ func createRouter(s *Server) *mux.Router {
15821685
"/exec/{name:.*}/resize": s.postContainerExecResize,
15831686
"/containers/{name:.*}/rename": s.postContainerRename,
15841687
},
1688+
"PUT": {
1689+
"/containers/{name:.*}/archive": s.putContainersArchive,
1690+
},
15851691
"DELETE": {
15861692
"/containers/{name:.*}": s.deleteContainers,
15871693
"/images/{name:.*}": s.deleteImages,

api/types/types.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ type CopyConfig struct {
128128
Resource string
129129
}
130130

131-
// ContainerPathStat is used to encode the response from
132-
// GET /containers/{name:.*}/stat-path
131+
// ContainerPathStat is used to encode the header from
132+
// GET /containers/{name:.*}/archive
133+
// "name" is the file or directory name.
134+
// "path" is the absolute path to the resource in the container.
133135
type ContainerPathStat struct {
134136
Name string `json:"name"`
135137
Path string `json:"path"`

0 commit comments

Comments
 (0)