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