github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/api/server/server.go (about)

     1  package server
     2  
     3  import (
     4  	"crypto/tls"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"net/http"
    11  	"os"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/gorilla/mux"
    18  	"golang.org/x/net/websocket"
    19  
    20  	"github.com/Sirupsen/logrus"
    21  	"github.com/docker/docker/api"
    22  	"github.com/docker/docker/api/types"
    23  	"github.com/docker/docker/autogen/dockerversion"
    24  	"github.com/docker/docker/builder"
    25  	"github.com/docker/docker/cliconfig"
    26  	"github.com/docker/docker/daemon"
    27  	"github.com/docker/docker/graph"
    28  	"github.com/docker/docker/pkg/ioutils"
    29  	"github.com/docker/docker/pkg/jsonmessage"
    30  	"github.com/docker/docker/pkg/parsers"
    31  	"github.com/docker/docker/pkg/parsers/filters"
    32  	"github.com/docker/docker/pkg/parsers/kernel"
    33  	"github.com/docker/docker/pkg/signal"
    34  	"github.com/docker/docker/pkg/sockets"
    35  	"github.com/docker/docker/pkg/stdcopy"
    36  	"github.com/docker/docker/pkg/streamformatter"
    37  	"github.com/docker/docker/pkg/version"
    38  	"github.com/docker/docker/runconfig"
    39  	"github.com/docker/docker/utils"
    40  )
    41  
    42  type ServerConfig struct {
    43  	Logging     bool
    44  	EnableCors  bool
    45  	CorsHeaders string
    46  	Version     string
    47  	SocketGroup string
    48  	TLSConfig   *tls.Config
    49  }
    50  
    51  type Server struct {
    52  	daemon  *daemon.Daemon
    53  	cfg     *ServerConfig
    54  	router  *mux.Router
    55  	start   chan struct{}
    56  	servers []serverCloser
    57  }
    58  
    59  func New(cfg *ServerConfig) *Server {
    60  	srv := &Server{
    61  		cfg:   cfg,
    62  		start: make(chan struct{}),
    63  	}
    64  	r := createRouter(srv)
    65  	srv.router = r
    66  	return srv
    67  }
    68  
    69  func (s *Server) Close() {
    70  	for _, srv := range s.servers {
    71  		if err := srv.Close(); err != nil {
    72  			logrus.Error(err)
    73  		}
    74  	}
    75  }
    76  
    77  type serverCloser interface {
    78  	Serve() error
    79  	Close() error
    80  }
    81  
    82  // ServeApi loops through all of the protocols sent in to docker and spawns
    83  // off a go routine to setup a serving http.Server for each.
    84  func (s *Server) ServeApi(protoAddrs []string) error {
    85  	var chErrors = make(chan error, len(protoAddrs))
    86  
    87  	for _, protoAddr := range protoAddrs {
    88  		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
    89  		if len(protoAddrParts) != 2 {
    90  			return fmt.Errorf("bad format, expected PROTO://ADDR")
    91  		}
    92  		srv, err := s.newServer(protoAddrParts[0], protoAddrParts[1])
    93  		if err != nil {
    94  			return err
    95  		}
    96  		s.servers = append(s.servers, srv...)
    97  
    98  		for _, s := range srv {
    99  			logrus.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
   100  			go func(s serverCloser) {
   101  				if err := s.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
   102  					err = nil
   103  				}
   104  				chErrors <- err
   105  			}(s)
   106  		}
   107  	}
   108  
   109  	for i := 0; i < len(protoAddrs); i++ {
   110  		err := <-chErrors
   111  		if err != nil {
   112  			return err
   113  		}
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  type HttpServer struct {
   120  	srv *http.Server
   121  	l   net.Listener
   122  }
   123  
   124  func (s *HttpServer) Serve() error {
   125  	return s.srv.Serve(s.l)
   126  }
   127  func (s *HttpServer) Close() error {
   128  	return s.l.Close()
   129  }
   130  
   131  type HttpApiFunc func(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
   132  
   133  func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
   134  	conn, _, err := w.(http.Hijacker).Hijack()
   135  	if err != nil {
   136  		return nil, nil, err
   137  	}
   138  	// Flush the options to make sure the client sets the raw mode
   139  	conn.Write([]byte{})
   140  	return conn, conn, nil
   141  }
   142  
   143  func closeStreams(streams ...interface{}) {
   144  	for _, stream := range streams {
   145  		if tcpc, ok := stream.(interface {
   146  			CloseWrite() error
   147  		}); ok {
   148  			tcpc.CloseWrite()
   149  		} else if closer, ok := stream.(io.Closer); ok {
   150  			closer.Close()
   151  		}
   152  	}
   153  }
   154  
   155  // Check to make sure request's Content-Type is application/json
   156  func checkForJson(r *http.Request) error {
   157  	ct := r.Header.Get("Content-Type")
   158  
   159  	// No Content-Type header is ok as long as there's no Body
   160  	if ct == "" {
   161  		if r.Body == nil || r.ContentLength == 0 {
   162  			return nil
   163  		}
   164  	}
   165  
   166  	// Otherwise it better be json
   167  	if api.MatchesContentType(ct, "application/json") {
   168  		return nil
   169  	}
   170  	return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
   171  }
   172  
   173  //If we don't do this, POST method without Content-type (even with empty body) will fail
   174  func parseForm(r *http.Request) error {
   175  	if r == nil {
   176  		return nil
   177  	}
   178  	if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
   179  		return err
   180  	}
   181  	return nil
   182  }
   183  
   184  func parseMultipartForm(r *http.Request) error {
   185  	if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
   186  		return err
   187  	}
   188  	return nil
   189  }
   190  
   191  func httpError(w http.ResponseWriter, err error) {
   192  	if err == nil || w == nil {
   193  		logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
   194  		return
   195  	}
   196  	statusCode := http.StatusInternalServerError
   197  	// FIXME: this is brittle and should not be necessary.
   198  	// If we need to differentiate between different possible error types, we should
   199  	// create appropriate error types with clearly defined meaning.
   200  	errStr := strings.ToLower(err.Error())
   201  	for keyword, status := range map[string]int{
   202  		"not found":             http.StatusNotFound,
   203  		"no such":               http.StatusNotFound,
   204  		"bad parameter":         http.StatusBadRequest,
   205  		"conflict":              http.StatusConflict,
   206  		"impossible":            http.StatusNotAcceptable,
   207  		"wrong login/password":  http.StatusUnauthorized,
   208  		"hasn't been activated": http.StatusForbidden,
   209  	} {
   210  		if strings.Contains(errStr, keyword) {
   211  			statusCode = status
   212  			break
   213  		}
   214  	}
   215  
   216  	logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": err}).Error("HTTP Error")
   217  	http.Error(w, err.Error(), statusCode)
   218  }
   219  
   220  // writeJSON writes the value v to the http response stream as json with standard
   221  // json encoding.
   222  func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
   223  	w.Header().Set("Content-Type", "application/json")
   224  	w.WriteHeader(code)
   225  	return json.NewEncoder(w).Encode(v)
   226  }
   227  
   228  func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   229  	var config *cliconfig.AuthConfig
   230  	err := json.NewDecoder(r.Body).Decode(&config)
   231  	r.Body.Close()
   232  	if err != nil {
   233  		return err
   234  	}
   235  	status, err := s.daemon.RegistryService.Auth(config)
   236  	if err != nil {
   237  		return err
   238  	}
   239  	return writeJSON(w, http.StatusOK, &types.AuthResponse{
   240  		Status: status,
   241  	})
   242  }
   243  
   244  func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   245  	v := &types.Version{
   246  		Version:    dockerversion.VERSION,
   247  		ApiVersion: api.Version,
   248  		GitCommit:  dockerversion.GITCOMMIT,
   249  		GoVersion:  runtime.Version(),
   250  		Os:         runtime.GOOS,
   251  		Arch:       runtime.GOARCH,
   252  		BuildTime:  dockerversion.BUILDTIME,
   253  	}
   254  
   255  	if version.GreaterThanOrEqualTo("1.19") {
   256  		v.Experimental = utils.ExperimentalBuild()
   257  	}
   258  
   259  	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
   260  		v.KernelVersion = kernelVersion.String()
   261  	}
   262  
   263  	return writeJSON(w, http.StatusOK, v)
   264  }
   265  
   266  func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   267  	if vars == nil {
   268  		return fmt.Errorf("Missing parameter")
   269  	}
   270  	if err := parseForm(r); err != nil {
   271  		return err
   272  	}
   273  
   274  	var sig uint64
   275  	name := vars["name"]
   276  
   277  	// If we have a signal, look at it. Otherwise, do nothing
   278  	if sigStr := r.Form.Get("signal"); sigStr != "" {
   279  		// Check if we passed the signal as a number:
   280  		// The largest legal signal is 31, so let's parse on 5 bits
   281  		sigN, err := strconv.ParseUint(sigStr, 10, 5)
   282  		if err != nil {
   283  			// The signal is not a number, treat it as a string (either like
   284  			// "KILL" or like "SIGKILL")
   285  			syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
   286  			if !ok {
   287  				return fmt.Errorf("Invalid signal: %s", sigStr)
   288  			}
   289  			sig = uint64(syscallSig)
   290  		} else {
   291  			sig = sigN
   292  		}
   293  
   294  		if sig == 0 {
   295  			return fmt.Errorf("Invalid signal: %s", sigStr)
   296  		}
   297  	}
   298  
   299  	if err := s.daemon.ContainerKill(name, sig); err != nil {
   300  		return err
   301  	}
   302  
   303  	w.WriteHeader(http.StatusNoContent)
   304  	return nil
   305  }
   306  
   307  func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   308  	if vars == nil {
   309  		return fmt.Errorf("Missing parameter")
   310  	}
   311  	if err := parseForm(r); err != nil {
   312  		return err
   313  	}
   314  
   315  	if err := s.daemon.ContainerPause(vars["name"]); err != nil {
   316  		return err
   317  	}
   318  
   319  	w.WriteHeader(http.StatusNoContent)
   320  
   321  	return nil
   322  }
   323  
   324  func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   325  	if vars == nil {
   326  		return fmt.Errorf("Missing parameter")
   327  	}
   328  	if err := parseForm(r); err != nil {
   329  		return err
   330  	}
   331  
   332  	if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
   333  		return err
   334  	}
   335  
   336  	w.WriteHeader(http.StatusNoContent)
   337  
   338  	return nil
   339  }
   340  
   341  func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   342  	if vars == nil {
   343  		return fmt.Errorf("Missing parameter")
   344  	}
   345  
   346  	return s.daemon.ContainerExport(vars["name"], w)
   347  }
   348  
   349  func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   350  	if err := parseForm(r); err != nil {
   351  		return err
   352  	}
   353  
   354  	imagesConfig := graph.ImagesConfig{
   355  		Filters: r.Form.Get("filters"),
   356  		// FIXME this parameter could just be a match filter
   357  		Filter: r.Form.Get("filter"),
   358  		All:    boolValue(r, "all"),
   359  	}
   360  
   361  	images, err := s.daemon.Repositories().Images(&imagesConfig)
   362  	if err != nil {
   363  		return err
   364  	}
   365  
   366  	return writeJSON(w, http.StatusOK, images)
   367  }
   368  
   369  func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   370  	info, err := s.daemon.SystemInfo()
   371  	if err != nil {
   372  		return err
   373  	}
   374  
   375  	return writeJSON(w, http.StatusOK, info)
   376  }
   377  
   378  func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   379  	if err := parseForm(r); err != nil {
   380  		return err
   381  	}
   382  	var since int64 = -1
   383  	if r.Form.Get("since") != "" {
   384  		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
   385  		if err != nil {
   386  			return err
   387  		}
   388  		since = s
   389  	}
   390  
   391  	var until int64 = -1
   392  	if r.Form.Get("until") != "" {
   393  		u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
   394  		if err != nil {
   395  			return err
   396  		}
   397  		until = u
   398  	}
   399  
   400  	timer := time.NewTimer(0)
   401  	timer.Stop()
   402  	if until > 0 {
   403  		dur := time.Unix(until, 0).Sub(time.Now())
   404  		timer = time.NewTimer(dur)
   405  	}
   406  
   407  	ef, err := filters.FromParam(r.Form.Get("filters"))
   408  	if err != nil {
   409  		return err
   410  	}
   411  
   412  	isFiltered := func(field string, filter []string) bool {
   413  		if len(filter) == 0 {
   414  			return false
   415  		}
   416  		for _, v := range filter {
   417  			if v == field {
   418  				return false
   419  			}
   420  			if strings.Contains(field, ":") {
   421  				image := strings.Split(field, ":")
   422  				if image[0] == v {
   423  					return false
   424  				}
   425  			}
   426  		}
   427  		return true
   428  	}
   429  
   430  	d := s.daemon
   431  	es := d.EventsService
   432  	w.Header().Set("Content-Type", "application/json")
   433  	enc := json.NewEncoder(ioutils.NewWriteFlusher(w))
   434  
   435  	getContainerId := func(cn string) string {
   436  		c, err := d.Get(cn)
   437  		if err != nil {
   438  			return ""
   439  		}
   440  		return c.ID
   441  	}
   442  
   443  	sendEvent := func(ev *jsonmessage.JSONMessage) error {
   444  		//incoming container filter can be name,id or partial id, convert and replace as a full container id
   445  		for i, cn := range ef["container"] {
   446  			ef["container"][i] = getContainerId(cn)
   447  		}
   448  
   449  		if isFiltered(ev.Status, ef["event"]) || isFiltered(ev.From, ef["image"]) ||
   450  			isFiltered(ev.ID, ef["container"]) {
   451  			return nil
   452  		}
   453  
   454  		return enc.Encode(ev)
   455  	}
   456  
   457  	current, l := es.Subscribe()
   458  	if since == -1 {
   459  		current = nil
   460  	}
   461  	defer es.Evict(l)
   462  	for _, ev := range current {
   463  		if ev.Time < since {
   464  			continue
   465  		}
   466  		if err := sendEvent(ev); err != nil {
   467  			return err
   468  		}
   469  	}
   470  
   471  	var closeNotify <-chan bool
   472  	if closeNotifier, ok := w.(http.CloseNotifier); ok {
   473  		closeNotify = closeNotifier.CloseNotify()
   474  	}
   475  
   476  	for {
   477  		select {
   478  		case ev := <-l:
   479  			jev, ok := ev.(*jsonmessage.JSONMessage)
   480  			if !ok {
   481  				continue
   482  			}
   483  			if err := sendEvent(jev); err != nil {
   484  				return err
   485  			}
   486  		case <-timer.C:
   487  			return nil
   488  		case <-closeNotify:
   489  			logrus.Debug("Client disconnected, stop sending events")
   490  			return nil
   491  		}
   492  	}
   493  }
   494  
   495  func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   496  	if vars == nil {
   497  		return fmt.Errorf("Missing parameter")
   498  	}
   499  
   500  	name := vars["name"]
   501  	history, err := s.daemon.Repositories().History(name)
   502  	if err != nil {
   503  		return err
   504  	}
   505  
   506  	return writeJSON(w, http.StatusOK, history)
   507  }
   508  
   509  func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   510  	if vars == nil {
   511  		return fmt.Errorf("Missing parameter")
   512  	}
   513  
   514  	changes, err := s.daemon.ContainerChanges(vars["name"])
   515  	if err != nil {
   516  		return err
   517  	}
   518  
   519  	return writeJSON(w, http.StatusOK, changes)
   520  }
   521  
   522  func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   523  	if vars == nil {
   524  		return fmt.Errorf("Missing parameter")
   525  	}
   526  
   527  	if err := parseForm(r); err != nil {
   528  		return err
   529  	}
   530  
   531  	procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
   532  	if err != nil {
   533  		return err
   534  	}
   535  
   536  	return writeJSON(w, http.StatusOK, procList)
   537  }
   538  
   539  func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   540  	if err := parseForm(r); err != nil {
   541  		return err
   542  	}
   543  
   544  	config := &daemon.ContainersConfig{
   545  		All:     boolValue(r, "all"),
   546  		Size:    boolValue(r, "size"),
   547  		Since:   r.Form.Get("since"),
   548  		Before:  r.Form.Get("before"),
   549  		Filters: r.Form.Get("filters"),
   550  	}
   551  
   552  	if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
   553  		limit, err := strconv.Atoi(tmpLimit)
   554  		if err != nil {
   555  			return err
   556  		}
   557  		config.Limit = limit
   558  	}
   559  
   560  	containers, err := s.daemon.Containers(config)
   561  	if err != nil {
   562  		return err
   563  	}
   564  
   565  	return writeJSON(w, http.StatusOK, containers)
   566  }
   567  
   568  func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   569  	if err := parseForm(r); err != nil {
   570  		return err
   571  	}
   572  	if vars == nil {
   573  		return fmt.Errorf("Missing parameter")
   574  	}
   575  
   576  	stream := boolValueOrDefault(r, "stream", true)
   577  	var out io.Writer
   578  	if !stream {
   579  		w.Header().Set("Content-Type", "application/json")
   580  		out = w
   581  	} else {
   582  		out = ioutils.NewWriteFlusher(w)
   583  	}
   584  
   585  	var closeNotifier <-chan bool
   586  	if notifier, ok := w.(http.CloseNotifier); ok {
   587  		closeNotifier = notifier.CloseNotify()
   588  	}
   589  
   590  	config := &daemon.ContainerStatsConfig{
   591  		Stream:    stream,
   592  		OutStream: out,
   593  		Stop:      closeNotifier,
   594  	}
   595  
   596  	return s.daemon.ContainerStats(vars["name"], config)
   597  }
   598  
   599  func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   600  	if err := parseForm(r); err != nil {
   601  		return err
   602  	}
   603  	if vars == nil {
   604  		return fmt.Errorf("Missing parameter")
   605  	}
   606  
   607  	// Validate args here, because we can't return not StatusOK after job.Run() call
   608  	stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
   609  	if !(stdout || stderr) {
   610  		return fmt.Errorf("Bad parameters: you must choose at least one stream")
   611  	}
   612  
   613  	var since time.Time
   614  	if r.Form.Get("since") != "" {
   615  		s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
   616  		if err != nil {
   617  			return err
   618  		}
   619  		since = time.Unix(s, 0)
   620  	}
   621  
   622  	var closeNotifier <-chan bool
   623  	if notifier, ok := w.(http.CloseNotifier); ok {
   624  		closeNotifier = notifier.CloseNotify()
   625  	}
   626  
   627  	logsConfig := &daemon.ContainerLogsConfig{
   628  		Follow:     boolValue(r, "follow"),
   629  		Timestamps: boolValue(r, "timestamps"),
   630  		Since:      since,
   631  		Tail:       r.Form.Get("tail"),
   632  		UseStdout:  stdout,
   633  		UseStderr:  stderr,
   634  		OutStream:  ioutils.NewWriteFlusher(w),
   635  		Stop:       closeNotifier,
   636  	}
   637  
   638  	if err := s.daemon.ContainerLogs(vars["name"], logsConfig); err != nil {
   639  		fmt.Fprintf(w, "Error running logs job: %s\n", err)
   640  	}
   641  
   642  	return nil
   643  }
   644  
   645  func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   646  	if err := parseForm(r); err != nil {
   647  		return err
   648  	}
   649  	if vars == nil {
   650  		return fmt.Errorf("Missing parameter")
   651  	}
   652  
   653  	repo := r.Form.Get("repo")
   654  	tag := r.Form.Get("tag")
   655  	force := boolValue(r, "force")
   656  	name := vars["name"]
   657  	if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
   658  		return err
   659  	}
   660  	s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
   661  	w.WriteHeader(http.StatusCreated)
   662  	return nil
   663  }
   664  
   665  func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   666  	if err := parseForm(r); err != nil {
   667  		return err
   668  	}
   669  
   670  	if err := checkForJson(r); err != nil {
   671  		return err
   672  	}
   673  
   674  	cname := r.Form.Get("container")
   675  
   676  	pause := boolValue(r, "pause")
   677  	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
   678  		pause = true
   679  	}
   680  
   681  	c, _, err := runconfig.DecodeContainerConfig(r.Body)
   682  	if err != nil && err != io.EOF { //Do not fail if body is empty.
   683  		return err
   684  	}
   685  
   686  	commitCfg := &builder.BuilderCommitConfig{
   687  		Pause:   pause,
   688  		Repo:    r.Form.Get("repo"),
   689  		Tag:     r.Form.Get("tag"),
   690  		Author:  r.Form.Get("author"),
   691  		Comment: r.Form.Get("comment"),
   692  		Changes: r.Form["changes"],
   693  		Config:  c,
   694  	}
   695  
   696  	imgID, err := builder.Commit(cname, s.daemon, commitCfg)
   697  	if err != nil {
   698  		return err
   699  	}
   700  
   701  	return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
   702  		ID: imgID,
   703  	})
   704  }
   705  
   706  // Creates an image from Pull or from Import
   707  func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   708  	if err := parseForm(r); err != nil {
   709  		return err
   710  	}
   711  
   712  	var (
   713  		image = r.Form.Get("fromImage")
   714  		repo  = r.Form.Get("repo")
   715  		tag   = r.Form.Get("tag")
   716  	)
   717  	authEncoded := r.Header.Get("X-Registry-Auth")
   718  	authConfig := &cliconfig.AuthConfig{}
   719  	if authEncoded != "" {
   720  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   721  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
   722  			// for a pull it is not an error if no auth was given
   723  			// to increase compatibility with the existing api it is defaulting to be empty
   724  			authConfig = &cliconfig.AuthConfig{}
   725  		}
   726  	}
   727  
   728  	var (
   729  		err    error
   730  		output = ioutils.NewWriteFlusher(w)
   731  	)
   732  
   733  	w.Header().Set("Content-Type", "application/json")
   734  
   735  	if image != "" { //pull
   736  		if tag == "" {
   737  			image, tag = parsers.ParseRepositoryTag(image)
   738  		}
   739  		metaHeaders := map[string][]string{}
   740  		for k, v := range r.Header {
   741  			if strings.HasPrefix(k, "X-Meta-") {
   742  				metaHeaders[k] = v
   743  			}
   744  		}
   745  
   746  		imagePullConfig := &graph.ImagePullConfig{
   747  			MetaHeaders: metaHeaders,
   748  			AuthConfig:  authConfig,
   749  			OutStream:   output,
   750  		}
   751  
   752  		err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
   753  	} else { //import
   754  		if tag == "" {
   755  			repo, tag = parsers.ParseRepositoryTag(repo)
   756  		}
   757  
   758  		src := r.Form.Get("fromSrc")
   759  		imageImportConfig := &graph.ImageImportConfig{
   760  			Changes:   r.Form["changes"],
   761  			InConfig:  r.Body,
   762  			OutStream: output,
   763  		}
   764  
   765  		// 'err' MUST NOT be defined within this block, we need any error
   766  		// generated from the download to be available to the output
   767  		// stream processing below
   768  		var newConfig *runconfig.Config
   769  		newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, imageImportConfig.Changes)
   770  		if err != nil {
   771  			return err
   772  		}
   773  		imageImportConfig.ContainerConfig = newConfig
   774  
   775  		err = s.daemon.Repositories().Import(src, repo, tag, imageImportConfig)
   776  	}
   777  	if err != nil {
   778  		if !output.Flushed() {
   779  			return err
   780  		}
   781  		sf := streamformatter.NewJSONStreamFormatter()
   782  		output.Write(sf.FormatError(err))
   783  	}
   784  
   785  	return nil
   786  
   787  }
   788  
   789  func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   790  	if err := parseForm(r); err != nil {
   791  		return err
   792  	}
   793  	var (
   794  		config      *cliconfig.AuthConfig
   795  		authEncoded = r.Header.Get("X-Registry-Auth")
   796  		headers     = map[string][]string{}
   797  	)
   798  
   799  	if authEncoded != "" {
   800  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   801  		if err := json.NewDecoder(authJson).Decode(&config); err != nil {
   802  			// for a search it is not an error if no auth was given
   803  			// to increase compatibility with the existing api it is defaulting to be empty
   804  			config = &cliconfig.AuthConfig{}
   805  		}
   806  	}
   807  	for k, v := range r.Header {
   808  		if strings.HasPrefix(k, "X-Meta-") {
   809  			headers[k] = v
   810  		}
   811  	}
   812  	query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
   813  	if err != nil {
   814  		return err
   815  	}
   816  	return json.NewEncoder(w).Encode(query.Results)
   817  }
   818  
   819  func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   820  	if vars == nil {
   821  		return fmt.Errorf("Missing parameter")
   822  	}
   823  
   824  	metaHeaders := map[string][]string{}
   825  	for k, v := range r.Header {
   826  		if strings.HasPrefix(k, "X-Meta-") {
   827  			metaHeaders[k] = v
   828  		}
   829  	}
   830  	if err := parseForm(r); err != nil {
   831  		return err
   832  	}
   833  	authConfig := &cliconfig.AuthConfig{}
   834  
   835  	authEncoded := r.Header.Get("X-Registry-Auth")
   836  	if authEncoded != "" {
   837  		// the new format is to handle the authConfig as a header
   838  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   839  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
   840  			// to increase compatibility to existing api it is defaulting to be empty
   841  			authConfig = &cliconfig.AuthConfig{}
   842  		}
   843  	} else {
   844  		// the old format is supported for compatibility if there was no authConfig header
   845  		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
   846  			return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
   847  		}
   848  	}
   849  
   850  	name := vars["name"]
   851  	output := ioutils.NewWriteFlusher(w)
   852  	imagePushConfig := &graph.ImagePushConfig{
   853  		MetaHeaders: metaHeaders,
   854  		AuthConfig:  authConfig,
   855  		Tag:         r.Form.Get("tag"),
   856  		OutStream:   output,
   857  	}
   858  
   859  	w.Header().Set("Content-Type", "application/json")
   860  
   861  	if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
   862  		if !output.Flushed() {
   863  			return err
   864  		}
   865  		sf := streamformatter.NewJSONStreamFormatter()
   866  		output.Write(sf.FormatError(err))
   867  	}
   868  	return nil
   869  
   870  }
   871  
   872  func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   873  	if vars == nil {
   874  		return fmt.Errorf("Missing parameter")
   875  	}
   876  	if err := parseForm(r); err != nil {
   877  		return err
   878  	}
   879  
   880  	w.Header().Set("Content-Type", "application/x-tar")
   881  
   882  	output := ioutils.NewWriteFlusher(w)
   883  	imageExportConfig := &graph.ImageExportConfig{Outstream: output}
   884  	if name, ok := vars["name"]; ok {
   885  		imageExportConfig.Names = []string{name}
   886  	} else {
   887  		imageExportConfig.Names = r.Form["names"]
   888  	}
   889  
   890  	if err := s.daemon.Repositories().ImageExport(imageExportConfig); err != nil {
   891  		if !output.Flushed() {
   892  			return err
   893  		}
   894  		sf := streamformatter.NewJSONStreamFormatter()
   895  		output.Write(sf.FormatError(err))
   896  	}
   897  	return nil
   898  
   899  }
   900  
   901  func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   902  	return s.daemon.Repositories().Load(r.Body, w)
   903  }
   904  
   905  func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   906  	if err := parseForm(r); err != nil {
   907  		return err
   908  	}
   909  	if err := checkForJson(r); err != nil {
   910  		return err
   911  	}
   912  	var (
   913  		warnings []string
   914  		name     = r.Form.Get("name")
   915  	)
   916  
   917  	config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
   918  	if err != nil {
   919  		return err
   920  	}
   921  	adjustCpuShares(version, hostConfig)
   922  
   923  	containerId, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig)
   924  	if err != nil {
   925  		return err
   926  	}
   927  
   928  	return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{
   929  		ID:       containerId,
   930  		Warnings: warnings,
   931  	})
   932  }
   933  
   934  func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   935  	if err := parseForm(r); err != nil {
   936  		return err
   937  	}
   938  	if vars == nil {
   939  		return fmt.Errorf("Missing parameter")
   940  	}
   941  
   942  	timeout, _ := strconv.Atoi(r.Form.Get("t"))
   943  
   944  	if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
   945  		return err
   946  	}
   947  
   948  	w.WriteHeader(http.StatusNoContent)
   949  
   950  	return nil
   951  }
   952  
   953  func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   954  	if err := parseForm(r); err != nil {
   955  		return err
   956  	}
   957  	if vars == nil {
   958  		return fmt.Errorf("Missing parameter")
   959  	}
   960  
   961  	name := vars["name"]
   962  	newName := r.Form.Get("name")
   963  	if err := s.daemon.ContainerRename(name, newName); err != nil {
   964  		return err
   965  	}
   966  	w.WriteHeader(http.StatusNoContent)
   967  	return nil
   968  }
   969  
   970  func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   971  	if err := parseForm(r); err != nil {
   972  		return err
   973  	}
   974  	if vars == nil {
   975  		return fmt.Errorf("Missing parameter")
   976  	}
   977  
   978  	name := vars["name"]
   979  	config := &daemon.ContainerRmConfig{
   980  		ForceRemove:  boolValue(r, "force"),
   981  		RemoveVolume: boolValue(r, "v"),
   982  		RemoveLink:   boolValue(r, "link"),
   983  	}
   984  
   985  	if err := s.daemon.ContainerRm(name, config); err != nil {
   986  		// Force a 404 for the empty string
   987  		if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
   988  			return fmt.Errorf("no such id: \"\"")
   989  		}
   990  		return err
   991  	}
   992  
   993  	w.WriteHeader(http.StatusNoContent)
   994  
   995  	return nil
   996  }
   997  
   998  func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   999  	if err := parseForm(r); err != nil {
  1000  		return err
  1001  	}
  1002  	if vars == nil {
  1003  		return fmt.Errorf("Missing parameter")
  1004  	}
  1005  
  1006  	name := vars["name"]
  1007  	force := boolValue(r, "force")
  1008  	noprune := boolValue(r, "noprune")
  1009  
  1010  	list, err := s.daemon.ImageDelete(name, force, noprune)
  1011  	if err != nil {
  1012  		return err
  1013  	}
  1014  
  1015  	return writeJSON(w, http.StatusOK, list)
  1016  }
  1017  
  1018  func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1019  	if vars == nil {
  1020  		return fmt.Errorf("Missing parameter")
  1021  	}
  1022  
  1023  	// If contentLength is -1, we can assumed chunked encoding
  1024  	// or more technically that the length is unknown
  1025  	// https://golang.org/src/pkg/net/http/request.go#L139
  1026  	// net/http otherwise seems to swallow any headers related to chunked encoding
  1027  	// including r.TransferEncoding
  1028  	// allow a nil body for backwards compatibility
  1029  	var hostConfig *runconfig.HostConfig
  1030  	if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
  1031  		if err := checkForJson(r); err != nil {
  1032  			return err
  1033  		}
  1034  
  1035  		c, err := runconfig.DecodeHostConfig(r.Body)
  1036  		if err != nil {
  1037  			return err
  1038  		}
  1039  
  1040  		hostConfig = c
  1041  	}
  1042  
  1043  	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
  1044  		if err.Error() == "Container already started" {
  1045  			w.WriteHeader(http.StatusNotModified)
  1046  			return nil
  1047  		}
  1048  		return err
  1049  	}
  1050  	w.WriteHeader(http.StatusNoContent)
  1051  	return nil
  1052  }
  1053  
  1054  func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1055  	if err := parseForm(r); err != nil {
  1056  		return err
  1057  	}
  1058  	if vars == nil {
  1059  		return fmt.Errorf("Missing parameter")
  1060  	}
  1061  
  1062  	seconds, _ := strconv.Atoi(r.Form.Get("t"))
  1063  
  1064  	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
  1065  		if err.Error() == "Container already stopped" {
  1066  			w.WriteHeader(http.StatusNotModified)
  1067  			return nil
  1068  		}
  1069  		return err
  1070  	}
  1071  	w.WriteHeader(http.StatusNoContent)
  1072  
  1073  	return nil
  1074  }
  1075  
  1076  func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1077  	if vars == nil {
  1078  		return fmt.Errorf("Missing parameter")
  1079  	}
  1080  
  1081  	status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
  1082  	if err != nil {
  1083  		return err
  1084  	}
  1085  
  1086  	return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
  1087  		StatusCode: status,
  1088  	})
  1089  }
  1090  
  1091  func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1092  	if err := parseForm(r); err != nil {
  1093  		return err
  1094  	}
  1095  	if vars == nil {
  1096  		return fmt.Errorf("Missing parameter")
  1097  	}
  1098  
  1099  	height, err := strconv.Atoi(r.Form.Get("h"))
  1100  	if err != nil {
  1101  		return err
  1102  	}
  1103  	width, err := strconv.Atoi(r.Form.Get("w"))
  1104  	if err != nil {
  1105  		return err
  1106  	}
  1107  
  1108  	return s.daemon.ContainerResize(vars["name"], height, width)
  1109  }
  1110  
  1111  func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1112  	if err := parseForm(r); err != nil {
  1113  		return err
  1114  	}
  1115  	if vars == nil {
  1116  		return fmt.Errorf("Missing parameter")
  1117  	}
  1118  
  1119  	inStream, outStream, err := hijackServer(w)
  1120  	if err != nil {
  1121  		return err
  1122  	}
  1123  	defer closeStreams(inStream, outStream)
  1124  
  1125  	if _, ok := r.Header["Upgrade"]; ok {
  1126  		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")
  1127  	} else {
  1128  		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
  1129  	}
  1130  
  1131  	attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
  1132  		InStream:  inStream,
  1133  		OutStream: outStream,
  1134  		UseStdin:  boolValue(r, "stdin"),
  1135  		UseStdout: boolValue(r, "stdout"),
  1136  		UseStderr: boolValue(r, "stderr"),
  1137  		Logs:      boolValue(r, "logs"),
  1138  		Stream:    boolValue(r, "stream"),
  1139  	}
  1140  
  1141  	if err := s.daemon.ContainerAttachWithLogs(vars["name"], attachWithLogsConfig); err != nil {
  1142  		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
  1143  	}
  1144  
  1145  	return nil
  1146  }
  1147  
  1148  func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1149  	if err := parseForm(r); err != nil {
  1150  		return err
  1151  	}
  1152  	if vars == nil {
  1153  		return fmt.Errorf("Missing parameter")
  1154  	}
  1155  
  1156  	h := websocket.Handler(func(ws *websocket.Conn) {
  1157  		defer ws.Close()
  1158  
  1159  		wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
  1160  			InStream:  ws,
  1161  			OutStream: ws,
  1162  			ErrStream: ws,
  1163  			Logs:      boolValue(r, "logs"),
  1164  			Stream:    boolValue(r, "stream"),
  1165  		}
  1166  
  1167  		if err := s.daemon.ContainerWsAttachWithLogs(vars["name"], wsAttachWithLogsConfig); err != nil {
  1168  			logrus.Errorf("Error attaching websocket: %s", err)
  1169  		}
  1170  	})
  1171  	h.ServeHTTP(w, r)
  1172  
  1173  	return nil
  1174  }
  1175  
  1176  func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1177  	if vars == nil {
  1178  		return fmt.Errorf("Missing parameter")
  1179  	}
  1180  
  1181  	if version.LessThan("1.19") {
  1182  		containerJSONRaw, err := s.daemon.ContainerInspectRaw(vars["name"])
  1183  		if err != nil {
  1184  			return err
  1185  		}
  1186  		return writeJSON(w, http.StatusOK, containerJSONRaw)
  1187  	}
  1188  
  1189  	containerJSON, err := s.daemon.ContainerInspect(vars["name"])
  1190  	if err != nil {
  1191  		return err
  1192  	}
  1193  	return writeJSON(w, http.StatusOK, containerJSON)
  1194  }
  1195  
  1196  func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1197  	if vars == nil {
  1198  		return fmt.Errorf("Missing parameter 'id'")
  1199  	}
  1200  
  1201  	eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
  1202  	if err != nil {
  1203  		return err
  1204  	}
  1205  
  1206  	return writeJSON(w, http.StatusOK, eConfig)
  1207  }
  1208  
  1209  func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1210  	if vars == nil {
  1211  		return fmt.Errorf("Missing parameter")
  1212  	}
  1213  
  1214  	imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
  1215  	if err != nil {
  1216  		return err
  1217  	}
  1218  
  1219  	return writeJSON(w, http.StatusOK, imageInspect)
  1220  }
  1221  
  1222  func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1223  	var (
  1224  		authConfigs        = map[string]cliconfig.AuthConfig{}
  1225  		authConfigsEncoded = r.Header.Get("X-Registry-Config")
  1226  		buildConfig        = builder.NewBuildConfig()
  1227  	)
  1228  
  1229  	if authConfigsEncoded != "" {
  1230  		authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
  1231  		if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
  1232  			// for a pull it is not an error if no auth was given
  1233  			// to increase compatibility with the existing api it is defaulting
  1234  			// to be empty.
  1235  		}
  1236  	}
  1237  
  1238  	w.Header().Set("Content-Type", "application/json")
  1239  
  1240  	if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
  1241  		buildConfig.Remove = true
  1242  	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
  1243  		buildConfig.Remove = true
  1244  	} else {
  1245  		buildConfig.Remove = boolValue(r, "rm")
  1246  	}
  1247  	if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
  1248  		buildConfig.Pull = true
  1249  	}
  1250  
  1251  	output := ioutils.NewWriteFlusher(w)
  1252  	buildConfig.Stdout = output
  1253  	buildConfig.Context = r.Body
  1254  
  1255  	buildConfig.RemoteURL = r.FormValue("remote")
  1256  	buildConfig.DockerfileName = r.FormValue("dockerfile")
  1257  	buildConfig.RepoName = r.FormValue("t")
  1258  	buildConfig.SuppressOutput = boolValue(r, "q")
  1259  	buildConfig.NoCache = boolValue(r, "nocache")
  1260  	buildConfig.ForceRemove = boolValue(r, "forcerm")
  1261  	buildConfig.AuthConfigs = authConfigs
  1262  	buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
  1263  	buildConfig.Memory = int64ValueOrZero(r, "memory")
  1264  	buildConfig.CpuShares = int64ValueOrZero(r, "cpushares")
  1265  	buildConfig.CpuPeriod = int64ValueOrZero(r, "cpuperiod")
  1266  	buildConfig.CpuQuota = int64ValueOrZero(r, "cpuquota")
  1267  	buildConfig.CpuSetCpus = r.FormValue("cpusetcpus")
  1268  	buildConfig.CpuSetMems = r.FormValue("cpusetmems")
  1269  	buildConfig.CgroupParent = r.FormValue("cgroupparent")
  1270  
  1271  	// Job cancellation. Note: not all job types support this.
  1272  	if closeNotifier, ok := w.(http.CloseNotifier); ok {
  1273  		finished := make(chan struct{})
  1274  		defer close(finished)
  1275  		go func() {
  1276  			select {
  1277  			case <-finished:
  1278  			case <-closeNotifier.CloseNotify():
  1279  				logrus.Infof("Client disconnected, cancelling job: build")
  1280  				buildConfig.Cancel()
  1281  			}
  1282  		}()
  1283  	}
  1284  
  1285  	if err := builder.Build(s.daemon, buildConfig); err != nil {
  1286  		// Do not write the error in the http output if it's still empty.
  1287  		// This prevents from writing a 200(OK) when there is an interal error.
  1288  		if !output.Flushed() {
  1289  			return err
  1290  		}
  1291  		sf := streamformatter.NewJSONStreamFormatter()
  1292  		w.Write(sf.FormatError(err))
  1293  	}
  1294  	return nil
  1295  }
  1296  
  1297  func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1298  	if vars == nil {
  1299  		return fmt.Errorf("Missing parameter")
  1300  	}
  1301  
  1302  	if err := checkForJson(r); err != nil {
  1303  		return err
  1304  	}
  1305  
  1306  	cfg := types.CopyConfig{}
  1307  	if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
  1308  		return err
  1309  	}
  1310  
  1311  	if cfg.Resource == "" {
  1312  		return fmt.Errorf("Path cannot be empty")
  1313  	}
  1314  
  1315  	data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
  1316  	if err != nil {
  1317  		if strings.Contains(strings.ToLower(err.Error()), "no such id") {
  1318  			w.WriteHeader(http.StatusNotFound)
  1319  			return nil
  1320  		}
  1321  		if os.IsNotExist(err) {
  1322  			return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
  1323  		}
  1324  		return err
  1325  	}
  1326  	defer data.Close()
  1327  
  1328  	w.Header().Set("Content-Type", "application/x-tar")
  1329  	if _, err := io.Copy(w, data); err != nil {
  1330  		return err
  1331  	}
  1332  
  1333  	return nil
  1334  }
  1335  
  1336  func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1337  	if err := parseForm(r); err != nil {
  1338  		return err
  1339  	}
  1340  	name := vars["name"]
  1341  
  1342  	execConfig := &runconfig.ExecConfig{}
  1343  	if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
  1344  		return err
  1345  	}
  1346  	execConfig.Container = name
  1347  
  1348  	if len(execConfig.Cmd) == 0 {
  1349  		return fmt.Errorf("No exec command specified")
  1350  	}
  1351  
  1352  	// Register an instance of Exec in container.
  1353  	id, err := s.daemon.ContainerExecCreate(execConfig)
  1354  	if err != nil {
  1355  		logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
  1356  		return err
  1357  	}
  1358  
  1359  	return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
  1360  		ID: id,
  1361  	})
  1362  }
  1363  
  1364  // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
  1365  func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1366  	if err := parseForm(r); err != nil {
  1367  		return err
  1368  	}
  1369  	var (
  1370  		execName = vars["name"]
  1371  		stdin    io.ReadCloser
  1372  		stdout   io.Writer
  1373  		stderr   io.Writer
  1374  	)
  1375  
  1376  	execStartCheck := &types.ExecStartCheck{}
  1377  	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
  1378  		return err
  1379  	}
  1380  
  1381  	if !execStartCheck.Detach {
  1382  		// Setting up the streaming http interface.
  1383  		inStream, outStream, err := hijackServer(w)
  1384  		if err != nil {
  1385  			return err
  1386  		}
  1387  		defer closeStreams(inStream, outStream)
  1388  
  1389  		var errStream io.Writer
  1390  
  1391  		if _, ok := r.Header["Upgrade"]; ok {
  1392  			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")
  1393  		} else {
  1394  			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
  1395  		}
  1396  
  1397  		if !execStartCheck.Tty {
  1398  			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
  1399  			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
  1400  		}
  1401  
  1402  		stdin = inStream
  1403  		stdout = outStream
  1404  		stderr = errStream
  1405  	}
  1406  	// Now run the user process in container.
  1407  
  1408  	if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
  1409  		logrus.Errorf("Error starting exec command in container %s: %s", execName, err)
  1410  		return err
  1411  	}
  1412  	w.WriteHeader(http.StatusNoContent)
  1413  
  1414  	return nil
  1415  }
  1416  
  1417  func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1418  	if err := parseForm(r); err != nil {
  1419  		return err
  1420  	}
  1421  	if vars == nil {
  1422  		return fmt.Errorf("Missing parameter")
  1423  	}
  1424  
  1425  	height, err := strconv.Atoi(r.Form.Get("h"))
  1426  	if err != nil {
  1427  		return err
  1428  	}
  1429  	width, err := strconv.Atoi(r.Form.Get("w"))
  1430  	if err != nil {
  1431  		return err
  1432  	}
  1433  
  1434  	return s.daemon.ContainerExecResize(vars["name"], height, width)
  1435  }
  1436  
  1437  func (s *Server) optionsHandler(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1438  	w.WriteHeader(http.StatusOK)
  1439  	return nil
  1440  }
  1441  func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
  1442  	logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
  1443  	w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
  1444  	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
  1445  	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
  1446  }
  1447  
  1448  func (s *Server) ping(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1449  	_, err := w.Write([]byte{'O', 'K'})
  1450  	return err
  1451  }
  1452  
  1453  func (s *Server) initTcpSocket(addr string) (l net.Listener, err error) {
  1454  	if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
  1455  		logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
  1456  	}
  1457  	if l, err = sockets.NewTcpSocket(addr, s.cfg.TLSConfig, s.start); err != nil {
  1458  		return nil, err
  1459  	}
  1460  	if err := allocateDaemonPort(addr); err != nil {
  1461  		return nil, err
  1462  	}
  1463  	return
  1464  }
  1465  
  1466  func makeHttpHandler(logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, corsHeaders string, dockerVersion version.Version) http.HandlerFunc {
  1467  	return func(w http.ResponseWriter, r *http.Request) {
  1468  		// log the request
  1469  		logrus.Debugf("Calling %s %s", localMethod, localRoute)
  1470  
  1471  		if logging {
  1472  			logrus.Infof("%s %s", r.Method, r.RequestURI)
  1473  		}
  1474  
  1475  		if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
  1476  			userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
  1477  
  1478  			// v1.20 onwards includes the GOOS of the client after the version
  1479  			// such as Docker/1.7.0 (linux)
  1480  			if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") {
  1481  				userAgent[1] = strings.Split(userAgent[1], " ")[0]
  1482  			}
  1483  
  1484  			if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
  1485  				logrus.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
  1486  			}
  1487  		}
  1488  		version := version.Version(mux.Vars(r)["version"])
  1489  		if version == "" {
  1490  			version = api.Version
  1491  		}
  1492  		if corsHeaders != "" {
  1493  			writeCorsHeaders(w, r, corsHeaders)
  1494  		}
  1495  
  1496  		if version.GreaterThan(api.Version) {
  1497  			http.Error(w, fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", version, api.Version).Error(), http.StatusBadRequest)
  1498  			return
  1499  		}
  1500  		if version.LessThan(api.MinVersion) {
  1501  			http.Error(w, fmt.Errorf("client is too old, minimum supported API version is %s, please upgrade your client to a newer version", api.MinVersion).Error(), http.StatusBadRequest)
  1502  			return
  1503  		}
  1504  
  1505  		w.Header().Set("Server", "Docker/"+dockerversion.VERSION+" ("+runtime.GOOS+")")
  1506  
  1507  		if err := handlerFunc(version, w, r, mux.Vars(r)); err != nil {
  1508  			logrus.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
  1509  			httpError(w, err)
  1510  		}
  1511  	}
  1512  }
  1513  
  1514  // we keep enableCors just for legacy usage, need to be removed in the future
  1515  func createRouter(s *Server) *mux.Router {
  1516  	r := mux.NewRouter()
  1517  	if os.Getenv("DEBUG") != "" {
  1518  		ProfilerSetup(r, "/debug/")
  1519  	}
  1520  	m := map[string]map[string]HttpApiFunc{
  1521  		"GET": {
  1522  			"/_ping":                          s.ping,
  1523  			"/events":                         s.getEvents,
  1524  			"/info":                           s.getInfo,
  1525  			"/version":                        s.getVersion,
  1526  			"/images/json":                    s.getImagesJSON,
  1527  			"/images/search":                  s.getImagesSearch,
  1528  			"/images/get":                     s.getImagesGet,
  1529  			"/images/{name:.*}/get":           s.getImagesGet,
  1530  			"/images/{name:.*}/history":       s.getImagesHistory,
  1531  			"/images/{name:.*}/json":          s.getImagesByName,
  1532  			"/containers/ps":                  s.getContainersJSON,
  1533  			"/containers/json":                s.getContainersJSON,
  1534  			"/containers/{name:.*}/export":    s.getContainersExport,
  1535  			"/containers/{name:.*}/changes":   s.getContainersChanges,
  1536  			"/containers/{name:.*}/json":      s.getContainersByName,
  1537  			"/containers/{name:.*}/top":       s.getContainersTop,
  1538  			"/containers/{name:.*}/logs":      s.getContainersLogs,
  1539  			"/containers/{name:.*}/stats":     s.getContainersStats,
  1540  			"/containers/{name:.*}/attach/ws": s.wsContainersAttach,
  1541  			"/exec/{id:.*}/json":              s.getExecByID,
  1542  		},
  1543  		"POST": {
  1544  			"/auth":                         s.postAuth,
  1545  			"/commit":                       s.postCommit,
  1546  			"/build":                        s.postBuild,
  1547  			"/images/create":                s.postImagesCreate,
  1548  			"/images/load":                  s.postImagesLoad,
  1549  			"/images/{name:.*}/push":        s.postImagesPush,
  1550  			"/images/{name:.*}/tag":         s.postImagesTag,
  1551  			"/containers/create":            s.postContainersCreate,
  1552  			"/containers/{name:.*}/kill":    s.postContainersKill,
  1553  			"/containers/{name:.*}/pause":   s.postContainersPause,
  1554  			"/containers/{name:.*}/unpause": s.postContainersUnpause,
  1555  			"/containers/{name:.*}/restart": s.postContainersRestart,
  1556  			"/containers/{name:.*}/start":   s.postContainersStart,
  1557  			"/containers/{name:.*}/stop":    s.postContainersStop,
  1558  			"/containers/{name:.*}/wait":    s.postContainersWait,
  1559  			"/containers/{name:.*}/resize":  s.postContainersResize,
  1560  			"/containers/{name:.*}/attach":  s.postContainersAttach,
  1561  			"/containers/{name:.*}/copy":    s.postContainersCopy,
  1562  			"/containers/{name:.*}/exec":    s.postContainerExecCreate,
  1563  			"/exec/{name:.*}/start":         s.postContainerExecStart,
  1564  			"/exec/{name:.*}/resize":        s.postContainerExecResize,
  1565  			"/containers/{name:.*}/rename":  s.postContainerRename,
  1566  		},
  1567  		"DELETE": {
  1568  			"/containers/{name:.*}": s.deleteContainers,
  1569  			"/images/{name:.*}":     s.deleteImages,
  1570  		},
  1571  		"OPTIONS": {
  1572  			"": s.optionsHandler,
  1573  		},
  1574  	}
  1575  
  1576  	// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
  1577  	// otherwise, all head values will be passed to HTTP handler
  1578  	corsHeaders := s.cfg.CorsHeaders
  1579  	if corsHeaders == "" && s.cfg.EnableCors {
  1580  		corsHeaders = "*"
  1581  	}
  1582  
  1583  	for method, routes := range m {
  1584  		for route, fct := range routes {
  1585  			logrus.Debugf("Registering %s, %s", method, route)
  1586  			// NOTE: scope issue, make sure the variables are local and won't be changed
  1587  			localRoute := route
  1588  			localFct := fct
  1589  			localMethod := method
  1590  
  1591  			// build the handler function
  1592  			f := makeHttpHandler(s.cfg.Logging, localMethod, localRoute, localFct, corsHeaders, version.Version(s.cfg.Version))
  1593  
  1594  			// add the new route
  1595  			if localRoute == "" {
  1596  				r.Methods(localMethod).HandlerFunc(f)
  1597  			} else {
  1598  				r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
  1599  				r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
  1600  			}
  1601  		}
  1602  	}
  1603  
  1604  	return r
  1605  }