Browse Source

Merge pull request #13698 from cpuguy83/split_api_routes_from_setup

Move api handlers to separate file
Tibor Vass 10 years ago
parent
commit
102724700b
7 changed files with 1400 additions and 1318 deletions
  1. 26 0
      api/server/auth.go
  2. 534 0
      api/server/container.go
  3. 115 0
      api/server/copy.go
  4. 174 0
      api/server/daemon.go
  5. 132 0
      api/server/exec.go
  6. 419 0
      api/server/image.go
  7. 0 1318
      api/server/server.go

+ 26 - 0
api/server/auth.go

@@ -0,0 +1,26 @@
+package server
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/pkg/version"
+)
+
+func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	var config *cliconfig.AuthConfig
+	err := json.NewDecoder(r.Body).Decode(&config)
+	r.Body.Close()
+	if err != nil {
+		return err
+	}
+	status, err := s.daemon.RegistryService.Auth(config)
+	if err != nil {
+		return err
+	}
+	return writeJSON(w, http.StatusOK, &types.AuthResponse{
+		Status: status,
+	})
+}

+ 534 - 0
api/server/container.go

@@ -0,0 +1,534 @@
+package server
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"golang.org/x/net/websocket"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/daemon"
+	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/pkg/version"
+	"github.com/docker/docker/runconfig"
+)
+
+func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	if version.LessThan("1.20") && runtime.GOOS != "windows" {
+		return getContainersByNameDownlevel(w, s, vars["name"])
+	}
+
+	containerJSON, err := s.daemon.ContainerInspect(vars["name"])
+	if err != nil {
+		return err
+	}
+	return writeJSON(w, http.StatusOK, containerJSON)
+}
+
+func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	config := &daemon.ContainersConfig{
+		All:     boolValue(r, "all"),
+		Size:    boolValue(r, "size"),
+		Since:   r.Form.Get("since"),
+		Before:  r.Form.Get("before"),
+		Filters: r.Form.Get("filters"),
+	}
+
+	if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
+		limit, err := strconv.Atoi(tmpLimit)
+		if err != nil {
+			return err
+		}
+		config.Limit = limit
+	}
+
+	containers, err := s.daemon.Containers(config)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, containers)
+}
+
+func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	stream := boolValueOrDefault(r, "stream", true)
+	var out io.Writer
+	if !stream {
+		w.Header().Set("Content-Type", "application/json")
+		out = w
+	} else {
+		out = ioutils.NewWriteFlusher(w)
+	}
+
+	var closeNotifier <-chan bool
+	if notifier, ok := w.(http.CloseNotifier); ok {
+		closeNotifier = notifier.CloseNotify()
+	}
+
+	config := &daemon.ContainerStatsConfig{
+		Stream:    stream,
+		OutStream: out,
+		Stop:      closeNotifier,
+	}
+
+	return s.daemon.ContainerStats(vars["name"], config)
+}
+
+func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	// Validate args here, because we can't return not StatusOK after job.Run() call
+	stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
+	if !(stdout || stderr) {
+		return fmt.Errorf("Bad parameters: you must choose at least one stream")
+	}
+
+	var since time.Time
+	if r.Form.Get("since") != "" {
+		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
+		if err != nil {
+			return err
+		}
+		since = time.Unix(s, 0)
+	}
+
+	var closeNotifier <-chan bool
+	if notifier, ok := w.(http.CloseNotifier); ok {
+		closeNotifier = notifier.CloseNotify()
+	}
+
+	c, err := s.daemon.Get(vars["name"])
+	if err != nil {
+		return err
+	}
+
+	outStream := ioutils.NewWriteFlusher(w)
+	// write an empty chunk of data (this is to ensure that the
+	// HTTP Response is sent immediatly, even if the container has
+	// not yet produced any data)
+	outStream.Write(nil)
+
+	logsConfig := &daemon.ContainerLogsConfig{
+		Follow:     boolValue(r, "follow"),
+		Timestamps: boolValue(r, "timestamps"),
+		Since:      since,
+		Tail:       r.Form.Get("tail"),
+		UseStdout:  stdout,
+		UseStderr:  stderr,
+		OutStream:  outStream,
+		Stop:       closeNotifier,
+	}
+
+	if err := s.daemon.ContainerLogs(c, logsConfig); err != nil {
+		fmt.Fprintf(w, "Error running logs job: %s\n", err)
+	}
+
+	return nil
+}
+
+func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	return s.daemon.ContainerExport(vars["name"], w)
+}
+
+func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	// If contentLength is -1, we can assumed chunked encoding
+	// or more technically that the length is unknown
+	// https://golang.org/src/pkg/net/http/request.go#L139
+	// net/http otherwise seems to swallow any headers related to chunked encoding
+	// including r.TransferEncoding
+	// allow a nil body for backwards compatibility
+	var hostConfig *runconfig.HostConfig
+	if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
+		if err := checkForJSON(r); err != nil {
+			return err
+		}
+
+		c, err := runconfig.DecodeHostConfig(r.Body)
+		if err != nil {
+			return err
+		}
+
+		hostConfig = c
+	}
+
+	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
+		if err.Error() == "Container already started" {
+			w.WriteHeader(http.StatusNotModified)
+			return nil
+		}
+		return err
+	}
+	w.WriteHeader(http.StatusNoContent)
+	return nil
+}
+
+func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	seconds, _ := strconv.Atoi(r.Form.Get("t"))
+
+	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
+		if err.Error() == "Container already stopped" {
+			w.WriteHeader(http.StatusNotModified)
+			return nil
+		}
+		return err
+	}
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	var sig uint64
+	name := vars["name"]
+
+	// If we have a signal, look at it. Otherwise, do nothing
+	if sigStr := r.Form.Get("signal"); sigStr != "" {
+		// Check if we passed the signal as a number:
+		// The largest legal signal is 31, so let's parse on 5 bits
+		sigN, err := strconv.ParseUint(sigStr, 10, 5)
+		if err != nil {
+			// The signal is not a number, treat it as a string (either like
+			// "KILL" or like "SIGKILL")
+			syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
+			if !ok {
+				return fmt.Errorf("Invalid signal: %s", sigStr)
+			}
+			sig = uint64(syscallSig)
+		} else {
+			sig = sigN
+		}
+
+		if sig == 0 {
+			return fmt.Errorf("Invalid signal: %s", sigStr)
+		}
+	}
+
+	if err := s.daemon.ContainerKill(name, sig); err != nil {
+		_, isStopped := err.(daemon.ErrContainerNotRunning)
+		// Return error that's not caused because the container is stopped.
+		// Return error if the container is not running and the api is >= 1.20
+		// to keep backwards compatibility.
+		if version.GreaterThanOrEqualTo("1.20") || !isStopped {
+			return fmt.Errorf("Cannot kill container %s: %v", name, err)
+		}
+	}
+
+	w.WriteHeader(http.StatusNoContent)
+	return nil
+}
+
+func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	timeout, _ := strconv.Atoi(r.Form.Get("t"))
+
+	if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
+		return err
+	}
+
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	if err := s.daemon.ContainerPause(vars["name"]); err != nil {
+		return err
+	}
+
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
+		return err
+	}
+
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
+		StatusCode: status,
+	})
+}
+
+func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	changes, err := s.daemon.ContainerChanges(vars["name"])
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, changes)
+}
+
+func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, procList)
+}
+
+func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	name := vars["name"]
+	newName := r.Form.Get("name")
+	if err := s.daemon.ContainerRename(name, newName); err != nil {
+		return err
+	}
+	w.WriteHeader(http.StatusNoContent)
+	return nil
+}
+
+func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if err := checkForJSON(r); err != nil {
+		return err
+	}
+	var (
+		warnings []string
+		name     = r.Form.Get("name")
+	)
+
+	config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
+	if err != nil {
+		return err
+	}
+	adjustCPUShares(version, hostConfig)
+
+	containerID, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{
+		ID:       containerID,
+		Warnings: warnings,
+	})
+}
+
+func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	name := vars["name"]
+	config := &daemon.ContainerRmConfig{
+		ForceRemove:  boolValue(r, "force"),
+		RemoveVolume: boolValue(r, "v"),
+		RemoveLink:   boolValue(r, "link"),
+	}
+
+	if err := s.daemon.ContainerRm(name, config); err != nil {
+		// Force a 404 for the empty string
+		if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
+			return fmt.Errorf("no such id: \"\"")
+		}
+		return err
+	}
+
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	height, err := strconv.Atoi(r.Form.Get("h"))
+	if err != nil {
+		return err
+	}
+	width, err := strconv.Atoi(r.Form.Get("w"))
+	if err != nil {
+		return err
+	}
+
+	return s.daemon.ContainerResize(vars["name"], height, width)
+}
+
+func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	cont, err := s.daemon.Get(vars["name"])
+	if err != nil {
+		return err
+	}
+
+	inStream, outStream, err := hijackServer(w)
+	if err != nil {
+		return err
+	}
+	defer closeStreams(inStream, outStream)
+
+	if _, ok := r.Header["Upgrade"]; ok {
+		fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
+	} else {
+		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
+	}
+
+	attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
+		InStream:  inStream,
+		OutStream: outStream,
+		UseStdin:  boolValue(r, "stdin"),
+		UseStdout: boolValue(r, "stdout"),
+		UseStderr: boolValue(r, "stderr"),
+		Logs:      boolValue(r, "logs"),
+		Stream:    boolValue(r, "stream"),
+	}
+
+	if err := s.daemon.ContainerAttachWithLogs(cont, attachWithLogsConfig); err != nil {
+		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
+	}
+
+	return nil
+}
+
+func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	cont, err := s.daemon.Get(vars["name"])
+	if err != nil {
+		return err
+	}
+
+	h := websocket.Handler(func(ws *websocket.Conn) {
+		defer ws.Close()
+
+		wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
+			InStream:  ws,
+			OutStream: ws,
+			ErrStream: ws,
+			Logs:      boolValue(r, "logs"),
+			Stream:    boolValue(r, "stream"),
+		}
+
+		if err := s.daemon.ContainerWsAttachWithLogs(cont, wsAttachWithLogsConfig); err != nil {
+			logrus.Errorf("Error attaching websocket: %s", err)
+		}
+	})
+	h.ServeHTTP(w, r)
+
+	return nil
+}

+ 115 - 0
api/server/copy.go

@@ -0,0 +1,115 @@
+package server
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"strings"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/version"
+)
+
+// postContainersCopy is deprecated in favor of getContainersArchivePath.
+func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	if err := checkForJSON(r); err != nil {
+		return err
+	}
+
+	cfg := types.CopyConfig{}
+	if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
+		return err
+	}
+
+	if cfg.Resource == "" {
+		return fmt.Errorf("Path cannot be empty")
+	}
+
+	data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
+	if err != nil {
+		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
+			w.WriteHeader(http.StatusNotFound)
+			return nil
+		}
+		if os.IsNotExist(err) {
+			return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
+		}
+		return err
+	}
+	defer data.Close()
+
+	w.Header().Set("Content-Type", "application/x-tar")
+	if _, err := io.Copy(w, data); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// // Encode the stat to JSON, base64 encode, and place in a header.
+func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
+	statJSON, err := json.Marshal(stat)
+	if err != nil {
+		return err
+	}
+
+	header.Set(
+		"X-Docker-Container-Path-Stat",
+		base64.StdEncoding.EncodeToString(statJSON),
+	)
+
+	return nil
+}
+
+func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	v, err := archiveFormValues(r, vars)
+	if err != nil {
+		return err
+	}
+
+	stat, err := s.daemon.ContainerStatPath(v.name, v.path)
+	if err != nil {
+		return err
+	}
+
+	return setContainerPathStatHeader(stat, w.Header())
+}
+
+func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	v, err := archiveFormValues(r, vars)
+	if err != nil {
+		return err
+	}
+
+	tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
+	if err != nil {
+		return err
+	}
+	defer tarArchive.Close()
+
+	if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
+		return err
+	}
+
+	w.Header().Set("Content-Type", "application/x-tar")
+	_, err = io.Copy(w, tarArchive)
+
+	return err
+}
+
+func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	v, err := archiveFormValues(r, vars)
+	if err != nil {
+		return err
+	}
+
+	noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
+	return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
+}

+ 174 - 0
api/server/daemon.go

@@ -0,0 +1,174 @@
+package server
+
+import (
+	"encoding/json"
+	"net/http"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/autogen/dockerversion"
+	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/parsers/filters"
+	"github.com/docker/docker/pkg/parsers/kernel"
+	"github.com/docker/docker/pkg/version"
+	"github.com/docker/docker/utils"
+)
+
+func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	v := &types.Version{
+		Version:    dockerversion.VERSION,
+		ApiVersion: api.Version,
+		GitCommit:  dockerversion.GITCOMMIT,
+		GoVersion:  runtime.Version(),
+		Os:         runtime.GOOS,
+		Arch:       runtime.GOARCH,
+		BuildTime:  dockerversion.BUILDTIME,
+	}
+
+	if version.GreaterThanOrEqualTo("1.19") {
+		v.Experimental = utils.ExperimentalBuild()
+	}
+
+	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
+		v.KernelVersion = kernelVersion.String()
+	}
+
+	return writeJSON(w, http.StatusOK, v)
+}
+
+func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	info, err := s.daemon.SystemInfo()
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, info)
+}
+
+func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	var since int64 = -1
+	if r.Form.Get("since") != "" {
+		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
+		if err != nil {
+			return err
+		}
+		since = s
+	}
+
+	var until int64 = -1
+	if r.Form.Get("until") != "" {
+		u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
+		if err != nil {
+			return err
+		}
+		until = u
+	}
+
+	timer := time.NewTimer(0)
+	timer.Stop()
+	if until > 0 {
+		dur := time.Unix(until, 0).Sub(time.Now())
+		timer = time.NewTimer(dur)
+	}
+
+	ef, err := filters.FromParam(r.Form.Get("filters"))
+	if err != nil {
+		return err
+	}
+
+	isFiltered := func(field string, filter []string) bool {
+		if len(field) == 0 {
+			return false
+		}
+		if len(filter) == 0 {
+			return false
+		}
+		for _, v := range filter {
+			if v == field {
+				return false
+			}
+			if strings.Contains(field, ":") {
+				image := strings.Split(field, ":")
+				if image[0] == v {
+					return false
+				}
+			}
+		}
+		return true
+	}
+
+	d := s.daemon
+	es := d.EventsService
+	w.Header().Set("Content-Type", "application/json")
+	outStream := ioutils.NewWriteFlusher(w)
+	outStream.Write(nil) // make sure response is sent immediately
+	enc := json.NewEncoder(outStream)
+
+	getContainerID := func(cn string) string {
+		c, err := d.Get(cn)
+		if err != nil {
+			return ""
+		}
+		return c.ID
+	}
+
+	sendEvent := func(ev *jsonmessage.JSONMessage) error {
+		//incoming container filter can be name,id or partial id, convert and replace as a full container id
+		for i, cn := range ef["container"] {
+			ef["container"][i] = getContainerID(cn)
+		}
+
+		if isFiltered(ev.Status, ef["event"]) || (isFiltered(ev.ID, ef["image"]) &&
+			isFiltered(ev.From, ef["image"])) || isFiltered(ev.ID, ef["container"]) {
+			return nil
+		}
+
+		return enc.Encode(ev)
+	}
+
+	current, l := es.Subscribe()
+	if since == -1 {
+		current = nil
+	}
+	defer es.Evict(l)
+	for _, ev := range current {
+		if ev.Time < since {
+			continue
+		}
+		if err := sendEvent(ev); err != nil {
+			return err
+		}
+	}
+
+	var closeNotify <-chan bool
+	if closeNotifier, ok := w.(http.CloseNotifier); ok {
+		closeNotify = closeNotifier.CloseNotify()
+	}
+
+	for {
+		select {
+		case ev := <-l:
+			jev, ok := ev.(*jsonmessage.JSONMessage)
+			if !ok {
+				continue
+			}
+			if err := sendEvent(jev); err != nil {
+				return err
+			}
+		case <-timer.C:
+			return nil
+		case <-closeNotify:
+			logrus.Debug("Client disconnected, stop sending events")
+			return nil
+		}
+	}
+}

+ 132 - 0
api/server/exec.go

@@ -0,0 +1,132 @@
+package server
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/docker/docker/pkg/version"
+	"github.com/docker/docker/runconfig"
+)
+
+func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter 'id'")
+	}
+
+	eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, eConfig)
+}
+
+func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if err := checkForJSON(r); err != nil {
+		return err
+	}
+	name := vars["name"]
+
+	execConfig := &runconfig.ExecConfig{}
+	if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
+		return err
+	}
+	execConfig.Container = name
+
+	if len(execConfig.Cmd) == 0 {
+		return fmt.Errorf("No exec command specified")
+	}
+
+	// Register an instance of Exec in container.
+	id, err := s.daemon.ContainerExecCreate(execConfig)
+	if err != nil {
+		logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
+		return err
+	}
+
+	return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
+		ID: id,
+	})
+}
+
+// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
+func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	var (
+		execName = vars["name"]
+		stdin    io.ReadCloser
+		stdout   io.Writer
+		stderr   io.Writer
+	)
+
+	execStartCheck := &types.ExecStartCheck{}
+	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
+		return err
+	}
+
+	if !execStartCheck.Detach {
+		// Setting up the streaming http interface.
+		inStream, outStream, err := hijackServer(w)
+		if err != nil {
+			return err
+		}
+		defer closeStreams(inStream, outStream)
+
+		var errStream io.Writer
+
+		if _, ok := r.Header["Upgrade"]; ok {
+			fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
+		} else {
+			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
+		}
+
+		if !execStartCheck.Tty {
+			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
+			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
+		}
+
+		stdin = inStream
+		stdout = outStream
+		stderr = errStream
+	}
+	// Now run the user process in container.
+
+	if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
+		logrus.Errorf("Error starting exec command in container %s: %s", execName, err)
+		return err
+	}
+	w.WriteHeader(http.StatusNoContent)
+
+	return nil
+}
+
+func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	height, err := strconv.Atoi(r.Form.Get("h"))
+	if err != nil {
+		return err
+	}
+	width, err := strconv.Atoi(r.Form.Get("w"))
+	if err != nil {
+		return err
+	}
+
+	return s.daemon.ContainerExecResize(vars["name"], height, width)
+}

+ 419 - 0
api/server/image.go

@@ -0,0 +1,419 @@
+package server
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"strings"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/builder"
+	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/graph"
+	"github.com/docker/docker/pkg/ioutils"
+	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/ulimit"
+	"github.com/docker/docker/pkg/version"
+	"github.com/docker/docker/runconfig"
+	"github.com/docker/docker/utils"
+)
+
+func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	if err := checkForJSON(r); err != nil {
+		return err
+	}
+
+	cname := r.Form.Get("container")
+
+	pause := boolValue(r, "pause")
+	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
+		pause = true
+	}
+
+	c, _, err := runconfig.DecodeContainerConfig(r.Body)
+	if err != nil && err != io.EOF { //Do not fail if body is empty.
+		return err
+	}
+
+	commitCfg := &builder.CommitConfig{
+		Pause:   pause,
+		Repo:    r.Form.Get("repo"),
+		Tag:     r.Form.Get("tag"),
+		Author:  r.Form.Get("author"),
+		Comment: r.Form.Get("comment"),
+		Changes: r.Form["changes"],
+		Config:  c,
+	}
+
+	imgID, err := builder.Commit(cname, s.daemon, commitCfg)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
+		ID: imgID,
+	})
+}
+
+// Creates an image from Pull or from Import
+func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	var (
+		image = r.Form.Get("fromImage")
+		repo  = r.Form.Get("repo")
+		tag   = r.Form.Get("tag")
+	)
+	authEncoded := r.Header.Get("X-Registry-Auth")
+	authConfig := &cliconfig.AuthConfig{}
+	if authEncoded != "" {
+		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
+		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
+			// for a pull it is not an error if no auth was given
+			// to increase compatibility with the existing api it is defaulting to be empty
+			authConfig = &cliconfig.AuthConfig{}
+		}
+	}
+
+	var (
+		err    error
+		output = ioutils.NewWriteFlusher(w)
+	)
+
+	w.Header().Set("Content-Type", "application/json")
+
+	if image != "" { //pull
+		if tag == "" {
+			image, tag = parsers.ParseRepositoryTag(image)
+		}
+		metaHeaders := map[string][]string{}
+		for k, v := range r.Header {
+			if strings.HasPrefix(k, "X-Meta-") {
+				metaHeaders[k] = v
+			}
+		}
+
+		imagePullConfig := &graph.ImagePullConfig{
+			MetaHeaders: metaHeaders,
+			AuthConfig:  authConfig,
+			OutStream:   output,
+		}
+
+		err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
+	} else { //import
+		if tag == "" {
+			repo, tag = parsers.ParseRepositoryTag(repo)
+		}
+
+		src := r.Form.Get("fromSrc")
+
+		// 'err' MUST NOT be defined within this block, we need any error
+		// generated from the download to be available to the output
+		// stream processing below
+		var newConfig *runconfig.Config
+		newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
+		if err != nil {
+			return err
+		}
+
+		err = s.daemon.Repositories().Import(src, repo, tag, r.Body, output, newConfig)
+	}
+	if err != nil {
+		if !output.Flushed() {
+			return err
+		}
+		sf := streamformatter.NewJSONStreamFormatter()
+		output.Write(sf.FormatError(err))
+	}
+
+	return nil
+}
+
+func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	metaHeaders := map[string][]string{}
+	for k, v := range r.Header {
+		if strings.HasPrefix(k, "X-Meta-") {
+			metaHeaders[k] = v
+		}
+	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	authConfig := &cliconfig.AuthConfig{}
+
+	authEncoded := r.Header.Get("X-Registry-Auth")
+	if authEncoded != "" {
+		// the new format is to handle the authConfig as a header
+		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
+		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
+			// to increase compatibility to existing api it is defaulting to be empty
+			authConfig = &cliconfig.AuthConfig{}
+		}
+	} else {
+		// the old format is supported for compatibility if there was no authConfig header
+		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
+			return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
+		}
+	}
+
+	name := vars["name"]
+	output := ioutils.NewWriteFlusher(w)
+	imagePushConfig := &graph.ImagePushConfig{
+		MetaHeaders: metaHeaders,
+		AuthConfig:  authConfig,
+		Tag:         r.Form.Get("tag"),
+		OutStream:   output,
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+
+	if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
+		if !output.Flushed() {
+			return err
+		}
+		sf := streamformatter.NewJSONStreamFormatter()
+		output.Write(sf.FormatError(err))
+	}
+	return nil
+}
+
+func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	w.Header().Set("Content-Type", "application/x-tar")
+
+	output := ioutils.NewWriteFlusher(w)
+	var names []string
+	if name, ok := vars["name"]; ok {
+		names = []string{name}
+	} else {
+		names = r.Form["names"]
+	}
+
+	if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
+		if !output.Flushed() {
+			return err
+		}
+		sf := streamformatter.NewJSONStreamFormatter()
+		output.Write(sf.FormatError(err))
+	}
+	return nil
+}
+
+func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	return s.daemon.Repositories().Load(r.Body, w)
+}
+
+func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	name := vars["name"]
+	force := boolValue(r, "force")
+	noprune := boolValue(r, "noprune")
+
+	list, err := s.daemon.ImageDelete(name, force, noprune)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, list)
+}
+
+func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, imageInspect)
+}
+
+func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	var (
+		authConfigs        = map[string]cliconfig.AuthConfig{}
+		authConfigsEncoded = r.Header.Get("X-Registry-Config")
+		buildConfig        = builder.NewBuildConfig()
+	)
+
+	if authConfigsEncoded != "" {
+		authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
+		if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
+			// for a pull it is not an error if no auth was given
+			// to increase compatibility with the existing api it is defaulting
+			// to be empty.
+		}
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+
+	if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
+		buildConfig.Remove = true
+	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
+		buildConfig.Remove = true
+	} else {
+		buildConfig.Remove = boolValue(r, "rm")
+	}
+	if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
+		buildConfig.Pull = true
+	}
+
+	output := ioutils.NewWriteFlusher(w)
+	buildConfig.Stdout = output
+	buildConfig.Context = r.Body
+
+	buildConfig.RemoteURL = r.FormValue("remote")
+	buildConfig.DockerfileName = r.FormValue("dockerfile")
+	buildConfig.RepoName = r.FormValue("t")
+	buildConfig.SuppressOutput = boolValue(r, "q")
+	buildConfig.NoCache = boolValue(r, "nocache")
+	buildConfig.ForceRemove = boolValue(r, "forcerm")
+	buildConfig.AuthConfigs = authConfigs
+	buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
+	buildConfig.Memory = int64ValueOrZero(r, "memory")
+	buildConfig.CPUShares = int64ValueOrZero(r, "cpushares")
+	buildConfig.CPUPeriod = int64ValueOrZero(r, "cpuperiod")
+	buildConfig.CPUQuota = int64ValueOrZero(r, "cpuquota")
+	buildConfig.CPUSetCpus = r.FormValue("cpusetcpus")
+	buildConfig.CPUSetMems = r.FormValue("cpusetmems")
+	buildConfig.CgroupParent = r.FormValue("cgroupparent")
+
+	var buildUlimits = []*ulimit.Ulimit{}
+	ulimitsJSON := r.FormValue("ulimits")
+	if ulimitsJSON != "" {
+		if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil {
+			return err
+		}
+		buildConfig.Ulimits = buildUlimits
+	}
+
+	// Job cancellation. Note: not all job types support this.
+	if closeNotifier, ok := w.(http.CloseNotifier); ok {
+		finished := make(chan struct{})
+		defer close(finished)
+		go func() {
+			select {
+			case <-finished:
+			case <-closeNotifier.CloseNotify():
+				logrus.Infof("Client disconnected, cancelling job: build")
+				buildConfig.Cancel()
+			}
+		}()
+	}
+
+	if err := builder.Build(s.daemon, buildConfig); err != nil {
+		// Do not write the error in the http output if it's still empty.
+		// This prevents from writing a 200(OK) when there is an interal error.
+		if !output.Flushed() {
+			return err
+		}
+		sf := streamformatter.NewJSONStreamFormatter()
+		w.Write(sf.FormatError(err))
+	}
+	return nil
+}
+
+func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+
+	// FIXME: The filter parameter could just be a match filter
+	images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, images)
+}
+
+func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	name := vars["name"]
+	history, err := s.daemon.Repositories().History(name)
+	if err != nil {
+		return err
+	}
+
+	return writeJSON(w, http.StatusOK, history)
+}
+
+func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	if vars == nil {
+		return fmt.Errorf("Missing parameter")
+	}
+
+	repo := r.Form.Get("repo")
+	tag := r.Form.Get("tag")
+	force := boolValue(r, "force")
+	name := vars["name"]
+	if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
+		return err
+	}
+	s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
+	w.WriteHeader(http.StatusCreated)
+	return nil
+}
+
+func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+	if err := parseForm(r); err != nil {
+		return err
+	}
+	var (
+		config      *cliconfig.AuthConfig
+		authEncoded = r.Header.Get("X-Registry-Auth")
+		headers     = map[string][]string{}
+	)
+
+	if authEncoded != "" {
+		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
+		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
+			// for a search it is not an error if no auth was given
+			// to increase compatibility with the existing api it is defaulting to be empty
+			config = &cliconfig.AuthConfig{}
+		}
+	}
+	for k, v := range r.Header {
+		if strings.HasPrefix(k, "X-Meta-") {
+			headers[k] = v
+		}
+	}
+	query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
+	if err != nil {
+		return err
+	}
+	return writeJSON(w, http.StatusOK, query.Results)
+}

+ 0 - 1318
api/server/server.go

@@ -2,7 +2,6 @@ package server
 
 
 import (
 import (
 	"crypto/tls"
 	"crypto/tls"
-	"encoding/base64"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -10,34 +9,16 @@ import (
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"runtime"
 	"runtime"
-	"strconv"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
-	"golang.org/x/net/websocket"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api"
-	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/autogen/dockerversion"
 	"github.com/docker/docker/autogen/dockerversion"
-	"github.com/docker/docker/builder"
-	"github.com/docker/docker/cliconfig"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/daemon"
-	"github.com/docker/docker/graph"
-	"github.com/docker/docker/pkg/ioutils"
-	"github.com/docker/docker/pkg/jsonmessage"
-	"github.com/docker/docker/pkg/parsers"
-	"github.com/docker/docker/pkg/parsers/filters"
-	"github.com/docker/docker/pkg/parsers/kernel"
-	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/sockets"
 	"github.com/docker/docker/pkg/sockets"
-	"github.com/docker/docker/pkg/stdcopy"
-	"github.com/docker/docker/pkg/streamformatter"
-	"github.com/docker/docker/pkg/ulimit"
 	"github.com/docker/docker/pkg/version"
 	"github.com/docker/docker/pkg/version"
-	"github.com/docker/docker/runconfig"
-	"github.com/docker/docker/utils"
 )
 )
 
 
 // Config provides the configuration for the API server
 // Config provides the configuration for the API server
@@ -238,1305 +219,6 @@ func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
 	return json.NewEncoder(w).Encode(v)
 	return json.NewEncoder(w).Encode(v)
 }
 }
 
 
-func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	var config *cliconfig.AuthConfig
-	err := json.NewDecoder(r.Body).Decode(&config)
-	r.Body.Close()
-	if err != nil {
-		return err
-	}
-	status, err := s.daemon.RegistryService.Auth(config)
-	if err != nil {
-		return err
-	}
-	return writeJSON(w, http.StatusOK, &types.AuthResponse{
-		Status: status,
-	})
-}
-
-func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	v := &types.Version{
-		Version:    dockerversion.VERSION,
-		ApiVersion: api.Version,
-		GitCommit:  dockerversion.GITCOMMIT,
-		GoVersion:  runtime.Version(),
-		Os:         runtime.GOOS,
-		Arch:       runtime.GOARCH,
-		BuildTime:  dockerversion.BUILDTIME,
-	}
-
-	if version.GreaterThanOrEqualTo("1.19") {
-		v.Experimental = utils.ExperimentalBuild()
-	}
-
-	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
-		v.KernelVersion = kernelVersion.String()
-	}
-
-	return writeJSON(w, http.StatusOK, v)
-}
-
-func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	var sig uint64
-	name := vars["name"]
-
-	// If we have a signal, look at it. Otherwise, do nothing
-	if sigStr := r.Form.Get("signal"); sigStr != "" {
-		// Check if we passed the signal as a number:
-		// The largest legal signal is 31, so let's parse on 5 bits
-		sigN, err := strconv.ParseUint(sigStr, 10, 5)
-		if err != nil {
-			// The signal is not a number, treat it as a string (either like
-			// "KILL" or like "SIGKILL")
-			syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
-			if !ok {
-				return fmt.Errorf("Invalid signal: %s", sigStr)
-			}
-			sig = uint64(syscallSig)
-		} else {
-			sig = sigN
-		}
-
-		if sig == 0 {
-			return fmt.Errorf("Invalid signal: %s", sigStr)
-		}
-	}
-
-	if err := s.daemon.ContainerKill(name, sig); err != nil {
-		_, isStopped := err.(daemon.ErrContainerNotRunning)
-		// Return error that's not caused because the container is stopped.
-		// Return error if the container is not running and the api is >= 1.20
-		// to keep backwards compatibility.
-		if version.GreaterThanOrEqualTo("1.20") || !isStopped {
-			return fmt.Errorf("Cannot kill container %s: %v", name, err)
-		}
-	}
-
-	w.WriteHeader(http.StatusNoContent)
-	return nil
-}
-
-func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	if err := s.daemon.ContainerPause(vars["name"]); err != nil {
-		return err
-	}
-
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
-		return err
-	}
-
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	return s.daemon.ContainerExport(vars["name"], w)
-}
-
-func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	// FIXME: The filter parameter could just be a match filter
-	images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, images)
-}
-
-func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	info, err := s.daemon.SystemInfo()
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, info)
-}
-
-func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	var since int64 = -1
-	if r.Form.Get("since") != "" {
-		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
-		if err != nil {
-			return err
-		}
-		since = s
-	}
-
-	var until int64 = -1
-	if r.Form.Get("until") != "" {
-		u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
-		if err != nil {
-			return err
-		}
-		until = u
-	}
-
-	timer := time.NewTimer(0)
-	timer.Stop()
-	if until > 0 {
-		dur := time.Unix(until, 0).Sub(time.Now())
-		timer = time.NewTimer(dur)
-	}
-
-	ef, err := filters.FromParam(r.Form.Get("filters"))
-	if err != nil {
-		return err
-	}
-
-	isFiltered := func(field string, filter []string) bool {
-		if len(field) == 0 {
-			return false
-		}
-		if len(filter) == 0 {
-			return false
-		}
-		for _, v := range filter {
-			if v == field {
-				return false
-			}
-			if strings.Contains(field, ":") {
-				image := strings.Split(field, ":")
-				if image[0] == v {
-					return false
-				}
-			}
-		}
-		return true
-	}
-
-	d := s.daemon
-	es := d.EventsService
-	w.Header().Set("Content-Type", "application/json")
-	outStream := ioutils.NewWriteFlusher(w)
-	outStream.Write(nil) // make sure response is sent immediately
-	enc := json.NewEncoder(outStream)
-
-	getContainerID := func(cn string) string {
-		c, err := d.Get(cn)
-		if err != nil {
-			return ""
-		}
-		return c.ID
-	}
-
-	sendEvent := func(ev *jsonmessage.JSONMessage) error {
-		//incoming container filter can be name,id or partial id, convert and replace as a full container id
-		for i, cn := range ef["container"] {
-			ef["container"][i] = getContainerID(cn)
-		}
-
-		if isFiltered(ev.Status, ef["event"]) || (isFiltered(ev.ID, ef["image"]) &&
-			isFiltered(ev.From, ef["image"])) || isFiltered(ev.ID, ef["container"]) {
-			return nil
-		}
-
-		return enc.Encode(ev)
-	}
-
-	current, l := es.Subscribe()
-	if since == -1 {
-		current = nil
-	}
-	defer es.Evict(l)
-	for _, ev := range current {
-		if ev.Time < since {
-			continue
-		}
-		if err := sendEvent(ev); err != nil {
-			return err
-		}
-	}
-
-	var closeNotify <-chan bool
-	if closeNotifier, ok := w.(http.CloseNotifier); ok {
-		closeNotify = closeNotifier.CloseNotify()
-	}
-
-	for {
-		select {
-		case ev := <-l:
-			jev, ok := ev.(*jsonmessage.JSONMessage)
-			if !ok {
-				continue
-			}
-			if err := sendEvent(jev); err != nil {
-				return err
-			}
-		case <-timer.C:
-			return nil
-		case <-closeNotify:
-			logrus.Debug("Client disconnected, stop sending events")
-			return nil
-		}
-	}
-}
-
-func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	name := vars["name"]
-	history, err := s.daemon.Repositories().History(name)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, history)
-}
-
-func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	changes, err := s.daemon.ContainerChanges(vars["name"])
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, changes)
-}
-
-func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, procList)
-}
-
-func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	config := &daemon.ContainersConfig{
-		All:     boolValue(r, "all"),
-		Size:    boolValue(r, "size"),
-		Since:   r.Form.Get("since"),
-		Before:  r.Form.Get("before"),
-		Filters: r.Form.Get("filters"),
-	}
-
-	if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
-		limit, err := strconv.Atoi(tmpLimit)
-		if err != nil {
-			return err
-		}
-		config.Limit = limit
-	}
-
-	containers, err := s.daemon.Containers(config)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, containers)
-}
-
-func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	stream := boolValueOrDefault(r, "stream", true)
-	var out io.Writer
-	if !stream {
-		w.Header().Set("Content-Type", "application/json")
-		out = w
-	} else {
-		out = ioutils.NewWriteFlusher(w)
-	}
-
-	var closeNotifier <-chan bool
-	if notifier, ok := w.(http.CloseNotifier); ok {
-		closeNotifier = notifier.CloseNotify()
-	}
-
-	config := &daemon.ContainerStatsConfig{
-		Stream:    stream,
-		OutStream: out,
-		Stop:      closeNotifier,
-	}
-
-	return s.daemon.ContainerStats(vars["name"], config)
-}
-
-func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	// Validate args here, because we can't return not StatusOK after job.Run() call
-	stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
-	if !(stdout || stderr) {
-		return fmt.Errorf("Bad parameters: you must choose at least one stream")
-	}
-
-	var since time.Time
-	if r.Form.Get("since") != "" {
-		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
-		if err != nil {
-			return err
-		}
-		since = time.Unix(s, 0)
-	}
-
-	var closeNotifier <-chan bool
-	if notifier, ok := w.(http.CloseNotifier); ok {
-		closeNotifier = notifier.CloseNotify()
-	}
-
-	c, err := s.daemon.Get(vars["name"])
-	if err != nil {
-		return err
-	}
-
-	outStream := ioutils.NewWriteFlusher(w)
-	// write an empty chunk of data (this is to ensure that the
-	// HTTP Response is sent immediatly, even if the container has
-	// not yet produced any data)
-	outStream.Write(nil)
-
-	logsConfig := &daemon.ContainerLogsConfig{
-		Follow:     boolValue(r, "follow"),
-		Timestamps: boolValue(r, "timestamps"),
-		Since:      since,
-		Tail:       r.Form.Get("tail"),
-		UseStdout:  stdout,
-		UseStderr:  stderr,
-		OutStream:  outStream,
-		Stop:       closeNotifier,
-	}
-
-	if err := s.daemon.ContainerLogs(c, logsConfig); err != nil {
-		fmt.Fprintf(w, "Error running logs job: %s\n", err)
-	}
-
-	return nil
-}
-
-func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	repo := r.Form.Get("repo")
-	tag := r.Form.Get("tag")
-	force := boolValue(r, "force")
-	name := vars["name"]
-	if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
-		return err
-	}
-	s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
-	w.WriteHeader(http.StatusCreated)
-	return nil
-}
-
-func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	if err := checkForJSON(r); err != nil {
-		return err
-	}
-
-	cname := r.Form.Get("container")
-
-	pause := boolValue(r, "pause")
-	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
-		pause = true
-	}
-
-	c, _, err := runconfig.DecodeContainerConfig(r.Body)
-	if err != nil && err != io.EOF { //Do not fail if body is empty.
-		return err
-	}
-
-	commitCfg := &builder.CommitConfig{
-		Pause:   pause,
-		Repo:    r.Form.Get("repo"),
-		Tag:     r.Form.Get("tag"),
-		Author:  r.Form.Get("author"),
-		Comment: r.Form.Get("comment"),
-		Changes: r.Form["changes"],
-		Config:  c,
-	}
-
-	imgID, err := builder.Commit(cname, s.daemon, commitCfg)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
-		ID: imgID,
-	})
-}
-
-// Creates an image from Pull or from Import
-func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	var (
-		image = r.Form.Get("fromImage")
-		repo  = r.Form.Get("repo")
-		tag   = r.Form.Get("tag")
-	)
-	authEncoded := r.Header.Get("X-Registry-Auth")
-	authConfig := &cliconfig.AuthConfig{}
-	if authEncoded != "" {
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
-			// for a pull it is not an error if no auth was given
-			// to increase compatibility with the existing api it is defaulting to be empty
-			authConfig = &cliconfig.AuthConfig{}
-		}
-	}
-
-	var (
-		err    error
-		output = ioutils.NewWriteFlusher(w)
-	)
-
-	w.Header().Set("Content-Type", "application/json")
-
-	if image != "" { //pull
-		if tag == "" {
-			image, tag = parsers.ParseRepositoryTag(image)
-		}
-		metaHeaders := map[string][]string{}
-		for k, v := range r.Header {
-			if strings.HasPrefix(k, "X-Meta-") {
-				metaHeaders[k] = v
-			}
-		}
-
-		imagePullConfig := &graph.ImagePullConfig{
-			MetaHeaders: metaHeaders,
-			AuthConfig:  authConfig,
-			OutStream:   output,
-		}
-
-		err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
-	} else { //import
-		if tag == "" {
-			repo, tag = parsers.ParseRepositoryTag(repo)
-		}
-
-		src := r.Form.Get("fromSrc")
-
-		// 'err' MUST NOT be defined within this block, we need any error
-		// generated from the download to be available to the output
-		// stream processing below
-		var newConfig *runconfig.Config
-		newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
-		if err != nil {
-			return err
-		}
-
-		err = s.daemon.Repositories().Import(src, repo, tag, r.Body, output, newConfig)
-	}
-	if err != nil {
-		if !output.Flushed() {
-			return err
-		}
-		sf := streamformatter.NewJSONStreamFormatter()
-		output.Write(sf.FormatError(err))
-	}
-
-	return nil
-
-}
-
-func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	var (
-		config      *cliconfig.AuthConfig
-		authEncoded = r.Header.Get("X-Registry-Auth")
-		headers     = map[string][]string{}
-	)
-
-	if authEncoded != "" {
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
-			// for a search it is not an error if no auth was given
-			// to increase compatibility with the existing api it is defaulting to be empty
-			config = &cliconfig.AuthConfig{}
-		}
-	}
-	for k, v := range r.Header {
-		if strings.HasPrefix(k, "X-Meta-") {
-			headers[k] = v
-		}
-	}
-	query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
-	if err != nil {
-		return err
-	}
-	return writeJSON(w, http.StatusOK, query.Results)
-}
-
-func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	metaHeaders := map[string][]string{}
-	for k, v := range r.Header {
-		if strings.HasPrefix(k, "X-Meta-") {
-			metaHeaders[k] = v
-		}
-	}
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	authConfig := &cliconfig.AuthConfig{}
-
-	authEncoded := r.Header.Get("X-Registry-Auth")
-	if authEncoded != "" {
-		// the new format is to handle the authConfig as a header
-		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
-		if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
-			// to increase compatibility to existing api it is defaulting to be empty
-			authConfig = &cliconfig.AuthConfig{}
-		}
-	} else {
-		// the old format is supported for compatibility if there was no authConfig header
-		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
-			return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
-		}
-	}
-
-	name := vars["name"]
-	output := ioutils.NewWriteFlusher(w)
-	imagePushConfig := &graph.ImagePushConfig{
-		MetaHeaders: metaHeaders,
-		AuthConfig:  authConfig,
-		Tag:         r.Form.Get("tag"),
-		OutStream:   output,
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-
-	if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
-		if !output.Flushed() {
-			return err
-		}
-		sf := streamformatter.NewJSONStreamFormatter()
-		output.Write(sf.FormatError(err))
-	}
-	return nil
-
-}
-
-func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-	if err := parseForm(r); err != nil {
-		return err
-	}
-
-	w.Header().Set("Content-Type", "application/x-tar")
-
-	output := ioutils.NewWriteFlusher(w)
-	var names []string
-	if name, ok := vars["name"]; ok {
-		names = []string{name}
-	} else {
-		names = r.Form["names"]
-	}
-
-	if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
-		if !output.Flushed() {
-			return err
-		}
-		sf := streamformatter.NewJSONStreamFormatter()
-		output.Write(sf.FormatError(err))
-	}
-	return nil
-
-}
-
-func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	return s.daemon.Repositories().Load(r.Body, w)
-}
-
-func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if err := checkForJSON(r); err != nil {
-		return err
-	}
-	var (
-		warnings []string
-		name     = r.Form.Get("name")
-	)
-
-	config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
-	if err != nil {
-		return err
-	}
-	adjustCPUShares(version, hostConfig)
-
-	containerID, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{
-		ID:       containerID,
-		Warnings: warnings,
-	})
-}
-
-func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	timeout, _ := strconv.Atoi(r.Form.Get("t"))
-
-	if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
-		return err
-	}
-
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	name := vars["name"]
-	newName := r.Form.Get("name")
-	if err := s.daemon.ContainerRename(name, newName); err != nil {
-		return err
-	}
-	w.WriteHeader(http.StatusNoContent)
-	return nil
-}
-
-func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	name := vars["name"]
-	config := &daemon.ContainerRmConfig{
-		ForceRemove:  boolValue(r, "force"),
-		RemoveVolume: boolValue(r, "v"),
-		RemoveLink:   boolValue(r, "link"),
-	}
-
-	if err := s.daemon.ContainerRm(name, config); err != nil {
-		// Force a 404 for the empty string
-		if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
-			return fmt.Errorf("no such id: \"\"")
-		}
-		return err
-	}
-
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	name := vars["name"]
-	force := boolValue(r, "force")
-	noprune := boolValue(r, "noprune")
-
-	list, err := s.daemon.ImageDelete(name, force, noprune)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, list)
-}
-
-func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	// If contentLength is -1, we can assumed chunked encoding
-	// or more technically that the length is unknown
-	// https://golang.org/src/pkg/net/http/request.go#L139
-	// net/http otherwise seems to swallow any headers related to chunked encoding
-	// including r.TransferEncoding
-	// allow a nil body for backwards compatibility
-	var hostConfig *runconfig.HostConfig
-	if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
-		if err := checkForJSON(r); err != nil {
-			return err
-		}
-
-		c, err := runconfig.DecodeHostConfig(r.Body)
-		if err != nil {
-			return err
-		}
-
-		hostConfig = c
-	}
-
-	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
-		if err.Error() == "Container already started" {
-			w.WriteHeader(http.StatusNotModified)
-			return nil
-		}
-		return err
-	}
-	w.WriteHeader(http.StatusNoContent)
-	return nil
-}
-
-func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	seconds, _ := strconv.Atoi(r.Form.Get("t"))
-
-	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
-		if err.Error() == "Container already stopped" {
-			w.WriteHeader(http.StatusNotModified)
-			return nil
-		}
-		return err
-	}
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
-		StatusCode: status,
-	})
-}
-
-func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	height, err := strconv.Atoi(r.Form.Get("h"))
-	if err != nil {
-		return err
-	}
-	width, err := strconv.Atoi(r.Form.Get("w"))
-	if err != nil {
-		return err
-	}
-
-	return s.daemon.ContainerResize(vars["name"], height, width)
-}
-
-func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	cont, err := s.daemon.Get(vars["name"])
-	if err != nil {
-		return err
-	}
-
-	inStream, outStream, err := hijackServer(w)
-	if err != nil {
-		return err
-	}
-	defer closeStreams(inStream, outStream)
-
-	if _, ok := r.Header["Upgrade"]; ok {
-		fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
-	} else {
-		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
-	}
-
-	attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
-		InStream:  inStream,
-		OutStream: outStream,
-		UseStdin:  boolValue(r, "stdin"),
-		UseStdout: boolValue(r, "stdout"),
-		UseStderr: boolValue(r, "stderr"),
-		Logs:      boolValue(r, "logs"),
-		Stream:    boolValue(r, "stream"),
-	}
-
-	if err := s.daemon.ContainerAttachWithLogs(cont, attachWithLogsConfig); err != nil {
-		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
-	}
-
-	return nil
-}
-
-func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	cont, err := s.daemon.Get(vars["name"])
-	if err != nil {
-		return err
-	}
-
-	h := websocket.Handler(func(ws *websocket.Conn) {
-		defer ws.Close()
-
-		wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
-			InStream:  ws,
-			OutStream: ws,
-			ErrStream: ws,
-			Logs:      boolValue(r, "logs"),
-			Stream:    boolValue(r, "stream"),
-		}
-
-		if err := s.daemon.ContainerWsAttachWithLogs(cont, wsAttachWithLogsConfig); err != nil {
-			logrus.Errorf("Error attaching websocket: %s", err)
-		}
-	})
-	h.ServeHTTP(w, r)
-
-	return nil
-}
-
-func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	if version.LessThan("1.20") && runtime.GOOS != "windows" {
-		return getContainersByNameDownlevel(w, s, vars["name"])
-	}
-
-	containerJSON, err := s.daemon.ContainerInspect(vars["name"])
-	if err != nil {
-		return err
-	}
-	return writeJSON(w, http.StatusOK, containerJSON)
-}
-
-func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter 'id'")
-	}
-
-	eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, eConfig)
-}
-
-func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
-	if err != nil {
-		return err
-	}
-
-	return writeJSON(w, http.StatusOK, imageInspect)
-}
-
-func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	var (
-		authConfigs        = map[string]cliconfig.AuthConfig{}
-		authConfigsEncoded = r.Header.Get("X-Registry-Config")
-		buildConfig        = builder.NewBuildConfig()
-	)
-
-	if authConfigsEncoded != "" {
-		authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
-		if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
-			// for a pull it is not an error if no auth was given
-			// to increase compatibility with the existing api it is defaulting
-			// to be empty.
-		}
-	}
-
-	w.Header().Set("Content-Type", "application/json")
-
-	if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
-		buildConfig.Remove = true
-	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
-		buildConfig.Remove = true
-	} else {
-		buildConfig.Remove = boolValue(r, "rm")
-	}
-	if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
-		buildConfig.Pull = true
-	}
-
-	output := ioutils.NewWriteFlusher(w)
-	buildConfig.Stdout = output
-	buildConfig.Context = r.Body
-
-	buildConfig.RemoteURL = r.FormValue("remote")
-	buildConfig.DockerfileName = r.FormValue("dockerfile")
-	buildConfig.RepoName = r.FormValue("t")
-	buildConfig.SuppressOutput = boolValue(r, "q")
-	buildConfig.NoCache = boolValue(r, "nocache")
-	buildConfig.ForceRemove = boolValue(r, "forcerm")
-	buildConfig.AuthConfigs = authConfigs
-	buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
-	buildConfig.Memory = int64ValueOrZero(r, "memory")
-	buildConfig.CPUShares = int64ValueOrZero(r, "cpushares")
-	buildConfig.CPUPeriod = int64ValueOrZero(r, "cpuperiod")
-	buildConfig.CPUQuota = int64ValueOrZero(r, "cpuquota")
-	buildConfig.CPUSetCpus = r.FormValue("cpusetcpus")
-	buildConfig.CPUSetMems = r.FormValue("cpusetmems")
-	buildConfig.CgroupParent = r.FormValue("cgroupparent")
-
-	var buildUlimits = []*ulimit.Ulimit{}
-	ulimitsJSON := r.FormValue("ulimits")
-	if ulimitsJSON != "" {
-		if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil {
-			return err
-		}
-		buildConfig.Ulimits = buildUlimits
-	}
-
-	// Job cancellation. Note: not all job types support this.
-	if closeNotifier, ok := w.(http.CloseNotifier); ok {
-		finished := make(chan struct{})
-		defer close(finished)
-		go func() {
-			select {
-			case <-finished:
-			case <-closeNotifier.CloseNotify():
-				logrus.Infof("Client disconnected, cancelling job: build")
-				buildConfig.Cancel()
-			}
-		}()
-	}
-
-	if err := builder.Build(s.daemon, buildConfig); err != nil {
-		// Do not write the error in the http output if it's still empty.
-		// This prevents from writing a 200(OK) when there is an interal error.
-		if !output.Flushed() {
-			return err
-		}
-		sf := streamformatter.NewJSONStreamFormatter()
-		w.Write(sf.FormatError(err))
-	}
-	return nil
-}
-
-// postContainersCopy is deprecated in favor of getContainersArchivePath.
-func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	if err := checkForJSON(r); err != nil {
-		return err
-	}
-
-	cfg := types.CopyConfig{}
-	if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
-		return err
-	}
-
-	if cfg.Resource == "" {
-		return fmt.Errorf("Path cannot be empty")
-	}
-
-	data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
-	if err != nil {
-		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
-			w.WriteHeader(http.StatusNotFound)
-			return nil
-		}
-		if os.IsNotExist(err) {
-			return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
-		}
-		return err
-	}
-	defer data.Close()
-
-	w.Header().Set("Content-Type", "application/x-tar")
-	if _, err := io.Copy(w, data); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// // Encode the stat to JSON, base64 encode, and place in a header.
-func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
-	statJSON, err := json.Marshal(stat)
-	if err != nil {
-		return err
-	}
-
-	header.Set(
-		"X-Docker-Container-Path-Stat",
-		base64.StdEncoding.EncodeToString(statJSON),
-	)
-
-	return nil
-}
-
-func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	v, err := archiveFormValues(r, vars)
-	if err != nil {
-		return err
-	}
-
-	stat, err := s.daemon.ContainerStatPath(v.name, v.path)
-	if err != nil {
-		return err
-	}
-
-	return setContainerPathStatHeader(stat, w.Header())
-}
-
-func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	v, err := archiveFormValues(r, vars)
-	if err != nil {
-		return err
-	}
-
-	tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
-	if err != nil {
-		return err
-	}
-	defer tarArchive.Close()
-
-	if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
-		return err
-	}
-
-	w.Header().Set("Content-Type", "application/x-tar")
-	_, err = io.Copy(w, tarArchive)
-
-	return err
-}
-
-func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	v, err := archiveFormValues(r, vars)
-	if err != nil {
-		return err
-	}
-
-	noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
-	return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
-}
-
-func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if err := checkForJSON(r); err != nil {
-		return err
-	}
-	name := vars["name"]
-
-	execConfig := &runconfig.ExecConfig{}
-	if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
-		return err
-	}
-	execConfig.Container = name
-
-	if len(execConfig.Cmd) == 0 {
-		return fmt.Errorf("No exec command specified")
-	}
-
-	// Register an instance of Exec in container.
-	id, err := s.daemon.ContainerExecCreate(execConfig)
-	if err != nil {
-		logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
-		return err
-	}
-
-	return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
-		ID: id,
-	})
-}
-
-// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
-func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	var (
-		execName = vars["name"]
-		stdin    io.ReadCloser
-		stdout   io.Writer
-		stderr   io.Writer
-	)
-
-	execStartCheck := &types.ExecStartCheck{}
-	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
-		return err
-	}
-
-	if !execStartCheck.Detach {
-		// Setting up the streaming http interface.
-		inStream, outStream, err := hijackServer(w)
-		if err != nil {
-			return err
-		}
-		defer closeStreams(inStream, outStream)
-
-		var errStream io.Writer
-
-		if _, ok := r.Header["Upgrade"]; ok {
-			fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
-		} else {
-			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
-		}
-
-		if !execStartCheck.Tty {
-			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
-			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
-		}
-
-		stdin = inStream
-		stdout = outStream
-		stderr = errStream
-	}
-	// Now run the user process in container.
-
-	if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
-		logrus.Errorf("Error starting exec command in container %s: %s", execName, err)
-		return err
-	}
-	w.WriteHeader(http.StatusNoContent)
-
-	return nil
-}
-
-func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	if err := parseForm(r); err != nil {
-		return err
-	}
-	if vars == nil {
-		return fmt.Errorf("Missing parameter")
-	}
-
-	height, err := strconv.Atoi(r.Form.Get("h"))
-	if err != nil {
-		return err
-	}
-	width, err := strconv.Atoi(r.Form.Get("w"))
-	if err != nil {
-		return err
-	}
-
-	return s.daemon.ContainerExecResize(vars["name"], height, width)
-}
-
 func (s *Server) optionsHandler(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 func (s *Server) optionsHandler(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	return nil
 	return nil