api.go
a11b3139
 package docker
 
 import (
c0d5d596
 	"encoding/json"
b295239d
 	"fmt"
f37399d2
 	"github.com/dotcloud/docker/auth"
2e69e172
 	"github.com/dotcloud/docker/utils"
a11b3139
 	"github.com/gorilla/mux"
57cfe72e
 	"io"
79e91058
 	"log"
3adf9ce0
 	"net"
a11b3139
 	"net/http"
3adf9ce0
 	"os"
1aa7f139
 	"strconv"
b295239d
 	"strings"
a11b3139
 )
 
c9062392
 const APIVERSION = 1.2
3adf9ce0
 const DEFAULTHTTPHOST string = "127.0.0.1"
 const DEFAULTHTTPPORT int = 4243
faae7220
 
57cfe72e
 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
 	conn, _, err := w.(http.Hijacker).Hijack()
04cd20fa
 	if err != nil {
 		return nil, nil, err
 	}
 	// Flush the options to make sure the client sets the raw mode
57cfe72e
 	conn.Write([]byte{})
 	return conn, conn, nil
04cd20fa
 }
 
954ecac3
 //If we don't do this, POST method without Content-type (even with empty body) will fail
 func parseForm(r *http.Request) error {
 	if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
 		return err
 	}
 	return nil
 }
 
0f135ad7
 func parseMultipartForm(r *http.Request) error {
 	if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
 		return err
 	}
 	return nil
 }
 
04cd20fa
 func httpError(w http.ResponseWriter, err error) {
 	if strings.HasPrefix(err.Error(), "No such") {
 		http.Error(w, err.Error(), http.StatusNotFound)
0c544357
 	} else if strings.HasPrefix(err.Error(), "Bad parameter") {
 		http.Error(w, err.Error(), http.StatusBadRequest)
67b20f2c
 	} else if strings.HasPrefix(err.Error(), "Conflict") {
 		http.Error(w, err.Error(), http.StatusConflict)
468e4c4b
 	} else if strings.HasPrefix(err.Error(), "Impossible") {
 		http.Error(w, err.Error(), http.StatusNotAcceptable)
04cd20fa
 	} else {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 	}
 }
 
fd224ee5
 func writeJSON(w http.ResponseWriter, b []byte) {
f7beba3a
 	w.Header().Set("Content-Type", "application/json")
 	w.Write(b)
 }
 
70d2123e
 // FIXME: Use stvconv.ParseBool() instead?
0c544357
 func getBoolParam(value string) (bool, error) {
 	if value == "1" || strings.ToLower(value) == "true" {
 		return true, nil
 	}
 	if value == "" || value == "0" || strings.ToLower(value) == "false" {
 		return false, nil
 	}
 	return false, fmt.Errorf("Bad parameter")
 }
 
3dd1e4d5
 func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if version > 1.1 {
 		w.WriteHeader(http.StatusNotFound)
 		return nil
 	}
 	authConfig, err := auth.LoadConfig(srv.runtime.root)
 	if err != nil {
 		if err != auth.ErrConfigFileMissing {
 			return err
 		}
 		authConfig = &auth.AuthConfig{}
 	}
 	b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
3dd1e4d5
 	return nil
 }
 
 func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	authConfig := &auth.AuthConfig{}
 	err := json.NewDecoder(r.Body).Decode(authConfig)
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
3dd1e4d5
 	status := ""
 	if version > 1.1 {
 		status, err = auth.Login(authConfig, false)
 		if err != nil {
 			return err
 		}
 	} else {
 		localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
 		if err != nil {
 			if err != auth.ErrConfigFileMissing {
 				return err
 			}
 		}
 		if authConfig.Username == localAuthConfig.Username {
 			authConfig.Password = localAuthConfig.Password
 		}
 
 		newAuthConfig := auth.NewAuthConfig(authConfig.Username, authConfig.Password, authConfig.Email, srv.runtime.root)
 		status, err = auth.Login(newAuthConfig, true)
 		if err != nil {
 			return err
 		}
 	}
b56b2da5
 	if status != "" {
fd224ee5
 		b, err := json.Marshal(&APIAuth{Status: status})
f37399d2
 		if err != nil {
7cc08234
 			return err
f37399d2
 		}
fd224ee5
 		writeJSON(w, b)
7cc08234
 		return nil
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
f37399d2
 
faae7220
 func getVersion(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
b56b2da5
 	m := srv.DockerVersion()
 	b, err := json.Marshal(m)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
f37399d2
 
faae7220
 func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	if err := srv.ContainerKill(name); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
f37399d2
 
faae7220
 func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
a11b3139
 
93dc2c33
 	if err := srv.ContainerExport(name, w); err != nil {
2e69e172
 		utils.Debugf("%s", err.Error())
8b31d306
 		return err
b56b2da5
 	}
7cc08234
 	return nil
b56b2da5
 }
1e357c69
 
fd224ee5
 func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
c7bbe7ca
 
0c544357
 	all, err := getBoolParam(r.Form.Get("all"))
 	if err != nil {
 		return err
 	}
c423a790
 	filter := r.Form.Get("filter")
c7bbe7ca
 
1990c49a
 	outs, err := srv.Images(all, filter)
c423a790
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
c423a790
 	b, err := json.Marshal(outs)
 	if err != nil {
7cc08234
 		return err
c423a790
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
c423a790
 }
 
faae7220
 func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
c423a790
 	if err := srv.ImagesViz(w); err != nil {
7cc08234
 		return err
c423a790
 	}
7cc08234
 	return nil
b56b2da5
 }
10c0e990
 
faae7220
 func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
b56b2da5
 	out := srv.DockerInfo()
 	b, err := json.Marshal(out)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
79e91058
 
faae7220
 func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	outs, err := srv.ImageHistory(name)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	b, err := json.Marshal(outs)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
b295239d
 
faae7220
 func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	changesStr, err := srv.ContainerChanges(name)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	b, err := json.Marshal(changesStr)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
b295239d
 
fd224ee5
 func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0c544357
 	all, err := getBoolParam(r.Form.Get("all"))
 	if err != nil {
 		return err
 	}
bc3fa506
 	since := r.Form.Get("since")
 	before := r.Form.Get("before")
60ddcaa1
 	n, err := strconv.Atoi(r.Form.Get("limit"))
b56b2da5
 	if err != nil {
 		n = -1
 	}
b295239d
 
1990c49a
 	outs := srv.Containers(all, n, since, before)
b56b2da5
 	b, err := json.Marshal(outs)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
04cd20fa
 
faae7220
 func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	repo := r.Form.Get("repo")
 	tag := r.Form.Get("tag")
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
0c544357
 	force, err := getBoolParam(r.Form.Get("force"))
 	if err != nil {
 		return err
 	}
b295239d
 
b56b2da5
 	if err := srv.ContainerTag(name, repo, tag, force); err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	w.WriteHeader(http.StatusCreated)
7cc08234
 	return nil
b56b2da5
 }
79512b2a
 
faae7220
 func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
5bec9275
 	config := &Config{}
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
2e69e172
 		utils.Debugf("%s", err.Error())
b56b2da5
 	}
 	repo := r.Form.Get("repo")
 	tag := r.Form.Get("tag")
 	container := r.Form.Get("container")
 	author := r.Form.Get("author")
 	comment := r.Form.Get("comment")
5bec9275
 	id, err := srv.ContainerCommit(container, repo, tag, author, comment, config)
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	b, err := json.Marshal(&APIID{id})
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusCreated)
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
79512b2a
 
152ebeea
 // Creates an image from Pull or from Import
faae7220
 func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
6ce475db
 
b56b2da5
 	src := r.Form.Get("fromSrc")
 	image := r.Form.Get("fromImage")
 	tag := r.Form.Get("tag")
f29e5dc8
 	repo := r.Form.Get("repo")
cf19be44
 
c8c7094b
 	if version > 1.0 {
 		w.Header().Set("Content-Type", "application/json")
 	}
 	sf := utils.NewStreamFormatter(version > 1.0)
b56b2da5
 	if image != "" { //pull
 		registry := r.Form.Get("registry")
7e59b830
 		if err := srv.ImagePull(image, tag, registry, w, sf, &auth.AuthConfig{}); err != nil {
c8c7094b
 			if sf.Used() {
5a36efb6
 				w.Write(sf.FormatError(err))
c8c7094b
 				return nil
 			}
f29e5dc8
 			return err
0b6c79b3
 		}
b56b2da5
 	} else { //import
c8c7094b
 		if err := srv.ImageImport(src, repo, tag, r.Body, w, sf); err != nil {
 			if sf.Used() {
5a36efb6
 				w.Write(sf.FormatError(err))
c8c7094b
 				return nil
 			}
f29e5dc8
 			return err
0b6c79b3
 		}
b56b2da5
 	}
7cc08234
 	return nil
b56b2da5
 }
0b6c79b3
 
faae7220
 func getImagesSearch(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
04cd20fa
 
b56b2da5
 	term := r.Form.Get("term")
 	outs, err := srv.ImagesSearch(term)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	b, err := json.Marshal(outs)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
36b968bb
 
faae7220
 func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
36b968bb
 
b56b2da5
 	url := r.Form.Get("url")
 	path := r.Form.Get("path")
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
c8c7094b
 	if version > 1.0 {
 		w.Header().Set("Content-Type", "application/json")
 	}
 	sf := utils.NewStreamFormatter(version > 1.0)
fd224ee5
 	imgID, err := srv.ImageInsert(name, url, path, w, sf)
0f135ad7
 	if err != nil {
c8c7094b
 		if sf.Used() {
5a36efb6
 			w.Write(sf.FormatError(err))
c8c7094b
 			return nil
 		}
b56b2da5
 	}
fd224ee5
 	b, err := json.Marshal(&APIID{ID: imgID})
0f135ad7
 	if err != nil {
 		return err
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
59a6316f
 
faae7220
 func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
49e65683
 	authConfig := &auth.AuthConfig{}
3dd1e4d5
 	if version > 1.1 {
 		if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
 			return err
 		}
 	} else {
 		localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
 		if err != nil && err != auth.ErrConfigFileMissing {
 			return err
 		}
 		authConfig = localAuthConfig
49e65683
 	}
2f4de386
 	if err := parseForm(r); err != nil {
 		return err
 	}
 	registry := r.Form.Get("registry")
 
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
 	name := vars["name"]
c8c7094b
 	if version > 1.0 {
 		w.Header().Set("Content-Type", "application/json")
 	}
 	sf := utils.NewStreamFormatter(version > 1.0)
62c78696
 	if err := srv.ImagePush(name, registry, w, sf, authConfig); err != nil {
c8c7094b
 		if sf.Used() {
5a36efb6
 			w.Write(sf.FormatError(err))
c8c7094b
 			return nil
 		}
2f4de386
 		return err
 	}
7cc08234
 	return nil
b56b2da5
 }
10c0e990
 
faae7220
 func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
152ebeea
 	config := &Config{}
a3f6054f
 	out := &APIRun{}
 
152ebeea
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
7cc08234
 		return err
b56b2da5
 	}
a3f6054f
 
 	if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns() {
7f118519
 		out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns))
a3f6054f
 		config.Dns = defaultDns
 	}
 
152ebeea
 	id, err := srv.ContainerCreate(config)
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
a3f6054f
 	out.ID = id
152ebeea
 
 	if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
 		log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
b56b2da5
 		out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
 	}
152ebeea
 	if config.Memory > 0 && !srv.runtime.capabilities.SwapLimit {
 		log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
b56b2da5
 		out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
 	}
a3f6054f
 
b56b2da5
 	b, err := json.Marshal(out)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusCreated)
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
10c0e990
 
faae7220
 func postContainersRestart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	t, err := strconv.Atoi(r.Form.Get("t"))
 	if err != nil || t < 0 {
 		t = 10
 	}
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	if err := srv.ContainerRestart(name, t); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
f37399d2
 
faae7220
 func deleteContainers(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
0c544357
 	removeVolume, err := getBoolParam(r.Form.Get("v"))
 	if err != nil {
 		return err
 	}
ab96da8e
 
0c6380cc
 	if err := srv.ContainerDestroy(name, removeVolume); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
6ce475db
 
faae7220
 func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
67b20f2c
 	if err := parseForm(r); err != nil {
 		return err
 	}
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
c46382ba
 	imgs, err := srv.ImageDelete(name, version > 1.1)
9060b5c2
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
9060b5c2
 	if imgs != nil {
 		if len(*imgs) != 0 {
 			b, err := json.Marshal(imgs)
 			if err != nil {
 				return err
 			}
66d9a733
 			writeJSON(w, b)
9060b5c2
 		} else {
 			return fmt.Errorf("Conflict, %s wasn't deleted", name)
 		}
 	} else {
 		w.WriteHeader(http.StatusNoContent)
 	}
7cc08234
 	return nil
b56b2da5
 }
b295239d
 
faae7220
 func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	if err := srv.ContainerStart(name); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
b295239d
 
faae7220
 func postContainersStop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	t, err := strconv.Atoi(r.Form.Get("t"))
 	if err != nil || t < 0 {
 		t = 10
 	}
2a303dab
 
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
b295239d
 
b56b2da5
 	if err := srv.ContainerStop(name, t); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0862183c
 	w.WriteHeader(http.StatusNoContent)
7cc08234
 	return nil
b56b2da5
 }
b295239d
 
faae7220
 func postContainersWait(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 	status, err := srv.ContainerWait(name)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	b, err := json.Marshal(&APIWait{StatusCode: status})
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
04cd20fa
 
70d2123e
 func postContainersResize(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	if err := parseForm(r); err != nil {
 		return err
 	}
 	height, err := strconv.Atoi(r.Form.Get("h"))
 	if err != nil {
 		return err
 	}
 	width, err := strconv.Atoi(r.Form.Get("w"))
 	if err != nil {
 		return err
 	}
 	if vars == nil {
 		return fmt.Errorf("Missing parameter")
 	}
 	name := vars["name"]
 	if err := srv.ContainerResize(name, height, width); err != nil {
 		return err
 	}
 	return nil
 }
 
faae7220
 func postContainersAttach(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
954ecac3
 	if err := parseForm(r); err != nil {
7cc08234
 		return err
b56b2da5
 	}
0c544357
 	logs, err := getBoolParam(r.Form.Get("logs"))
 	if err != nil {
 		return err
 	}
 	stream, err := getBoolParam(r.Form.Get("stream"))
 	if err != nil {
 		return err
 	}
 	stdin, err := getBoolParam(r.Form.Get("stdin"))
 	if err != nil {
 		return err
 	}
 	stdout, err := getBoolParam(r.Form.Get("stdout"))
 	if err != nil {
 		return err
 	}
 	stderr, err := getBoolParam(r.Form.Get("stderr"))
 	if err != nil {
 		return err
 	}
 
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
 
e5fa4a49
 	if _, err := srv.ContainerInspect(name); err != nil {
 		return err
 	}
 
57cfe72e
 	in, out, err := hijackServer(w)
b56b2da5
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
cacc7e56
 	defer in.Close()
a11b3139
 
4a1e0d32
 	fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
57cfe72e
 	if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, in, out); err != nil {
 		fmt.Fprintf(out, "Error: %s\n", err)
b56b2da5
 	}
7cc08234
 	return nil
b56b2da5
 }
a4bcf7e1
 
faae7220
 func getContainersByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
a4bcf7e1
 
b56b2da5
 	container, err := srv.ContainerInspect(name)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	b, err := json.Marshal(container)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
a4bcf7e1
 
faae7220
 func getImagesByName(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
ff67da9c
 	if vars == nil {
7cc08234
 		return fmt.Errorf("Missing parameter")
ff67da9c
 	}
b56b2da5
 	name := vars["name"]
1e357c69
 
b56b2da5
 	image, err := srv.ImageInspect(name)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
 	b, err := json.Marshal(image)
 	if err != nil {
7cc08234
 		return err
b56b2da5
 	}
fd224ee5
 	writeJSON(w, b)
7cc08234
 	return nil
b56b2da5
 }
131c6ab3
 
faae7220
 func postImagesGetCache(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
fd224ee5
 	apiConfig := &APIImageConfig{}
0f312113
 	if err := json.NewDecoder(r.Body).Decode(apiConfig); err != nil {
 		return err
 	}
 
fd224ee5
 	image, err := srv.ImageGetCached(apiConfig.ID, apiConfig.Config)
0f312113
 	if err != nil {
 		return err
 	}
c2a14bb1
 	if image == nil {
 		w.WriteHeader(http.StatusNotFound)
 		return nil
 	}
fd224ee5
 	apiID := &APIID{ID: image.ID}
 	b, err := json.Marshal(apiID)
0f312113
 	if err != nil {
 		return err
 	}
fd224ee5
 	writeJSON(w, b)
0f312113
 	return nil
 }
 
a4879901
 func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
d42c10aa
 	if err := r.ParseMultipartForm(4096); err != nil {
0f135ad7
 		return err
 	}
56431d31
 	remote := r.FormValue("t")
 	tag := ""
 	if strings.Contains(remote, ":") {
 		remoteParts := strings.Split(remote, ":")
 		tag = remoteParts[1]
 		remote = remoteParts[0]
 	}
0f135ad7
 
fe0c0c20
 	dockerfile, _, err := r.FormFile("Dockerfile")
0f135ad7
 	if err != nil {
 		return err
 	}
 
d42c10aa
 	context, _, err := r.FormFile("Context")
0f135ad7
 	if err != nil {
d42c10aa
 		if err != http.ErrMissingFile {
 			return err
 		}
0f135ad7
 	}
 
582a9e0a
 	b := NewBuildFile(srv, utils.NewWriteFlusher(w))
56431d31
 	if id, err := b.Build(dockerfile, context); err != nil {
fe0c0c20
 		fmt.Fprintf(w, "Error build: %s\n", err)
56431d31
 	} else if remote != "" {
 		srv.runtime.repositories.Set(remote, tag, id, false)
0f135ad7
 	}
 	return nil
 }
 
dd53c457
 func optionsHandler(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	w.WriteHeader(http.StatusOK)
 	return nil
 }
6d5bdff3
 func writeCorsHeaders(w http.ResponseWriter, r *http.Request) {
 	w.Header().Add("Access-Control-Allow-Origin", "*")
 	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
393e873d
 	w.Header().Add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS")
6d5bdff3
 }
 
0a28628c
 func createRouter(srv *Server, logging bool) (*mux.Router, error) {
b56b2da5
 	r := mux.NewRouter()
131c6ab3
 
faae7220
 	m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
b56b2da5
 		"GET": {
3dd1e4d5
 			"/auth":                         getAuth,
b56b2da5
 			"/version":                      getVersion,
152ebeea
 			"/info":                         getInfo,
fd224ee5
 			"/images/json":                  getImagesJSON,
c423a790
 			"/images/viz":                   getImagesViz,
60ddcaa1
 			"/images/search":                getImagesSearch,
b56b2da5
 			"/images/{name:.*}/history":     getImagesHistory,
60ddcaa1
 			"/images/{name:.*}/json":        getImagesByName,
fd224ee5
 			"/containers/ps":                getContainersJSON,
 			"/containers/json":              getContainersJSON,
152ebeea
 			"/containers/{name:.*}/export":  getContainersExport,
 			"/containers/{name:.*}/changes": getContainersChanges,
60ddcaa1
 			"/containers/{name:.*}/json":    getContainersByName,
b56b2da5
 		},
 		"POST": {
152ebeea
 			"/auth":                         postAuth,
b56b2da5
 			"/commit":                       postCommit,
0f135ad7
 			"/build":                        postBuild,
152ebeea
 			"/images/create":                postImagesCreate,
1941c791
 			"/images/{name:.*}/insert":      postImagesInsert,
 			"/images/{name:.*}/push":        postImagesPush,
152ebeea
 			"/images/{name:.*}/tag":         postImagesTag,
0f312113
 			"/images/getCache":              postImagesGetCache,
152ebeea
 			"/containers/create":            postContainersCreate,
 			"/containers/{name:.*}/kill":    postContainersKill,
b56b2da5
 			"/containers/{name:.*}/restart": postContainersRestart,
 			"/containers/{name:.*}/start":   postContainersStart,
 			"/containers/{name:.*}/stop":    postContainersStop,
 			"/containers/{name:.*}/wait":    postContainersWait,
70d2123e
 			"/containers/{name:.*}/resize":  postContainersResize,
b56b2da5
 			"/containers/{name:.*}/attach":  postContainersAttach,
 		},
 		"DELETE": {
 			"/containers/{name:.*}": deleteContainers,
 			"/images/{name:.*}":     deleteImages,
 		},
dd53c457
 		"OPTIONS": {
 			"": optionsHandler,
 		},
b56b2da5
 	}
 
 	for method, routes := range m {
 		for route, fct := range routes {
2e69e172
 			utils.Debugf("Registering %s, %s", method, route)
b56b2da5
 			// NOTE: scope issue, make sure the variables are local and won't be changed
 			localRoute := route
 			localMethod := method
 			localFct := fct
faae7220
 			f := func(w http.ResponseWriter, r *http.Request) {
2e69e172
 				utils.Debugf("Calling %s %s", localMethod, localRoute)
c423a790
 				if logging {
 					log.Println(r.Method, r.RequestURI)
 				}
7c7619ec
 				if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
 					userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
 					if len(userAgent) == 2 && userAgent[1] != VERSION {
2e69e172
 						utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION)
7c7619ec
 					}
 				}
faae7220
 				version, err := strconv.ParseFloat(mux.Vars(r)["version"], 64)
 				if err != nil {
fd224ee5
 					version = APIVERSION
faae7220
 				}
393e873d
 				if srv.enableCors {
 					writeCorsHeaders(w, r)
 				}
fd224ee5
 				if version == 0 || version > APIVERSION {
faae7220
 					w.WriteHeader(http.StatusNotFound)
 					return
 				}
 				if err := localFct(srv, version, w, r, mux.Vars(r)); err != nil {
891c5202
 					httpError(w, err)
 				}
faae7220
 			}
dd53c457
 
 			if localRoute == "" {
 				r.Methods(localMethod).HandlerFunc(f)
 			} else {
 				r.Path("/v{version:[0-9.]+}" + localRoute).Methods(localMethod).HandlerFunc(f)
 				r.Path(localRoute).Methods(localMethod).HandlerFunc(f)
 			}
131c6ab3
 		}
b56b2da5
 	}
0a28628c
 	return r, nil
 }
 
3adf9ce0
 func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
 	log.Printf("Listening for HTTP on %s (%s)\n", addr, proto)
0a28628c
 
 	r, err := createRouter(srv, logging)
 	if err != nil {
 		return err
 	}
3adf9ce0
 	l, e := net.Listen(proto, addr)
 	if e != nil {
 		return e
 	}
 	//as the daemon is launched as root, change to permission of the socket to allow non-root to connect
 	if proto == "unix" {
 		os.Chmod(addr, 0777)
 	}
 	httpSrv := http.Server{Addr: addr, Handler: r}
 	return httpSrv.Serve(l)
a11b3139
 }