// holdHijackedConnection hold the HijackedResponse, redirect the inputStream to the connection, and redirect the response // stream to stdout and stderr. NOTE: If needed, we could also add context in this function. func (d *kubeDockerClient) holdHijackedConnection(tty bool, inputStream io.Reader, outputStream, errorStream io.Writer, resp dockertypes.HijackedResponse) error { receiveStdout := make(chan error) if outputStream != nil || errorStream != nil { go func() { receiveStdout <- d.redirectResponseToOutputStream(tty, outputStream, errorStream, resp.Reader) }() } stdinDone := make(chan struct{}) go func() { if inputStream != nil { io.Copy(resp.Conn, inputStream) } resp.CloseWrite() close(stdinDone) }() select { case err := <-receiveStdout: return err case <-stdinDone: if outputStream != nil || errorStream != nil { return <-receiveStdout } } return nil }
// holdHijackedConnection pumps data up to the container's stdin, and runs a // goroutine to pump data down from the container's stdout and stderr. it holds // open the HijackedResponse until all of this is done. Caller's responsibility // to close resp, as well as outputStream and errorStream if appropriate. func (d *stiDocker) holdHijackedConnection(tty bool, inputStream io.Reader, outputStream, errorStream io.WriteCloser, resp dockertypes.HijackedResponse) error { receiveStdout := make(chan error, 1) if outputStream != nil || errorStream != nil { go func() { receiveErr := d.redirectResponseToOutputStream(tty, outputStream, errorStream, resp.Reader) if outputStream != nil { outputStream.Close() } if errorStream != nil { errorStream.Close() } receiveStdout <- receiveErr }() } var err error if inputStream != nil { _, err = io.Copy(resp.Conn, inputStream) if err != nil { return err } } err = resp.CloseWrite() if err != nil { return err } // Hang around until the streaming is over - either when the server closes // the connection, or someone locally closes resp. return <-receiveStdout }
func holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error { var err error receiveStdout := make(chan error, 1) if outputStream != nil || errorStream != nil { go func() { // When TTY is ON, use regular copy if tty && outputStream != nil { _, err = io.Copy(outputStream, resp.Reader) } else { _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader) } logrus.Debugf("[hijack] End of stdout") receiveStdout <- err }() } stdinDone := make(chan struct{}) go func() { if inputStream != nil { io.Copy(resp.Conn, inputStream) logrus.Debugf("[hijack] End of stdin") } if err := resp.CloseWrite(); err != nil { logrus.Debugf("Couldn't send EOF: %s", err) } close(stdinDone) }() select { case err := <-receiveStdout: if err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } case <-stdinDone: if outputStream != nil || errorStream != nil { if err := <-receiveStdout; err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } } } return nil }
func (cli *DockerCli) holdHijackedConnection(setRawTerminal bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error { var ( err error oldState *term.State ) if inputStream != nil && setRawTerminal && cli.isTerminalIn && os.Getenv("NORAW") == "" { oldState, err = term.SetRawTerminal(cli.inFd) if err != nil { return err } defer term.RestoreTerminal(cli.inFd, oldState) } receiveStdout := make(chan error, 1) if outputStream != nil || errorStream != nil { go func() { defer func() { if inputStream != nil { if setRawTerminal && cli.isTerminalIn { term.RestoreTerminal(cli.inFd, oldState) } inputStream.Close() } }() // When TTY is ON, use regular copy if setRawTerminal && outputStream != nil { _, err = io.Copy(outputStream, resp.Reader) } else { _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader) } logrus.Debugf("[hijack] End of stdout") receiveStdout <- err }() } stdinDone := make(chan struct{}) go func() { if inputStream != nil { io.Copy(resp.Conn, inputStream) logrus.Debugf("[hijack] End of stdin") } if err := resp.CloseWrite(); err != nil { logrus.Debugf("Couldn't send EOF: %s", err) } close(stdinDone) }() select { case err := <-receiveStdout: if err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } case <-stdinDone: if outputStream != nil || errorStream != nil { if err := <-receiveStdout; err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } } } return nil }
func (cli *DockerCli) holdHijackedConnection(ctx context.Context, tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error { var ( err error restoreOnce sync.Once ) if inputStream != nil && tty { if err := cli.setRawTerminal(); err != nil { return err } defer func() { restoreOnce.Do(func() { cli.restoreTerminal(inputStream) }) }() } receiveStdout := make(chan error, 1) if outputStream != nil || errorStream != nil { go func() { // When TTY is ON, use regular copy if tty && outputStream != nil { _, err = io.Copy(outputStream, resp.Reader) // we should restore the terminal as soon as possible once connection end // so any following print messages will be in normal type. if inputStream != nil { restoreOnce.Do(func() { cli.restoreTerminal(inputStream) }) } } else { _, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader) } logrus.Debugf("[hijack] End of stdout") receiveStdout <- err }() } stdinDone := make(chan struct{}) go func() { if inputStream != nil { io.Copy(resp.Conn, inputStream) // we should restore the terminal as soon as possible once connection end // so any following print messages will be in normal type. if tty { restoreOnce.Do(func() { cli.restoreTerminal(inputStream) }) } logrus.Debugf("[hijack] End of stdin") } if err := resp.CloseWrite(); err != nil { logrus.Debugf("Couldn't send EOF: %s", err) } close(stdinDone) }() select { case err := <-receiveStdout: if err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } case <-stdinDone: if outputStream != nil || errorStream != nil { select { case err := <-receiveStdout: if err != nil { logrus.Debugf("Error receiveStdout: %s", err) return err } case <-ctx.Done(): } } case <-ctx.Done(): } return nil }