github.com/squaremo/docker@v1.3.2-0.20150516120342-42cfc9554972/api/server/server.go (about)

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