From 8c9192cd76ad46bda3d0ec5ba7eb4a30669afb40 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 2 May 2014 00:40:13 +0000 Subject: [PATCH] move hijack to it's own file Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api/client/hijack.go | 133 ++++++++++++++++++++++++++++++++++++++++++ api/client/utils.go | 134 +------------------------------------------ 2 files changed, 134 insertions(+), 133 deletions(-) create mode 100644 api/client/hijack.go diff --git a/api/client/hijack.go b/api/client/hijack.go new file mode 100644 index 0000000000..0a9d5d8ef2 --- /dev/null +++ b/api/client/hijack.go @@ -0,0 +1,133 @@ +package client + +import ( + "crypto/tls" + "fmt" + "io" + "net" + "net/http" + "net/http/httputil" + "os" + "runtime" + "strings" + + "github.com/dotcloud/docker/api" + "github.com/dotcloud/docker/dockerversion" + "github.com/dotcloud/docker/pkg/term" + "github.com/dotcloud/docker/utils" +) + +func (cli *DockerCli) dial() (net.Conn, error) { + if cli.tlsConfig != nil && cli.proto != "unix" { + return tls.Dial(cli.proto, cli.addr, cli.tlsConfig) + } + return net.Dial(cli.proto, cli.addr) +} + +func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error { + defer func() { + if started != nil { + close(started) + } + }() + + req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil) + if err != nil { + return err + } + req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION) + req.Header.Set("Content-Type", "plain/text") + req.Host = cli.addr + + dial, err := cli.dial() + if err != nil { + if strings.Contains(err.Error(), "connection refused") { + return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?") + } + return err + } + clientconn := httputil.NewClientConn(dial, nil) + defer clientconn.Close() + + // Server hijacks the connection, error 'connection closed' expected + clientconn.Do(req) + + rwc, br := clientconn.Hijack() + defer rwc.Close() + + if started != nil { + started <- rwc + } + + var receiveStdout chan error + + var oldState *term.State + + if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" { + oldState, err = term.SetRawTerminal(cli.terminalFd) + if err != nil { + return err + } + defer term.RestoreTerminal(cli.terminalFd, oldState) + } + + if stdout != nil || stderr != nil { + receiveStdout = utils.Go(func() (err error) { + defer func() { + if in != nil { + if setRawTerminal && cli.isTerminal { + term.RestoreTerminal(cli.terminalFd, oldState) + } + // For some reason this Close call blocks on darwin.. + // As the client exists right after, simply discard the close + // until we find a better solution. + if runtime.GOOS != "darwin" { + in.Close() + } + } + }() + + // When TTY is ON, use regular copy + if setRawTerminal { + _, err = io.Copy(stdout, br) + } else { + _, err = utils.StdCopy(stdout, stderr, br) + } + utils.Debugf("[hijack] End of stdout") + return err + }) + } + + sendStdin := utils.Go(func() error { + if in != nil { + io.Copy(rwc, in) + utils.Debugf("[hijack] End of stdin") + } + if tcpc, ok := rwc.(*net.TCPConn); ok { + if err := tcpc.CloseWrite(); err != nil { + utils.Debugf("Couldn't send EOF: %s\n", err) + } + } else if unixc, ok := rwc.(*net.UnixConn); ok { + if err := unixc.CloseWrite(); err != nil { + utils.Debugf("Couldn't send EOF: %s\n", err) + } + } + // Discard errors due to pipe interruption + return nil + }) + + if stdout != nil || stderr != nil { + if err := <-receiveStdout; err != nil { + utils.Debugf("Error receiveStdout: %s", err) + return err + } + } + + if !cli.isTerminal { + if err := <-sendStdin; err != nil { + utils.Debugf("Error sendStdin: %s", err) + return err + } + } + return nil +} diff --git a/api/client/utils.go b/api/client/utils.go index 152e3540ff..6f574b48db 100644 --- a/api/client/utils.go +++ b/api/client/utils.go @@ -2,7 +2,6 @@ package client import ( "bytes" - "crypto/tls" "encoding/base64" "encoding/json" "errors" @@ -11,12 +10,9 @@ import ( "io/ioutil" "net" "net/http" - "net/http/httputil" "net/url" "os" gosignal "os/signal" - "regexp" - goruntime "runtime" "strconv" "strings" "syscall" @@ -35,23 +31,14 @@ var ( func (cli *DockerCli) HTTPClient() *http.Client { tr := &http.Transport{ + TLSClientConfig: cli.tlsConfig, Dial: func(network, addr string) (net.Conn, error) { return net.Dial(cli.proto, cli.addr) }, } - if cli.proto != "unix" { - tr.TLSClientConfig = cli.tlsConfig - } return &http.Client{Transport: tr} } -func (cli *DockerCli) dial() (net.Conn, error) { - if cli.tlsConfig != nil && cli.proto != "unix" { - return tls.Dial(cli.proto, cli.addr, cli.tlsConfig) - } - return net.Dial(cli.proto, cli.addr) -} - func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo bool) (io.ReadCloser, int, error) { params := bytes.NewBuffer(nil) if data != nil { @@ -69,9 +56,6 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b } } } - // fixme: refactor client to support redirect - re := regexp.MustCompile("/+") - path = re.ReplaceAllString(path, "/") req, err := http.NewRequest(method, fmt.Sprintf("http://v%s%s", api.APIVERSION, path), params) if err != nil { @@ -134,10 +118,6 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in in = bytes.NewReader([]byte{}) } - // fixme: refactor client to support redirect - re := regexp.MustCompile("/+") - path = re.ReplaceAllString(path, "/") - req, err := http.NewRequest(method, fmt.Sprintf("http://v%s%s", api.APIVERSION, path), in) if err != nil { return err @@ -189,118 +169,6 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in return nil } -func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error { - defer func() { - if started != nil { - close(started) - } - }() - // fixme: refactor client to support redirect - re := regexp.MustCompile("/+") - path = re.ReplaceAllString(path, "/") - - req, err := http.NewRequest(method, fmt.Sprintf("/v%s%s", api.APIVERSION, path), nil) - if err != nil { - return err - } - req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION) - req.Header.Set("Content-Type", "plain/text") - req.Host = cli.addr - - dial, err := cli.dial() - if err != nil { - if strings.Contains(err.Error(), "connection refused") { - return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?") - } - return err - } - clientconn := httputil.NewClientConn(dial, nil) - defer clientconn.Close() - - // Server hijacks the connection, error 'connection closed' expected - clientconn.Do(req) - - rwc, br := clientconn.Hijack() - defer rwc.Close() - - if started != nil { - started <- rwc - } - - var receiveStdout chan error - - var oldState *term.State - - if in != nil && setRawTerminal && cli.isTerminal && os.Getenv("NORAW") == "" { - oldState, err = term.SetRawTerminal(cli.terminalFd) - if err != nil { - return err - } - defer term.RestoreTerminal(cli.terminalFd, oldState) - } - - if stdout != nil || stderr != nil { - receiveStdout = utils.Go(func() (err error) { - defer func() { - if in != nil { - if setRawTerminal && cli.isTerminal { - term.RestoreTerminal(cli.terminalFd, oldState) - } - // For some reason this Close call blocks on darwin.. - // As the client exists right after, simply discard the close - // until we find a better solution. - if goruntime.GOOS != "darwin" { - in.Close() - } - } - }() - - // When TTY is ON, use regular copy - if setRawTerminal { - _, err = io.Copy(stdout, br) - } else { - _, err = utils.StdCopy(stdout, stderr, br) - } - utils.Debugf("[hijack] End of stdout") - return err - }) - } - - sendStdin := utils.Go(func() error { - if in != nil { - io.Copy(rwc, in) - utils.Debugf("[hijack] End of stdin") - } - if tcpc, ok := rwc.(*net.TCPConn); ok { - if err := tcpc.CloseWrite(); err != nil { - utils.Debugf("Couldn't send EOF: %s\n", err) - } - } else if unixc, ok := rwc.(*net.UnixConn); ok { - if err := unixc.CloseWrite(); err != nil { - utils.Debugf("Couldn't send EOF: %s\n", err) - } - } - // Discard errors due to pipe interruption - return nil - }) - - if stdout != nil || stderr != nil { - if err := <-receiveStdout; err != nil { - utils.Debugf("Error receiveStdout: %s", err) - return err - } - } - - if !cli.isTerminal { - if err := <-sendStdin; err != nil { - utils.Debugf("Error sendStdin: %s", err) - return err - } - } - return nil - -} - func (cli *DockerCli) resizeTty(id string) { height, width := cli.getTtySize() if height == 0 && width == 0 {