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