func (c *client) hijack(method, path string, in io.ReadCloser, stdout, stderr io.Writer) error { path = fmt.Sprintf("/%s%s", c.version, path) dial, err := c.transport.Dial("ignored", "ignored") if err != nil { return err } req, err := http.NewRequest(method, path, nil) if err != nil { return err } clientconn := httputil.NewClientConn(dial, nil) defer clientconn.Close() clientconn.Do(req) rwc, br := clientconn.Hijack() defer rwc.Close() receiveStdout := dockerutils.Go(func() (err error) { defer func() { if in != nil { in.Close() } }() _, err = dockerutils.StdCopy(stdout, stderr, br) dockerutils.Debugf("[hijack] End of stdout") return err }) sendStdin := dockerutils.Go(func() error { if in != nil { io.Copy(rwc, in) dockerutils.Debugf("[hijack] End of stdin") } if tcpc, ok := rwc.(*net.TCPConn); ok { if err := tcpc.CloseWrite(); err != nil { dockerutils.Debugf("Couldn't send EOF: %s", err) } } else if unixc, ok := rwc.(*net.UnixConn); ok { if err := unixc.CloseWrite(); err != nil { dockerutils.Debugf("Couldn't send EOF: %s", err) } } // Discard errors due to pipe interruption return nil }) if err := <-receiveStdout; err != nil { dockerutils.Debugf("Error receiveStdout: %s", err) return err } if err := <-sendStdin; err != nil { dockerutils.Debugf("Error sendStdin: %s", err) return err } return nil }
func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in io.Reader, stdout, stderr io.Writer, headers map[string][]string) error { if (method == "POST" || method == "PUT") && in == nil { in = bytes.NewReader([]byte{}) } req, err := http.NewRequest(method, fmt.Sprintf("http://v%s%s", api.APIVERSION, path), in) if err != nil { return err } req.Header.Set("User-Agent", "Docker-Client/"+dockerversion.VERSION) req.URL.Host = cli.addr req.URL.Scheme = cli.scheme if method == "POST" { req.Header.Set("Content-Type", "plain/text") } if headers != nil { for k, v := range headers { req.Header[k] = v } } resp, err := cli.HTTPClient().Do(req) 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 } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 400 { body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } if len(body) == 0 { return fmt.Errorf("Error :%s", http.StatusText(resp.StatusCode)) } return fmt.Errorf("Error: %s", bytes.TrimSpace(body)) } if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") { return utils.DisplayJSONMessagesStream(resp.Body, stdout, cli.terminalFd, cli.isTerminal) } if stdout != nil || stderr != nil { // When TTY is ON, use regular copy if setRawTerminal { _, err = io.Copy(stdout, resp.Body) } else { _, err = utils.StdCopy(stdout, stderr, resp.Body) } utils.Debugf("[stream] End of stdout") return err } return nil }
func (c *DockerClient) hijack(method, path string, setRawTerminal bool, in io.Reader, errStream io.Writer, out io.Writer) error { req, err := http.NewRequest(method, c.getURL(path), nil) if err != nil { return err } req.Header.Set("Content-Type", "plain/text") protocol := c.endpointURL.Scheme address := c.endpointURL.Path if protocol != "unix" { protocol = "tcp" address = c.endpointURL.Host } dial, err := net.Dial(protocol, address) if err != nil { return err } clientconn := httputil.NewClientConn(dial, nil) clientconn.Do(req) defer clientconn.Close() rwc, br := clientconn.Hijack() defer rwc.Close() errStdout := make(chan error, 1) go func() { var err error if setRawTerminal { _, err = io.Copy(out, br) } else { _, err = utils.StdCopy(out, errStream, br) } errStdout <- err }() if inFile, ok := in.(*os.File); ok && setRawTerminal && term.IsTerminal(inFile.Fd()) && os.Getenv("NORAW") == "" { oldState, err := term.SetRawTerminal(inFile.Fd()) if err != nil { return err } defer term.RestoreTerminal(inFile.Fd(), oldState) } go func() { if in != nil { io.Copy(rwc, in) } if err := rwc.(interface { CloseWrite() error }).CloseWrite(); err != nil && errStream != nil { fmt.Fprintf(errStream, "Couldn't send EOF: %s\n", err) } }() if err := <-errStdout; err != nil { return err } return nil }
func (c *Client) hijack(method, path string, setRawTerminal bool, out io.Writer) error { req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil) if err != nil { return err } req.Header.Set("User-Agent", "Docker-Client/"+VERSION) req.Header.Set("Content-Type", "plain/text") req.Host = c.addr dial, err := net.Dial(c.proto, c.addr) if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Can't connect to 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) // Hijack the connection to read / write rwc, br := clientconn.Hijack() defer rwc.Close() // launch a goroutine to copy the stream // of build output to the writer. errStdout := make(chan error, 1) go func() { var err error if setRawTerminal { _, err = io.Copy(out, br) } else { _, err = utils.StdCopy(out, out, br) } errStdout <- err }() // wait for a response if err := <-errStdout; err != nil { return err } 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) } }() 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 && stdout != nil { _, 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) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer) error { req, err := http.NewRequest(method, fmt.Sprintf("/v%g%s", APIVERSION, path), nil) if err != nil { return err } req.Header.Set("User-Agent", "Docker-Client/"+VERSION) req.Header.Set("Content-Type", "plain/text") req.Host = cli.addr dial, err := net.Dial(cli.proto, cli.addr) if err != nil { if strings.Contains(err.Error(), "connection refused") { return fmt.Errorf("Can't connect to 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() var receiveStdout chan error if stdout != nil { receiveStdout = utils.Go(func() (err error) { // 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 }) } 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) } 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 { 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 }