github.com/pritambaral/docker@v1.4.2-0.20150120174542-b2fe1b3dd952/api/server/server.go (about)

     1  package server
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  
     7  	"encoding/base64"
     8  	"encoding/json"
     9  	"expvar"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net"
    14  	"net/http"
    15  	"net/http/pprof"
    16  	"os"
    17  	"strconv"
    18  	"strings"
    19  	"syscall"
    20  
    21  	"crypto/tls"
    22  	"crypto/x509"
    23  
    24  	"code.google.com/p/go.net/websocket"
    25  	"github.com/docker/libcontainer/user"
    26  	"github.com/gorilla/mux"
    27  
    28  	log "github.com/Sirupsen/logrus"
    29  	"github.com/docker/docker/api"
    30  	"github.com/docker/docker/daemon/networkdriver/portallocator"
    31  	"github.com/docker/docker/engine"
    32  	"github.com/docker/docker/pkg/listenbuffer"
    33  	"github.com/docker/docker/pkg/parsers"
    34  	"github.com/docker/docker/pkg/stdcopy"
    35  	"github.com/docker/docker/pkg/systemd"
    36  	"github.com/docker/docker/pkg/version"
    37  	"github.com/docker/docker/registry"
    38  	"github.com/docker/docker/utils"
    39  )
    40  
    41  var (
    42  	activationLock chan struct{}
    43  )
    44  
    45  type HttpServer struct {
    46  	srv *http.Server
    47  	l   net.Listener
    48  }
    49  
    50  func (s *HttpServer) Serve() error {
    51  	return s.srv.Serve(s.l)
    52  }
    53  func (s *HttpServer) Close() error {
    54  	return s.l.Close()
    55  }
    56  
    57  type HttpApiFunc func(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error
    58  
    59  func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
    60  	conn, _, err := w.(http.Hijacker).Hijack()
    61  	if err != nil {
    62  		return nil, nil, err
    63  	}
    64  	// Flush the options to make sure the client sets the raw mode
    65  	conn.Write([]byte{})
    66  	return conn, conn, nil
    67  }
    68  
    69  func closeStreams(streams ...interface{}) {
    70  	for _, stream := range streams {
    71  		if tcpc, ok := stream.(interface {
    72  			CloseWrite() error
    73  		}); ok {
    74  			tcpc.CloseWrite()
    75  		} else if closer, ok := stream.(io.Closer); ok {
    76  			closer.Close()
    77  		}
    78  	}
    79  }
    80  
    81  // Check to make sure request's Content-Type is application/json
    82  func checkForJson(r *http.Request) error {
    83  	ct := r.Header.Get("Content-Type")
    84  
    85  	// No Content-Type header is ok as long as there's no Body
    86  	if ct == "" {
    87  		if r.Body == nil || r.ContentLength == 0 {
    88  			return nil
    89  		}
    90  	}
    91  
    92  	// Otherwise it better be json
    93  	if api.MatchesContentType(ct, "application/json") {
    94  		return nil
    95  	}
    96  	return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
    97  }
    98  
    99  //If we don't do this, POST method without Content-type (even with empty body) will fail
   100  func parseForm(r *http.Request) error {
   101  	if r == nil {
   102  		return nil
   103  	}
   104  	if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
   105  		return err
   106  	}
   107  	return nil
   108  }
   109  
   110  func parseMultipartForm(r *http.Request) error {
   111  	if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
   112  		return err
   113  	}
   114  	return nil
   115  }
   116  
   117  func httpError(w http.ResponseWriter, err error) {
   118  	statusCode := http.StatusInternalServerError
   119  	// FIXME: this is brittle and should not be necessary.
   120  	// If we need to differentiate between different possible error types, we should
   121  	// create appropriate error types with clearly defined meaning.
   122  	errStr := strings.ToLower(err.Error())
   123  	if strings.Contains(errStr, "no such") {
   124  		statusCode = http.StatusNotFound
   125  	} else if strings.Contains(errStr, "bad parameter") {
   126  		statusCode = http.StatusBadRequest
   127  	} else if strings.Contains(errStr, "conflict") {
   128  		statusCode = http.StatusConflict
   129  	} else if strings.Contains(errStr, "impossible") {
   130  		statusCode = http.StatusNotAcceptable
   131  	} else if strings.Contains(errStr, "wrong login/password") {
   132  		statusCode = http.StatusUnauthorized
   133  	} else if strings.Contains(errStr, "hasn't been activated") {
   134  		statusCode = http.StatusForbidden
   135  	}
   136  
   137  	if err != nil {
   138  		log.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
   139  		http.Error(w, err.Error(), statusCode)
   140  	}
   141  }
   142  
   143  func writeJSON(w http.ResponseWriter, code int, v engine.Env) error {
   144  	w.Header().Set("Content-Type", "application/json")
   145  	w.WriteHeader(code)
   146  	return v.Encode(w)
   147  }
   148  
   149  func streamJSON(job *engine.Job, w http.ResponseWriter, flush bool) {
   150  	w.Header().Set("Content-Type", "application/json")
   151  	if flush {
   152  		job.Stdout.Add(utils.NewWriteFlusher(w))
   153  	} else {
   154  		job.Stdout.Add(w)
   155  	}
   156  }
   157  
   158  func getBoolParam(value string) (bool, error) {
   159  	if value == "" {
   160  		return false, nil
   161  	}
   162  	ret, err := strconv.ParseBool(value)
   163  	if err != nil {
   164  		return false, fmt.Errorf("Bad parameter")
   165  	}
   166  	return ret, nil
   167  }
   168  
   169  func postAuth(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   170  	var (
   171  		authConfig, err = ioutil.ReadAll(r.Body)
   172  		job             = eng.Job("auth")
   173  		stdoutBuffer    = bytes.NewBuffer(nil)
   174  	)
   175  	if err != nil {
   176  		return err
   177  	}
   178  	job.Setenv("authConfig", string(authConfig))
   179  	job.Stdout.Add(stdoutBuffer)
   180  	if err = job.Run(); err != nil {
   181  		return err
   182  	}
   183  	if status := engine.Tail(stdoutBuffer, 1); status != "" {
   184  		var env engine.Env
   185  		env.Set("Status", status)
   186  		return writeJSON(w, http.StatusOK, env)
   187  	}
   188  	w.WriteHeader(http.StatusNoContent)
   189  	return nil
   190  }
   191  
   192  func getVersion(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   193  	w.Header().Set("Content-Type", "application/json")
   194  	eng.ServeHTTP(w, r)
   195  	return nil
   196  }
   197  
   198  func postContainersKill(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   199  	if vars == nil {
   200  		return fmt.Errorf("Missing parameter")
   201  	}
   202  	if err := parseForm(r); err != nil {
   203  		return err
   204  	}
   205  	job := eng.Job("kill", vars["name"])
   206  	if sig := r.Form.Get("signal"); sig != "" {
   207  		job.Args = append(job.Args, sig)
   208  	}
   209  	if err := job.Run(); err != nil {
   210  		return err
   211  	}
   212  	w.WriteHeader(http.StatusNoContent)
   213  	return nil
   214  }
   215  
   216  func postContainersPause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   217  	if vars == nil {
   218  		return fmt.Errorf("Missing parameter")
   219  	}
   220  	if err := parseForm(r); err != nil {
   221  		return err
   222  	}
   223  	job := eng.Job("pause", vars["name"])
   224  	if err := job.Run(); err != nil {
   225  		return err
   226  	}
   227  	w.WriteHeader(http.StatusNoContent)
   228  	return nil
   229  }
   230  
   231  func postContainersUnpause(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   232  	if vars == nil {
   233  		return fmt.Errorf("Missing parameter")
   234  	}
   235  	if err := parseForm(r); err != nil {
   236  		return err
   237  	}
   238  	job := eng.Job("unpause", vars["name"])
   239  	if err := job.Run(); err != nil {
   240  		return err
   241  	}
   242  	w.WriteHeader(http.StatusNoContent)
   243  	return nil
   244  }
   245  
   246  func getContainersExport(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   247  	if vars == nil {
   248  		return fmt.Errorf("Missing parameter")
   249  	}
   250  	job := eng.Job("export", vars["name"])
   251  	job.Stdout.Add(w)
   252  	if err := job.Run(); err != nil {
   253  		return err
   254  	}
   255  	return nil
   256  }
   257  
   258  func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   259  	if err := parseForm(r); err != nil {
   260  		return err
   261  	}
   262  
   263  	var (
   264  		err  error
   265  		outs *engine.Table
   266  		job  = eng.Job("images")
   267  	)
   268  
   269  	job.Setenv("filters", r.Form.Get("filters"))
   270  	// FIXME this parameter could just be a match filter
   271  	job.Setenv("filter", r.Form.Get("filter"))
   272  	job.Setenv("all", r.Form.Get("all"))
   273  
   274  	if version.GreaterThanOrEqualTo("1.7") {
   275  		streamJSON(job, w, false)
   276  	} else if outs, err = job.Stdout.AddListTable(); err != nil {
   277  		return err
   278  	}
   279  
   280  	if err := job.Run(); err != nil {
   281  		return err
   282  	}
   283  
   284  	if version.LessThan("1.7") && outs != nil { // Convert to legacy format
   285  		outsLegacy := engine.NewTable("Created", 0)
   286  		for _, out := range outs.Data {
   287  			for _, repoTag := range out.GetList("RepoTags") {
   288  				repo, tag := parsers.ParseRepositoryTag(repoTag)
   289  				outLegacy := &engine.Env{}
   290  				outLegacy.Set("Repository", repo)
   291  				outLegacy.SetJson("Tag", tag)
   292  				outLegacy.Set("Id", out.Get("Id"))
   293  				outLegacy.SetInt64("Created", out.GetInt64("Created"))
   294  				outLegacy.SetInt64("Size", out.GetInt64("Size"))
   295  				outLegacy.SetInt64("VirtualSize", out.GetInt64("VirtualSize"))
   296  				outsLegacy.Add(outLegacy)
   297  			}
   298  		}
   299  		w.Header().Set("Content-Type", "application/json")
   300  		if _, err := outsLegacy.WriteListTo(w); err != nil {
   301  			return err
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  func getImagesViz(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   308  	if version.GreaterThan("1.6") {
   309  		w.WriteHeader(http.StatusNotFound)
   310  		return fmt.Errorf("This is now implemented in the client.")
   311  	}
   312  	eng.ServeHTTP(w, r)
   313  	return nil
   314  }
   315  
   316  func getInfo(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   317  	w.Header().Set("Content-Type", "application/json")
   318  	eng.ServeHTTP(w, r)
   319  	return nil
   320  }
   321  
   322  func getEvents(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   323  	if err := parseForm(r); err != nil {
   324  		return err
   325  	}
   326  
   327  	var job = eng.Job("events")
   328  	streamJSON(job, w, true)
   329  	job.Setenv("since", r.Form.Get("since"))
   330  	job.Setenv("until", r.Form.Get("until"))
   331  	job.Setenv("filters", r.Form.Get("filters"))
   332  	return job.Run()
   333  }
   334  
   335  func getImagesHistory(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   336  	if vars == nil {
   337  		return fmt.Errorf("Missing parameter")
   338  	}
   339  
   340  	var job = eng.Job("history", vars["name"])
   341  	streamJSON(job, w, false)
   342  
   343  	if err := job.Run(); err != nil {
   344  		return err
   345  	}
   346  	return nil
   347  }
   348  
   349  func getContainersChanges(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   350  	if vars == nil {
   351  		return fmt.Errorf("Missing parameter")
   352  	}
   353  	var job = eng.Job("container_changes", vars["name"])
   354  	streamJSON(job, w, false)
   355  
   356  	return job.Run()
   357  }
   358  
   359  func getContainersTop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   360  	if version.LessThan("1.4") {
   361  		return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
   362  	}
   363  	if vars == nil {
   364  		return fmt.Errorf("Missing parameter")
   365  	}
   366  	if err := parseForm(r); err != nil {
   367  		return err
   368  	}
   369  
   370  	job := eng.Job("top", vars["name"], r.Form.Get("ps_args"))
   371  	streamJSON(job, w, false)
   372  	return job.Run()
   373  }
   374  
   375  func getContainersJSON(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   376  	if err := parseForm(r); err != nil {
   377  		return err
   378  	}
   379  	var (
   380  		err  error
   381  		outs *engine.Table
   382  		job  = eng.Job("containers")
   383  	)
   384  
   385  	job.Setenv("all", r.Form.Get("all"))
   386  	job.Setenv("size", r.Form.Get("size"))
   387  	job.Setenv("since", r.Form.Get("since"))
   388  	job.Setenv("before", r.Form.Get("before"))
   389  	job.Setenv("limit", r.Form.Get("limit"))
   390  	job.Setenv("filters", r.Form.Get("filters"))
   391  
   392  	if version.GreaterThanOrEqualTo("1.5") {
   393  		streamJSON(job, w, false)
   394  	} else if outs, err = job.Stdout.AddTable(); err != nil {
   395  		return err
   396  	}
   397  	if err = job.Run(); err != nil {
   398  		return err
   399  	}
   400  	if version.LessThan("1.5") { // Convert to legacy format
   401  		for _, out := range outs.Data {
   402  			ports := engine.NewTable("", 0)
   403  			ports.ReadListFrom([]byte(out.Get("Ports")))
   404  			out.Set("Ports", api.DisplayablePorts(ports))
   405  		}
   406  		w.Header().Set("Content-Type", "application/json")
   407  		if _, err = outs.WriteListTo(w); err != nil {
   408  			return err
   409  		}
   410  	}
   411  	return nil
   412  }
   413  
   414  func getContainersLogs(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   415  	if err := parseForm(r); err != nil {
   416  		return err
   417  	}
   418  	if vars == nil {
   419  		return fmt.Errorf("Missing parameter")
   420  	}
   421  
   422  	var (
   423  		inspectJob = eng.Job("container_inspect", vars["name"])
   424  		logsJob    = eng.Job("logs", vars["name"])
   425  		c, err     = inspectJob.Stdout.AddEnv()
   426  	)
   427  	if err != nil {
   428  		return err
   429  	}
   430  	logsJob.Setenv("follow", r.Form.Get("follow"))
   431  	logsJob.Setenv("tail", r.Form.Get("tail"))
   432  	logsJob.Setenv("stdout", r.Form.Get("stdout"))
   433  	logsJob.Setenv("stderr", r.Form.Get("stderr"))
   434  	logsJob.Setenv("timestamps", r.Form.Get("timestamps"))
   435  	// Validate args here, because we can't return not StatusOK after job.Run() call
   436  	stdout, stderr := logsJob.GetenvBool("stdout"), logsJob.GetenvBool("stderr")
   437  	if !(stdout || stderr) {
   438  		return fmt.Errorf("Bad parameters: you must choose at least one stream")
   439  	}
   440  	if err = inspectJob.Run(); err != nil {
   441  		return err
   442  	}
   443  
   444  	var outStream, errStream io.Writer
   445  	outStream = utils.NewWriteFlusher(w)
   446  
   447  	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
   448  		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
   449  		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
   450  	} else {
   451  		errStream = outStream
   452  	}
   453  
   454  	logsJob.Stdout.Add(outStream)
   455  	logsJob.Stderr.Set(errStream)
   456  	if err := logsJob.Run(); err != nil {
   457  		fmt.Fprintf(outStream, "Error running logs job: %s\n", err)
   458  	}
   459  	return nil
   460  }
   461  
   462  func postImagesTag(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   463  	if err := parseForm(r); err != nil {
   464  		return err
   465  	}
   466  	if vars == nil {
   467  		return fmt.Errorf("Missing parameter")
   468  	}
   469  
   470  	job := eng.Job("tag", vars["name"], r.Form.Get("repo"), r.Form.Get("tag"))
   471  	job.Setenv("force", r.Form.Get("force"))
   472  	if err := job.Run(); err != nil {
   473  		return err
   474  	}
   475  	w.WriteHeader(http.StatusCreated)
   476  	return nil
   477  }
   478  
   479  func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   480  	if err := parseForm(r); err != nil {
   481  		return err
   482  	}
   483  	var (
   484  		config       engine.Env
   485  		env          engine.Env
   486  		job          = eng.Job("commit", r.Form.Get("container"))
   487  		stdoutBuffer = bytes.NewBuffer(nil)
   488  	)
   489  
   490  	if err := checkForJson(r); err != nil {
   491  		return err
   492  	}
   493  
   494  	if err := config.Decode(r.Body); err != nil {
   495  		log.Errorf("%s", err)
   496  	}
   497  
   498  	if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
   499  		job.Setenv("pause", "1")
   500  	} else {
   501  		job.Setenv("pause", r.FormValue("pause"))
   502  	}
   503  
   504  	job.Setenv("repo", r.Form.Get("repo"))
   505  	job.Setenv("tag", r.Form.Get("tag"))
   506  	job.Setenv("author", r.Form.Get("author"))
   507  	job.Setenv("comment", r.Form.Get("comment"))
   508  	job.SetenvSubEnv("config", &config)
   509  
   510  	job.Stdout.Add(stdoutBuffer)
   511  	if err := job.Run(); err != nil {
   512  		return err
   513  	}
   514  	env.Set("Id", engine.Tail(stdoutBuffer, 1))
   515  	return writeJSON(w, http.StatusCreated, env)
   516  }
   517  
   518  // Creates an image from Pull or from Import
   519  func postImagesCreate(eng *engine.Engine, 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  	var (
   525  		image = r.Form.Get("fromImage")
   526  		repo  = r.Form.Get("repo")
   527  		tag   = r.Form.Get("tag")
   528  		job   *engine.Job
   529  	)
   530  	authEncoded := r.Header.Get("X-Registry-Auth")
   531  	authConfig := &registry.AuthConfig{}
   532  	if authEncoded != "" {
   533  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   534  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
   535  			// for a pull it is not an error if no auth was given
   536  			// to increase compatibility with the existing api it is defaulting to be empty
   537  			authConfig = &registry.AuthConfig{}
   538  		}
   539  	}
   540  	if image != "" { //pull
   541  		if tag == "" {
   542  			image, tag = parsers.ParseRepositoryTag(image)
   543  		}
   544  		metaHeaders := map[string][]string{}
   545  		for k, v := range r.Header {
   546  			if strings.HasPrefix(k, "X-Meta-") {
   547  				metaHeaders[k] = v
   548  			}
   549  		}
   550  		job = eng.Job("pull", image, tag)
   551  		job.SetenvBool("parallel", version.GreaterThan("1.3"))
   552  		job.SetenvJson("metaHeaders", metaHeaders)
   553  		job.SetenvJson("authConfig", authConfig)
   554  	} else { //import
   555  		if tag == "" {
   556  			repo, tag = parsers.ParseRepositoryTag(repo)
   557  		}
   558  		job = eng.Job("import", r.Form.Get("fromSrc"), repo, tag)
   559  		job.Stdin.Add(r.Body)
   560  	}
   561  
   562  	if version.GreaterThan("1.0") {
   563  		job.SetenvBool("json", true)
   564  		streamJSON(job, w, true)
   565  	} else {
   566  		job.Stdout.Add(utils.NewWriteFlusher(w))
   567  	}
   568  	if err := job.Run(); err != nil {
   569  		if !job.Stdout.Used() {
   570  			return err
   571  		}
   572  		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
   573  		w.Write(sf.FormatError(err))
   574  	}
   575  
   576  	return nil
   577  }
   578  
   579  func getImagesSearch(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   580  	if err := parseForm(r); err != nil {
   581  		return err
   582  	}
   583  	var (
   584  		authEncoded = r.Header.Get("X-Registry-Auth")
   585  		authConfig  = &registry.AuthConfig{}
   586  		metaHeaders = map[string][]string{}
   587  	)
   588  
   589  	if authEncoded != "" {
   590  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   591  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
   592  			// for a search it is not an error if no auth was given
   593  			// to increase compatibility with the existing api it is defaulting to be empty
   594  			authConfig = &registry.AuthConfig{}
   595  		}
   596  	}
   597  	for k, v := range r.Header {
   598  		if strings.HasPrefix(k, "X-Meta-") {
   599  			metaHeaders[k] = v
   600  		}
   601  	}
   602  
   603  	var job = eng.Job("search", r.Form.Get("term"))
   604  	job.SetenvJson("metaHeaders", metaHeaders)
   605  	job.SetenvJson("authConfig", authConfig)
   606  	streamJSON(job, w, false)
   607  
   608  	return job.Run()
   609  }
   610  
   611  func getImageManifest(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   612  	if err := parseForm(r); err != nil {
   613  		return err
   614  	}
   615  
   616  	job := eng.Job("image_manifest", vars["name"])
   617  	job.Setenv("tag", r.Form.Get("tag"))
   618  	job.Stdout.Add(utils.NewWriteFlusher(w))
   619  
   620  	return job.Run()
   621  }
   622  
   623  func postImagesPush(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   624  	if vars == nil {
   625  		return fmt.Errorf("Missing parameter")
   626  	}
   627  
   628  	metaHeaders := map[string][]string{}
   629  	for k, v := range r.Header {
   630  		if strings.HasPrefix(k, "X-Meta-") {
   631  			metaHeaders[k] = v
   632  		}
   633  	}
   634  	if err := parseForm(r); err != nil {
   635  		return err
   636  	}
   637  	authConfig := &registry.AuthConfig{}
   638  
   639  	authEncoded := r.Header.Get("X-Registry-Auth")
   640  	if authEncoded != "" {
   641  		// the new format is to handle the authConfig as a header
   642  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
   643  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
   644  			// to increase compatibility to existing api it is defaulting to be empty
   645  			authConfig = &registry.AuthConfig{}
   646  		}
   647  	} else {
   648  		// the old format is supported for compatibility if there was no authConfig header
   649  		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
   650  			return err
   651  		}
   652  	}
   653  
   654  	manifest, err := ioutil.ReadAll(r.Body)
   655  	if err != nil {
   656  		return err
   657  	}
   658  
   659  	job := eng.Job("push", vars["name"])
   660  	job.SetenvJson("metaHeaders", metaHeaders)
   661  	job.SetenvJson("authConfig", authConfig)
   662  	job.Setenv("manifest", string(manifest))
   663  	job.Setenv("tag", r.Form.Get("tag"))
   664  	if version.GreaterThan("1.0") {
   665  		job.SetenvBool("json", true)
   666  		streamJSON(job, w, true)
   667  	} else {
   668  		job.Stdout.Add(utils.NewWriteFlusher(w))
   669  	}
   670  
   671  	if err := job.Run(); err != nil {
   672  		if !job.Stdout.Used() {
   673  			return err
   674  		}
   675  		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
   676  		w.Write(sf.FormatError(err))
   677  	}
   678  	return nil
   679  }
   680  
   681  func getImagesGet(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   682  	if vars == nil {
   683  		return fmt.Errorf("Missing parameter")
   684  	}
   685  	if err := parseForm(r); err != nil {
   686  		return err
   687  	}
   688  	if version.GreaterThan("1.0") {
   689  		w.Header().Set("Content-Type", "application/x-tar")
   690  	}
   691  	var job *engine.Job
   692  	if name, ok := vars["name"]; ok {
   693  		job = eng.Job("image_export", name)
   694  	} else {
   695  		job = eng.Job("image_export", r.Form["names"]...)
   696  	}
   697  	job.Stdout.Add(w)
   698  	return job.Run()
   699  }
   700  
   701  func postImagesLoad(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   702  	job := eng.Job("load")
   703  	job.Stdin.Add(r.Body)
   704  	return job.Run()
   705  }
   706  
   707  func postContainersCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   708  	if err := parseForm(r); err != nil {
   709  		return nil
   710  	}
   711  	var (
   712  		out          engine.Env
   713  		job          = eng.Job("create", r.Form.Get("name"))
   714  		outWarnings  []string
   715  		stdoutBuffer = bytes.NewBuffer(nil)
   716  		warnings     = bytes.NewBuffer(nil)
   717  	)
   718  
   719  	if err := checkForJson(r); err != nil {
   720  		return err
   721  	}
   722  
   723  	if err := job.DecodeEnv(r.Body); err != nil {
   724  		return err
   725  	}
   726  	// Read container ID from the first line of stdout
   727  	job.Stdout.Add(stdoutBuffer)
   728  	// Read warnings from stderr
   729  	job.Stderr.Add(warnings)
   730  	if err := job.Run(); err != nil {
   731  		return err
   732  	}
   733  	// Parse warnings from stderr
   734  	scanner := bufio.NewScanner(warnings)
   735  	for scanner.Scan() {
   736  		outWarnings = append(outWarnings, scanner.Text())
   737  	}
   738  	out.Set("Id", engine.Tail(stdoutBuffer, 1))
   739  	out.SetList("Warnings", outWarnings)
   740  
   741  	return writeJSON(w, http.StatusCreated, out)
   742  }
   743  
   744  func postContainersRestart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   745  	if err := parseForm(r); err != nil {
   746  		return err
   747  	}
   748  	if vars == nil {
   749  		return fmt.Errorf("Missing parameter")
   750  	}
   751  	job := eng.Job("restart", vars["name"])
   752  	job.Setenv("t", r.Form.Get("t"))
   753  	if err := job.Run(); err != nil {
   754  		return err
   755  	}
   756  	w.WriteHeader(http.StatusNoContent)
   757  	return nil
   758  }
   759  
   760  func postContainerRename(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   761  	if err := parseForm(r); err != nil {
   762  		return err
   763  	}
   764  	if vars == nil {
   765  		return fmt.Errorf("Missing parameter")
   766  	}
   767  
   768  	newName := r.URL.Query().Get("name")
   769  	job := eng.Job("container_rename", vars["name"], newName)
   770  	job.Setenv("t", r.Form.Get("t"))
   771  	if err := job.Run(); err != nil {
   772  		return err
   773  	}
   774  	w.WriteHeader(http.StatusNoContent)
   775  	return nil
   776  }
   777  
   778  func deleteContainers(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   779  	if err := parseForm(r); err != nil {
   780  		return err
   781  	}
   782  	if vars == nil {
   783  		return fmt.Errorf("Missing parameter")
   784  	}
   785  	job := eng.Job("rm", vars["name"])
   786  
   787  	job.Setenv("forceRemove", r.Form.Get("force"))
   788  
   789  	job.Setenv("removeVolume", r.Form.Get("v"))
   790  	job.Setenv("removeLink", r.Form.Get("link"))
   791  	if err := job.Run(); err != nil {
   792  		return err
   793  	}
   794  	w.WriteHeader(http.StatusNoContent)
   795  	return nil
   796  }
   797  
   798  func deleteImages(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   799  	if err := parseForm(r); err != nil {
   800  		return err
   801  	}
   802  	if vars == nil {
   803  		return fmt.Errorf("Missing parameter")
   804  	}
   805  	var job = eng.Job("image_delete", vars["name"])
   806  	streamJSON(job, w, false)
   807  	job.Setenv("force", r.Form.Get("force"))
   808  	job.Setenv("noprune", r.Form.Get("noprune"))
   809  
   810  	return job.Run()
   811  }
   812  
   813  func postContainersStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   814  	if vars == nil {
   815  		return fmt.Errorf("Missing parameter")
   816  	}
   817  	var (
   818  		name = vars["name"]
   819  		job  = eng.Job("start", name)
   820  	)
   821  
   822  	// If contentLength is -1, we can assumed chunked encoding
   823  	// or more technically that the length is unknown
   824  	// http://golang.org/src/pkg/net/http/request.go#L139
   825  	// net/http otherwise seems to swallow any headers related to chunked encoding
   826  	// including r.TransferEncoding
   827  	// allow a nil body for backwards compatibility
   828  	if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
   829  		if err := checkForJson(r); err != nil {
   830  			return err
   831  		}
   832  
   833  		if err := job.DecodeEnv(r.Body); err != nil {
   834  			return err
   835  		}
   836  	}
   837  
   838  	if err := job.Run(); err != nil {
   839  		if err.Error() == "Container already started" {
   840  			w.WriteHeader(http.StatusNotModified)
   841  			return nil
   842  		}
   843  		return err
   844  	}
   845  	w.WriteHeader(http.StatusNoContent)
   846  	return nil
   847  }
   848  
   849  func postContainersStop(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   850  	if err := parseForm(r); err != nil {
   851  		return err
   852  	}
   853  	if vars == nil {
   854  		return fmt.Errorf("Missing parameter")
   855  	}
   856  	job := eng.Job("stop", vars["name"])
   857  	job.Setenv("t", r.Form.Get("t"))
   858  	if err := job.Run(); err != nil {
   859  		if err.Error() == "Container already stopped" {
   860  			w.WriteHeader(http.StatusNotModified)
   861  			return nil
   862  		}
   863  		return err
   864  	}
   865  	w.WriteHeader(http.StatusNoContent)
   866  	return nil
   867  }
   868  
   869  func postContainersWait(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   870  	if vars == nil {
   871  		return fmt.Errorf("Missing parameter")
   872  	}
   873  	var (
   874  		env          engine.Env
   875  		stdoutBuffer = bytes.NewBuffer(nil)
   876  		job          = eng.Job("wait", vars["name"])
   877  	)
   878  	job.Stdout.Add(stdoutBuffer)
   879  	if err := job.Run(); err != nil {
   880  		return err
   881  	}
   882  
   883  	env.Set("StatusCode", engine.Tail(stdoutBuffer, 1))
   884  	return writeJSON(w, http.StatusOK, env)
   885  }
   886  
   887  func postContainersResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   888  	if err := parseForm(r); err != nil {
   889  		return err
   890  	}
   891  	if vars == nil {
   892  		return fmt.Errorf("Missing parameter")
   893  	}
   894  	if err := eng.Job("resize", vars["name"], r.Form.Get("h"), r.Form.Get("w")).Run(); err != nil {
   895  		return err
   896  	}
   897  	return nil
   898  }
   899  
   900  func postContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   901  	if err := parseForm(r); err != nil {
   902  		return err
   903  	}
   904  	if vars == nil {
   905  		return fmt.Errorf("Missing parameter")
   906  	}
   907  
   908  	var (
   909  		job    = eng.Job("container_inspect", vars["name"])
   910  		c, err = job.Stdout.AddEnv()
   911  	)
   912  	if err != nil {
   913  		return err
   914  	}
   915  	if err = job.Run(); err != nil {
   916  		return err
   917  	}
   918  
   919  	inStream, outStream, err := hijackServer(w)
   920  	if err != nil {
   921  		return err
   922  	}
   923  	defer closeStreams(inStream, outStream)
   924  
   925  	var errStream io.Writer
   926  
   927  	if _, ok := r.Header["Upgrade"]; ok {
   928  		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")
   929  	} else {
   930  		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
   931  	}
   932  
   933  	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
   934  		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
   935  		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
   936  	} else {
   937  		errStream = outStream
   938  	}
   939  
   940  	job = eng.Job("attach", vars["name"])
   941  	job.Setenv("logs", r.Form.Get("logs"))
   942  	job.Setenv("stream", r.Form.Get("stream"))
   943  	job.Setenv("stdin", r.Form.Get("stdin"))
   944  	job.Setenv("stdout", r.Form.Get("stdout"))
   945  	job.Setenv("stderr", r.Form.Get("stderr"))
   946  	job.Stdin.Add(inStream)
   947  	job.Stdout.Add(outStream)
   948  	job.Stderr.Set(errStream)
   949  	if err := job.Run(); err != nil {
   950  		fmt.Fprintf(outStream, "Error attaching: %s\n", err)
   951  
   952  	}
   953  	return nil
   954  }
   955  
   956  func wsContainersAttach(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   957  	if err := parseForm(r); err != nil {
   958  		return err
   959  	}
   960  	if vars == nil {
   961  		return fmt.Errorf("Missing parameter")
   962  	}
   963  
   964  	if err := eng.Job("container_inspect", vars["name"]).Run(); err != nil {
   965  		return err
   966  	}
   967  
   968  	h := websocket.Handler(func(ws *websocket.Conn) {
   969  		defer ws.Close()
   970  		job := eng.Job("attach", vars["name"])
   971  		job.Setenv("logs", r.Form.Get("logs"))
   972  		job.Setenv("stream", r.Form.Get("stream"))
   973  		job.Setenv("stdin", r.Form.Get("stdin"))
   974  		job.Setenv("stdout", r.Form.Get("stdout"))
   975  		job.Setenv("stderr", r.Form.Get("stderr"))
   976  		job.Stdin.Add(ws)
   977  		job.Stdout.Add(ws)
   978  		job.Stderr.Set(ws)
   979  		if err := job.Run(); err != nil {
   980  			log.Errorf("Error attaching websocket: %s", err)
   981  		}
   982  	})
   983  	h.ServeHTTP(w, r)
   984  
   985  	return nil
   986  }
   987  
   988  func getContainersByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   989  	if vars == nil {
   990  		return fmt.Errorf("Missing parameter")
   991  	}
   992  	var job = eng.Job("container_inspect", vars["name"])
   993  	if version.LessThan("1.12") {
   994  		job.SetenvBool("raw", true)
   995  	}
   996  	streamJSON(job, w, false)
   997  	return job.Run()
   998  }
   999  
  1000  func getExecByID(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1001  	if vars == nil {
  1002  		return fmt.Errorf("Missing parameter 'id'")
  1003  	}
  1004  	var job = eng.Job("execInspect", vars["id"])
  1005  	streamJSON(job, w, false)
  1006  	return job.Run()
  1007  }
  1008  
  1009  func getImagesByName(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1010  	if vars == nil {
  1011  		return fmt.Errorf("Missing parameter")
  1012  	}
  1013  	var job = eng.Job("image_inspect", vars["name"])
  1014  	if version.LessThan("1.12") {
  1015  		job.SetenvBool("raw", true)
  1016  	}
  1017  	streamJSON(job, w, false)
  1018  	return job.Run()
  1019  }
  1020  
  1021  func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1022  	if version.LessThan("1.3") {
  1023  		return fmt.Errorf("Multipart upload for build is no longer supported. Please upgrade your docker client.")
  1024  	}
  1025  	var (
  1026  		authEncoded       = r.Header.Get("X-Registry-Auth")
  1027  		authConfig        = &registry.AuthConfig{}
  1028  		configFileEncoded = r.Header.Get("X-Registry-Config")
  1029  		configFile        = &registry.ConfigFile{}
  1030  		job               = eng.Job("build")
  1031  	)
  1032  
  1033  	// This block can be removed when API versions prior to 1.9 are deprecated.
  1034  	// Both headers will be parsed and sent along to the daemon, but if a non-empty
  1035  	// ConfigFile is present, any value provided as an AuthConfig directly will
  1036  	// be overridden. See BuildFile::CmdFrom for details.
  1037  	if version.LessThan("1.9") && authEncoded != "" {
  1038  		authJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
  1039  		if err := json.NewDecoder(authJson).Decode(authConfig); err != nil {
  1040  			// for a pull it is not an error if no auth was given
  1041  			// to increase compatibility with the existing api it is defaulting to be empty
  1042  			authConfig = &registry.AuthConfig{}
  1043  		}
  1044  	}
  1045  
  1046  	if configFileEncoded != "" {
  1047  		configFileJson := base64.NewDecoder(base64.URLEncoding, strings.NewReader(configFileEncoded))
  1048  		if err := json.NewDecoder(configFileJson).Decode(configFile); err != nil {
  1049  			// for a pull it is not an error if no auth was given
  1050  			// to increase compatibility with the existing api it is defaulting to be empty
  1051  			configFile = &registry.ConfigFile{}
  1052  		}
  1053  	}
  1054  
  1055  	if version.GreaterThanOrEqualTo("1.8") {
  1056  		job.SetenvBool("json", true)
  1057  		streamJSON(job, w, true)
  1058  	} else {
  1059  		job.Stdout.Add(utils.NewWriteFlusher(w))
  1060  	}
  1061  
  1062  	if r.FormValue("forcerm") == "1" && version.GreaterThanOrEqualTo("1.12") {
  1063  		job.Setenv("rm", "1")
  1064  	} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
  1065  		job.Setenv("rm", "1")
  1066  	} else {
  1067  		job.Setenv("rm", r.FormValue("rm"))
  1068  	}
  1069  	if r.FormValue("pull") == "1" && version.GreaterThanOrEqualTo("1.16") {
  1070  		job.Setenv("pull", "1")
  1071  	}
  1072  	job.Stdin.Add(r.Body)
  1073  	job.Setenv("remote", r.FormValue("remote"))
  1074  	job.Setenv("dockerfile", r.FormValue("dockerfile"))
  1075  	job.Setenv("t", r.FormValue("t"))
  1076  	job.Setenv("q", r.FormValue("q"))
  1077  	job.Setenv("nocache", r.FormValue("nocache"))
  1078  	job.Setenv("forcerm", r.FormValue("forcerm"))
  1079  	job.SetenvJson("authConfig", authConfig)
  1080  	job.SetenvJson("configFile", configFile)
  1081  
  1082  	if err := job.Run(); err != nil {
  1083  		if !job.Stdout.Used() {
  1084  			return err
  1085  		}
  1086  		sf := utils.NewStreamFormatter(version.GreaterThanOrEqualTo("1.8"))
  1087  		w.Write(sf.FormatError(err))
  1088  	}
  1089  	return nil
  1090  }
  1091  
  1092  func postContainersCopy(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1093  	if vars == nil {
  1094  		return fmt.Errorf("Missing parameter")
  1095  	}
  1096  
  1097  	var copyData engine.Env
  1098  
  1099  	if err := checkForJson(r); err != nil {
  1100  		return err
  1101  	}
  1102  
  1103  	if err := copyData.Decode(r.Body); err != nil {
  1104  		return err
  1105  	}
  1106  
  1107  	if copyData.Get("Resource") == "" {
  1108  		return fmt.Errorf("Path cannot be empty")
  1109  	}
  1110  
  1111  	origResource := copyData.Get("Resource")
  1112  
  1113  	if copyData.Get("Resource")[0] == '/' {
  1114  		copyData.Set("Resource", copyData.Get("Resource")[1:])
  1115  	}
  1116  
  1117  	job := eng.Job("container_copy", vars["name"], copyData.Get("Resource"))
  1118  	job.Stdout.Add(w)
  1119  	w.Header().Set("Content-Type", "application/x-tar")
  1120  	if err := job.Run(); err != nil {
  1121  		log.Errorf("%s", err.Error())
  1122  		if strings.Contains(strings.ToLower(err.Error()), "no such container") {
  1123  			w.WriteHeader(http.StatusNotFound)
  1124  		} else if strings.Contains(err.Error(), "no such file or directory") {
  1125  			return fmt.Errorf("Could not find the file %s in container %s", origResource, vars["name"])
  1126  		}
  1127  	}
  1128  	return nil
  1129  }
  1130  
  1131  func postContainerExecCreate(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1132  	if err := parseForm(r); err != nil {
  1133  		return nil
  1134  	}
  1135  	var (
  1136  		out          engine.Env
  1137  		name         = vars["name"]
  1138  		job          = eng.Job("execCreate", name)
  1139  		stdoutBuffer = bytes.NewBuffer(nil)
  1140  	)
  1141  
  1142  	if err := job.DecodeEnv(r.Body); err != nil {
  1143  		return err
  1144  	}
  1145  
  1146  	job.Stdout.Add(stdoutBuffer)
  1147  	// Register an instance of Exec in container.
  1148  	if err := job.Run(); err != nil {
  1149  		fmt.Fprintf(os.Stderr, "Error setting up exec command in container %s: %s\n", name, err)
  1150  		return err
  1151  	}
  1152  	// Return the ID
  1153  	out.Set("Id", engine.Tail(stdoutBuffer, 1))
  1154  
  1155  	return writeJSON(w, http.StatusCreated, out)
  1156  }
  1157  
  1158  // TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
  1159  func postContainerExecStart(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1160  	if err := parseForm(r); err != nil {
  1161  		return nil
  1162  	}
  1163  	var (
  1164  		name             = vars["name"]
  1165  		job              = eng.Job("execStart", name)
  1166  		errOut io.Writer = os.Stderr
  1167  	)
  1168  
  1169  	if err := job.DecodeEnv(r.Body); err != nil {
  1170  		return err
  1171  	}
  1172  	if !job.GetenvBool("Detach") {
  1173  		// Setting up the streaming http interface.
  1174  		inStream, outStream, err := hijackServer(w)
  1175  		if err != nil {
  1176  			return err
  1177  		}
  1178  		defer closeStreams(inStream, outStream)
  1179  
  1180  		var errStream io.Writer
  1181  
  1182  		if _, ok := r.Header["Upgrade"]; ok {
  1183  			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")
  1184  		} else {
  1185  			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
  1186  		}
  1187  
  1188  		if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
  1189  			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
  1190  			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
  1191  		} else {
  1192  			errStream = outStream
  1193  		}
  1194  		job.Stdin.Add(inStream)
  1195  		job.Stdout.Add(outStream)
  1196  		job.Stderr.Set(errStream)
  1197  		errOut = outStream
  1198  	}
  1199  	// Now run the user process in container.
  1200  	job.SetCloseIO(false)
  1201  	if err := job.Run(); err != nil {
  1202  		fmt.Fprintf(errOut, "Error starting exec command in container %s: %s\n", name, err)
  1203  		return err
  1204  	}
  1205  	w.WriteHeader(http.StatusNoContent)
  1206  
  1207  	return nil
  1208  }
  1209  
  1210  func postContainerExecResize(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1211  	if err := parseForm(r); err != nil {
  1212  		return err
  1213  	}
  1214  	if vars == nil {
  1215  		return fmt.Errorf("Missing parameter")
  1216  	}
  1217  	if err := eng.Job("execResize", vars["name"], r.Form.Get("h"), r.Form.Get("w")).Run(); err != nil {
  1218  		return err
  1219  	}
  1220  	return nil
  1221  }
  1222  
  1223  func optionsHandler(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1224  	w.WriteHeader(http.StatusOK)
  1225  	return nil
  1226  }
  1227  func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
  1228  	w.Header().Add("Access-Control-Allow-Origin", "*")
  1229  	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
  1230  	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
  1231  }
  1232  
  1233  func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
  1234  	_, err := w.Write([]byte{'O', 'K'})
  1235  	return err
  1236  }
  1237  
  1238  func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
  1239  	return func(w http.ResponseWriter, r *http.Request) {
  1240  		// log the request
  1241  		log.Debugf("Calling %s %s", localMethod, localRoute)
  1242  
  1243  		if logging {
  1244  			log.Infof("%s %s", r.Method, r.RequestURI)
  1245  		}
  1246  
  1247  		if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
  1248  			userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
  1249  			if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
  1250  				log.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
  1251  			}
  1252  		}
  1253  		version := version.Version(mux.Vars(r)["version"])
  1254  		if version == "" {
  1255  			version = api.APIVERSION
  1256  		}
  1257  		if enableCors {
  1258  			writeCorsHeaders(w, r)
  1259  		}
  1260  
  1261  		if version.GreaterThan(api.APIVERSION) {
  1262  			http.Error(w, fmt.Errorf("client and server don't have same version (client : %s, server: %s)", version, api.APIVERSION).Error(), http.StatusNotFound)
  1263  			return
  1264  		}
  1265  
  1266  		if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
  1267  			log.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
  1268  			httpError(w, err)
  1269  		}
  1270  	}
  1271  }
  1272  
  1273  // Replicated from expvar.go as not public.
  1274  func expvarHandler(w http.ResponseWriter, r *http.Request) {
  1275  	w.Header().Set("Content-Type", "application/json; charset=utf-8")
  1276  	fmt.Fprintf(w, "{\n")
  1277  	first := true
  1278  	expvar.Do(func(kv expvar.KeyValue) {
  1279  		if !first {
  1280  			fmt.Fprintf(w, ",\n")
  1281  		}
  1282  		first = false
  1283  		fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
  1284  	})
  1285  	fmt.Fprintf(w, "\n}\n")
  1286  }
  1287  
  1288  func AttachProfiler(router *mux.Router) {
  1289  	router.HandleFunc("/debug/vars", expvarHandler)
  1290  	router.HandleFunc("/debug/pprof/", pprof.Index)
  1291  	router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
  1292  	router.HandleFunc("/debug/pprof/profile", pprof.Profile)
  1293  	router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  1294  	router.HandleFunc("/debug/pprof/block", pprof.Handler("block").ServeHTTP)
  1295  	router.HandleFunc("/debug/pprof/heap", pprof.Handler("heap").ServeHTTP)
  1296  	router.HandleFunc("/debug/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
  1297  	router.HandleFunc("/debug/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
  1298  }
  1299  
  1300  func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion string) *mux.Router {
  1301  	r := mux.NewRouter()
  1302  	if os.Getenv("DEBUG") != "" {
  1303  		AttachProfiler(r)
  1304  	}
  1305  	m := map[string]map[string]HttpApiFunc{
  1306  		"GET": {
  1307  			"/_ping":                          ping,
  1308  			"/events":                         getEvents,
  1309  			"/info":                           getInfo,
  1310  			"/version":                        getVersion,
  1311  			"/images/json":                    getImagesJSON,
  1312  			"/images/viz":                     getImagesViz,
  1313  			"/images/search":                  getImagesSearch,
  1314  			"/images/get":                     getImagesGet,
  1315  			"/images/{name:.*}/manifest":      getImageManifest,
  1316  			"/images/{name:.*}/get":           getImagesGet,
  1317  			"/images/{name:.*}/history":       getImagesHistory,
  1318  			"/images/{name:.*}/json":          getImagesByName,
  1319  			"/containers/ps":                  getContainersJSON,
  1320  			"/containers/json":                getContainersJSON,
  1321  			"/containers/{name:.*}/export":    getContainersExport,
  1322  			"/containers/{name:.*}/changes":   getContainersChanges,
  1323  			"/containers/{name:.*}/json":      getContainersByName,
  1324  			"/containers/{name:.*}/top":       getContainersTop,
  1325  			"/containers/{name:.*}/logs":      getContainersLogs,
  1326  			"/containers/{name:.*}/attach/ws": wsContainersAttach,
  1327  			"/exec/{id:.*}/json":              getExecByID,
  1328  		},
  1329  		"POST": {
  1330  			"/auth":                         postAuth,
  1331  			"/commit":                       postCommit,
  1332  			"/build":                        postBuild,
  1333  			"/images/create":                postImagesCreate,
  1334  			"/images/load":                  postImagesLoad,
  1335  			"/images/{name:.*}/push":        postImagesPush,
  1336  			"/images/{name:.*}/tag":         postImagesTag,
  1337  			"/containers/create":            postContainersCreate,
  1338  			"/containers/{name:.*}/kill":    postContainersKill,
  1339  			"/containers/{name:.*}/pause":   postContainersPause,
  1340  			"/containers/{name:.*}/unpause": postContainersUnpause,
  1341  			"/containers/{name:.*}/restart": postContainersRestart,
  1342  			"/containers/{name:.*}/start":   postContainersStart,
  1343  			"/containers/{name:.*}/stop":    postContainersStop,
  1344  			"/containers/{name:.*}/wait":    postContainersWait,
  1345  			"/containers/{name:.*}/resize":  postContainersResize,
  1346  			"/containers/{name:.*}/attach":  postContainersAttach,
  1347  			"/containers/{name:.*}/copy":    postContainersCopy,
  1348  			"/containers/{name:.*}/exec":    postContainerExecCreate,
  1349  			"/exec/{name:.*}/start":         postContainerExecStart,
  1350  			"/exec/{name:.*}/resize":        postContainerExecResize,
  1351  			"/containers/{name:.*}/rename":  postContainerRename,
  1352  		},
  1353  		"DELETE": {
  1354  			"/containers/{name:.*}": deleteContainers,
  1355  			"/images/{name:.*}":     deleteImages,
  1356  		},
  1357  		"OPTIONS": {
  1358  			"": optionsHandler,
  1359  		},
  1360  	}
  1361  
  1362  	for method, routes := range m {
  1363  		for route, fct := range routes {
  1364  			log.Debugf("Registering %s, %s", method, route)
  1365  			// NOTE: scope issue, make sure the variables are local and won't be changed
  1366  			localRoute := route
  1367  			localFct := fct
  1368  			localMethod := method
  1369  
  1370  			// build the handler function
  1371  			f := makeHttpHandler(eng, logging, localMethod, localRoute, localFct, enableCors, version.Version(dockerVersion))
  1372  
  1373  			// add the new route
  1374  			if localRoute == "" {
  1375  				r.Methods(localMethod).HandlerFunc(f)
  1376  			} else {
  1377  				r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
  1378  				r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
  1379  			}
  1380  		}
  1381  	}
  1382  
  1383  	return r
  1384  }
  1385  
  1386  // ServeRequest processes a single http request to the docker remote api.
  1387  // FIXME: refactor this to be part of Server and not require re-creating a new
  1388  // router each time. This requires first moving ListenAndServe into Server.
  1389  func ServeRequest(eng *engine.Engine, apiversion version.Version, w http.ResponseWriter, req *http.Request) {
  1390  	router := createRouter(eng, false, true, "")
  1391  	// Insert APIVERSION into the request as a convenience
  1392  	req.URL.Path = fmt.Sprintf("/v%s%s", apiversion, req.URL.Path)
  1393  	router.ServeHTTP(w, req)
  1394  }
  1395  
  1396  // serveFd creates an http.Server and sets it up to serve given a socket activated
  1397  // argument.
  1398  func serveFd(addr string, job *engine.Job) error {
  1399  	r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
  1400  
  1401  	ls, e := systemd.ListenFD(addr)
  1402  	if e != nil {
  1403  		return e
  1404  	}
  1405  
  1406  	chErrors := make(chan error, len(ls))
  1407  
  1408  	// We don't want to start serving on these sockets until the
  1409  	// daemon is initialized and installed. Otherwise required handlers
  1410  	// won't be ready.
  1411  	<-activationLock
  1412  
  1413  	// Since ListenFD will return one or more sockets we have
  1414  	// to create a go func to spawn off multiple serves
  1415  	for i := range ls {
  1416  		listener := ls[i]
  1417  		go func() {
  1418  			httpSrv := http.Server{Handler: r}
  1419  			chErrors <- httpSrv.Serve(listener)
  1420  		}()
  1421  	}
  1422  
  1423  	for i := 0; i < len(ls); i++ {
  1424  		err := <-chErrors
  1425  		if err != nil {
  1426  			return err
  1427  		}
  1428  	}
  1429  
  1430  	return nil
  1431  }
  1432  
  1433  func lookupGidByName(nameOrGid string) (int, error) {
  1434  	groupFile, err := user.GetGroupPath()
  1435  	if err != nil {
  1436  		return -1, err
  1437  	}
  1438  	groups, err := user.ParseGroupFileFilter(groupFile, func(g user.Group) bool {
  1439  		return g.Name == nameOrGid || strconv.Itoa(g.Gid) == nameOrGid
  1440  	})
  1441  	if err != nil {
  1442  		return -1, err
  1443  	}
  1444  	if groups != nil && len(groups) > 0 {
  1445  		return groups[0].Gid, nil
  1446  	}
  1447  	return -1, fmt.Errorf("Group %s not found", nameOrGid)
  1448  }
  1449  
  1450  func setupTls(cert, key, ca string, l net.Listener) (net.Listener, error) {
  1451  	tlsCert, err := tls.LoadX509KeyPair(cert, key)
  1452  	if err != nil {
  1453  		return nil, fmt.Errorf("Couldn't load X509 key pair (%s, %s): %s. Key encrypted?",
  1454  			cert, key, err)
  1455  	}
  1456  	tlsConfig := &tls.Config{
  1457  		NextProtos:   []string{"http/1.1"},
  1458  		Certificates: []tls.Certificate{tlsCert},
  1459  		// Avoid fallback on insecure SSL protocols
  1460  		MinVersion: tls.VersionTLS10,
  1461  	}
  1462  
  1463  	if ca != "" {
  1464  		certPool := x509.NewCertPool()
  1465  		file, err := ioutil.ReadFile(ca)
  1466  		if err != nil {
  1467  			return nil, fmt.Errorf("Couldn't read CA certificate: %s", err)
  1468  		}
  1469  		certPool.AppendCertsFromPEM(file)
  1470  		tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
  1471  		tlsConfig.ClientCAs = certPool
  1472  	}
  1473  
  1474  	return tls.NewListener(l, tlsConfig), nil
  1475  }
  1476  
  1477  func newListener(proto, addr string, bufferRequests bool) (net.Listener, error) {
  1478  	if bufferRequests {
  1479  		return listenbuffer.NewListenBuffer(proto, addr, activationLock)
  1480  	}
  1481  
  1482  	return net.Listen(proto, addr)
  1483  }
  1484  
  1485  func changeGroup(addr string, nameOrGid string) error {
  1486  	gid, err := lookupGidByName(nameOrGid)
  1487  	if err != nil {
  1488  		return err
  1489  	}
  1490  
  1491  	log.Debugf("%s group found. gid: %d", nameOrGid, gid)
  1492  	return os.Chown(addr, 0, gid)
  1493  }
  1494  
  1495  func setSocketGroup(addr, group string) error {
  1496  	if group == "" {
  1497  		return nil
  1498  	}
  1499  
  1500  	if err := changeGroup(addr, group); err != nil {
  1501  		if group != "docker" {
  1502  			return err
  1503  		}
  1504  		log.Debugf("Warning: could not chgrp %s to docker: %v", addr, err)
  1505  	}
  1506  
  1507  	return nil
  1508  }
  1509  
  1510  func setupUnixHttp(addr string, job *engine.Job) (*HttpServer, error) {
  1511  	r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
  1512  
  1513  	if err := syscall.Unlink(addr); err != nil && !os.IsNotExist(err) {
  1514  		return nil, err
  1515  	}
  1516  	mask := syscall.Umask(0777)
  1517  	defer syscall.Umask(mask)
  1518  
  1519  	l, err := newListener("unix", addr, job.GetenvBool("BufferRequests"))
  1520  	if err != nil {
  1521  		return nil, err
  1522  	}
  1523  
  1524  	if err := setSocketGroup(addr, job.Getenv("SocketGroup")); err != nil {
  1525  		return nil, err
  1526  	}
  1527  
  1528  	if err := os.Chmod(addr, 0660); err != nil {
  1529  		return nil, err
  1530  	}
  1531  
  1532  	return &HttpServer{&http.Server{Addr: addr, Handler: r}, l}, nil
  1533  }
  1534  
  1535  func allocateDaemonPort(addr string) error {
  1536  	host, port, err := net.SplitHostPort(addr)
  1537  	if err != nil {
  1538  		return err
  1539  	}
  1540  
  1541  	intPort, err := strconv.Atoi(port)
  1542  	if err != nil {
  1543  		return err
  1544  	}
  1545  
  1546  	var hostIPs []net.IP
  1547  	if parsedIP := net.ParseIP(host); parsedIP != nil {
  1548  		hostIPs = append(hostIPs, parsedIP)
  1549  	} else if hostIPs, err = net.LookupIP(host); err != nil {
  1550  		return fmt.Errorf("failed to lookup %s address in host specification", host)
  1551  	}
  1552  
  1553  	for _, hostIP := range hostIPs {
  1554  		if _, err := portallocator.RequestPort(hostIP, "tcp", intPort); err != nil {
  1555  			return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
  1556  		}
  1557  	}
  1558  	return nil
  1559  }
  1560  
  1561  func setupTcpHttp(addr string, job *engine.Job) (*HttpServer, error) {
  1562  	if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") {
  1563  		log.Infof("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
  1564  	}
  1565  
  1566  	r := createRouter(job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"))
  1567  
  1568  	l, err := newListener("tcp", addr, job.GetenvBool("BufferRequests"))
  1569  	if err != nil {
  1570  		return nil, err
  1571  	}
  1572  
  1573  	if err := allocateDaemonPort(addr); err != nil {
  1574  		return nil, err
  1575  	}
  1576  
  1577  	if job.GetenvBool("Tls") || job.GetenvBool("TlsVerify") {
  1578  		var tlsCa string
  1579  		if job.GetenvBool("TlsVerify") {
  1580  			tlsCa = job.Getenv("TlsCa")
  1581  		}
  1582  		l, err = setupTls(job.Getenv("TlsCert"), job.Getenv("TlsKey"), tlsCa, l)
  1583  		if err != nil {
  1584  			return nil, err
  1585  		}
  1586  	}
  1587  	return &HttpServer{&http.Server{Addr: addr, Handler: r}, l}, nil
  1588  }
  1589  
  1590  // NewServer sets up the required Server and does protocol specific checking.
  1591  func NewServer(proto, addr string, job *engine.Job) (Server, error) {
  1592  	// Basic error and sanity checking
  1593  	switch proto {
  1594  	case "fd":
  1595  		return nil, serveFd(addr, job)
  1596  	case "tcp":
  1597  		return setupTcpHttp(addr, job)
  1598  	case "unix":
  1599  		return setupUnixHttp(addr, job)
  1600  	default:
  1601  		return nil, fmt.Errorf("Invalid protocol format.")
  1602  	}
  1603  }
  1604  
  1605  type Server interface {
  1606  	Serve() error
  1607  	Close() error
  1608  }
  1609  
  1610  // ServeApi loops through all of the protocols sent in to docker and spawns
  1611  // off a go routine to setup a serving http.Server for each.
  1612  func ServeApi(job *engine.Job) engine.Status {
  1613  	if len(job.Args) == 0 {
  1614  		return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
  1615  	}
  1616  	var (
  1617  		protoAddrs = job.Args
  1618  		chErrors   = make(chan error, len(protoAddrs))
  1619  	)
  1620  	activationLock = make(chan struct{})
  1621  
  1622  	for _, protoAddr := range protoAddrs {
  1623  		protoAddrParts := strings.SplitN(protoAddr, "://", 2)
  1624  		if len(protoAddrParts) != 2 {
  1625  			return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
  1626  		}
  1627  		go func() {
  1628  			log.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
  1629  			srv, err := NewServer(protoAddrParts[0], protoAddrParts[1], job)
  1630  			if err != nil {
  1631  				chErrors <- err
  1632  				return
  1633  			}
  1634  			chErrors <- srv.Serve()
  1635  		}()
  1636  	}
  1637  
  1638  	for i := 0; i < len(protoAddrs); i++ {
  1639  		err := <-chErrors
  1640  		if err != nil {
  1641  			return job.Error(err)
  1642  		}
  1643  	}
  1644  
  1645  	return engine.StatusOK
  1646  }
  1647  
  1648  func AcceptConnections(job *engine.Job) engine.Status {
  1649  	// Tell the init daemon we are accepting requests
  1650  	go systemd.SdNotify("READY=1")
  1651  
  1652  	// close the lock so the listeners start accepting connections
  1653  	if activationLock != nil {
  1654  		close(activationLock)
  1655  	}
  1656  
  1657  	return engine.StatusOK
  1658  }