diff --git a/api.go b/api.go index b77a60af4..b95b1c26d 100644 --- a/api.go +++ b/api.go @@ -1,35 +1,26 @@ package docker import ( - _ "bytes" "encoding/json" "fmt" "github.com/dotcloud/docker/auth" "github.com/gorilla/mux" "github.com/shin-/cookiejar" + "io" "log" - "net" "net/http" - "os" "strconv" "strings" ) -func hijackServer(w http.ResponseWriter) (*os.File, net.Conn, error) { - rwc, _, err := w.(http.Hijacker).Hijack() +func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { + conn, _, err := w.(http.Hijacker).Hijack() if err != nil { return nil, nil, err } - - file, err := rwc.(*net.TCPConn).File() - if err != nil { - return nil, rwc, err - } - // Flush the options to make sure the client sets the raw mode - rwc.Write([]byte{}) - - return file, rwc, nil + conn.Write([]byte{}) + return conn, conn, nil } func httpError(w http.ResponseWriter, err error) { @@ -106,19 +97,14 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request) ([ vars := mux.Vars(r) name := vars["name"] - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ContainerExport(name, file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ContainerExport(name, out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) return nil, err } return nil, nil @@ -131,19 +117,14 @@ func getImages(srv *Server, w http.ResponseWriter, r *http.Request) ([]byte, err viz := r.Form.Get("viz") == "1" if viz { - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ImagesViz(file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ImagesViz(out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) } return nil, nil } @@ -288,26 +269,21 @@ func postImages(srv *Server, w http.ResponseWriter, r *http.Request) ([]byte, er repo := r.Form.Get("repo") tag := r.Form.Get("tag") - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") if image != "" { //pull registry := r.Form.Get("registry") - if err := srv.ImagePull(image, tag, registry, file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + if err := srv.ImagePull(image, tag, registry, out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) return nil, err } } else { //import - if err := srv.ImageImport(src, repo, tag, file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + if err := srv.ImageImport(src, repo, tag, in, out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) return nil, err } } @@ -341,19 +317,14 @@ func postImagesInsert(srv *Server, w http.ResponseWriter, r *http.Request) ([]by vars := mux.Vars(r) name := vars["name"] - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ImageInsert(name, url, path, file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ImageInsert(name, url, path, out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) return nil, err } return nil, nil @@ -369,39 +340,28 @@ func postImagesPush(srv *Server, w http.ResponseWriter, r *http.Request) ([]byte vars := mux.Vars(r) name := vars["name"] - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ImagePush(name, registry, file); err != nil { - fmt.Fprintln(file, "Error: $s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ImagePush(name, registry, out); err != nil { + fmt.Fprintln(out, "Error: %s\n", err) return nil, err } return nil, nil } func postBuild(srv *Server, w http.ResponseWriter, r *http.Request) ([]byte, error) { - - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ImageCreateFormFile(file); err != nil { - fmt.Fprintln(file, "Error: %s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ImageCreateFromFile(in, out); err != nil { + fmt.Fprintln(out, "Error: %s\n", err) return nil, err } return nil, nil @@ -532,20 +492,15 @@ func postContainersAttach(srv *Server, w http.ResponseWriter, r *http.Request) ( vars := mux.Vars(r) name := vars["name"] - file, rwc, err := hijackServer(w) - if file != nil { - defer file.Close() - } - if rwc != nil { - defer rwc.Close() - } + in, out, err := hijackServer(w) if err != nil { + defer in.Close() return nil, err } - fmt.Fprintf(file, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") - if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, file); err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + fmt.Fprintf(out, "HTTP/1.1 200 OK\r\nContent-Type: raw-stream-hijack\r\n\r\n") + if err := srv.ContainerAttach(name, logs, stream, stdin, stdout, stderr, in, out); err != nil { + fmt.Fprintf(out, "Error: %s\n", err) return nil, err } return nil, nil diff --git a/server.go b/server.go index 1d5eaa850..5fb419113 100644 --- a/server.go +++ b/server.go @@ -26,7 +26,7 @@ func (srv *Server) ContainerKill(name string) error { return nil } -func (srv *Server) ContainerExport(name string, file *os.File) error { +func (srv *Server) ContainerExport(name string, out io.Writer) error { if container := srv.runtime.Get(name); container != nil { data, err := container.Export() @@ -35,7 +35,7 @@ func (srv *Server) ContainerExport(name string, file *os.File) error { } // Stream the entire contents of the container (basically a volatile snapshot) - if _, err := io.Copy(file, data); err != nil { + if _, err := io.Copy(out, data); err != nil { return err } return nil @@ -62,13 +62,13 @@ func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) { return outs, nil } -func (srv *Server) ImageInsert(name, url, path string, stdout *os.File) error { +func (srv *Server) ImageInsert(name, url, path string, out io.Writer) error { img, err := srv.runtime.repositories.LookupImage(name) if err != nil { return err } - file, err := Download(url, stdout) + file, err := Download(url, out) if err != nil { return err } @@ -85,7 +85,7 @@ func (srv *Server) ImageInsert(name, url, path string, stdout *os.File) error { return err } - if err := c.Inject(ProgressReader(file.Body, int(file.ContentLength), stdout, "Downloading %v/%v (%v)"), path); err != nil { + if err := c.Inject(ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)"), path); err != nil { return err } // FIXME: Handle custom repo, tag comment, author @@ -93,29 +93,31 @@ func (srv *Server) ImageInsert(name, url, path string, stdout *os.File) error { if err != nil { return err } - fmt.Fprintf(stdout, "%s\n", img.Id) + fmt.Fprintf(out, "%s\n", img.Id) return nil } -func (srv *Server) ImagesViz(file *os.File) error { +func (srv *Server) ImagesViz(out io.Writer) error { images, _ := srv.runtime.graph.All() if images == nil { return nil } - fmt.Fprintf(file, "digraph docker {\n") + fmt.Fprintf(out, "digraph docker {\n") - var parentImage *Image - var err error + var ( + parentImage *Image + err error + ) for _, image := range images { parentImage, err = image.GetParent() if err != nil { return fmt.Errorf("Error while getting parent image: %v", err) } if parentImage != nil { - fmt.Fprintf(file, " \"%s\" -> \"%s\"\n", parentImage.ShortId(), image.ShortId()) + fmt.Fprintf(out, " \"%s\" -> \"%s\"\n", parentImage.ShortId(), image.ShortId()) } else { - fmt.Fprintf(file, " base -> \"%s\" [style=invis]\n", image.ShortId()) + fmt.Fprintf(out, " base -> \"%s\" [style=invis]\n", image.ShortId()) } } @@ -128,11 +130,9 @@ func (srv *Server) ImagesViz(file *os.File) error { } for id, repos := range reporefs { - fmt.Fprintf(file, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", id, id, strings.Join(repos, "\\n")) + fmt.Fprintf(out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", id, id, strings.Join(repos, "\\n")) } - - fmt.Fprintf(file, " base [style=invisible]\n") - fmt.Fprintf(file, "}\n") + fmt.Fprintf(out, " base [style=invisible]\n}\n") return nil } @@ -299,26 +299,26 @@ func (srv *Server) ContainerTag(name, repo, tag string, force bool) error { return nil } -func (srv *Server) ImagePull(name, tag, registry string, file *os.File) error { +func (srv *Server) ImagePull(name, tag, registry string, out io.Writer) error { if registry != "" { - if err := srv.runtime.graph.PullImage(file, name, registry, nil); err != nil { + if err := srv.runtime.graph.PullImage(out, name, registry, nil); err != nil { return err } return nil } - if err := srv.runtime.graph.PullRepository(file, name, tag, srv.runtime.repositories, srv.runtime.authConfig); err != nil { + if err := srv.runtime.graph.PullRepository(out, name, tag, srv.runtime.repositories, srv.runtime.authConfig); err != nil { return err } return nil } -func (srv *Server) ImagePush(name, registry string, file *os.File) error { +func (srv *Server) ImagePush(name, registry string, out io.Writer) error { img, err := srv.runtime.graph.Get(name) if err != nil { Debugf("The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name])) // If it fails, try to get the repository if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists { - if err := srv.runtime.graph.PushRepository(file, name, localRepo, srv.runtime.authConfig); err != nil { + if err := srv.runtime.graph.PushRepository(out, name, localRepo, srv.runtime.authConfig); err != nil { return err } return nil @@ -326,37 +326,37 @@ func (srv *Server) ImagePush(name, registry string, file *os.File) error { return err } - err = srv.runtime.graph.PushImage(file, img, registry, nil) + err = srv.runtime.graph.PushImage(out, img, registry, nil) if err != nil { return err } return nil } -func (srv *Server) ImageImport(src, repo, tag string, file *os.File) error { +func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Writer) error { var archive io.Reader var resp *http.Response if src == "-" { - archive = file + archive = in } else { u, err := url.Parse(src) if err != nil { - fmt.Fprintf(file, "Error: %s\n", err) + fmt.Fprintf(out, "Error: %s\n", err) } if u.Scheme == "" { u.Scheme = "http" u.Host = src u.Path = "" } - fmt.Fprintln(file, "Downloading from", u) + fmt.Fprintln(out, "Downloading from", u) // Download with curl (pretty progress bar) // If curl is not available, fallback to http.Get() - resp, err = Download(u.String(), file) + resp, err = Download(u.String(), out) if err != nil { return err } - archive = ProgressReader(resp.Body, int(resp.ContentLength), file, "Importing %v/%v (%v)") + archive = ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)") } img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil) if err != nil { @@ -368,7 +368,7 @@ func (srv *Server) ImageImport(src, repo, tag string, file *os.File) error { return err } } - fmt.Fprintln(file, img.ShortId()) + fmt.Fprintln(out, img.ShortId()) return nil } @@ -397,12 +397,12 @@ func (srv *Server) ContainerCreate(config Config) (string, bool, bool, error) { return container.ShortId(), memoryW, swapW, nil } -func (srv *Server) ImageCreateFormFile(file *os.File) error { - img, err := NewBuilder(srv.runtime).Build(file, file) +func (srv *Server) ImageCreateFromFile(dockerfile io.Reader, out io.Writer) error { + img, err := NewBuilder(srv.runtime).Build(dockerfile, out) if err != nil { return err } - fmt.Fprintf(file, "%s\n", img.ShortId()) + fmt.Fprintf(out, "%s\n", img.ShortId()) return nil } @@ -496,7 +496,7 @@ func (srv *Server) ContainerWait(name string) (int, error) { return 0, fmt.Errorf("No such container: %s", name) } -func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, file *os.File) error { +func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, stderr bool, in io.ReadCloser, out io.Writer) error { if container := srv.runtime.Get(name); container != nil { //logs if logs { @@ -504,7 +504,7 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std cLog, err := container.ReadLog("stdout") if err != nil { Debugf(err.Error()) - } else if _, err := io.Copy(file, cLog); err != nil { + } else if _, err := io.Copy(out, cLog); err != nil { Debugf(err.Error()) } } @@ -512,7 +512,7 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std cLog, err := container.ReadLog("stderr") if err != nil { Debugf(err.Error()) - } else if _, err := io.Copy(file, cLog); err != nil { + } else if _, err := io.Copy(out, cLog); err != nil { Debugf(err.Error()) } } @@ -535,16 +535,16 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std go func() { defer w.Close() defer Debugf("Closing buffered stdin pipe") - io.Copy(w, file) + io.Copy(w, in) }() cStdin = r - cStdinCloser = file + cStdinCloser = in } if stdout { - cStdout = file + cStdout = out } if stderr { - cStderr = file + cStderr = out } <-container.Attach(cStdin, cStdinCloser, cStdout, cStderr)