mirror of https://github.com/docker/docs.git
				
				
				
			
		
			
				
	
	
		
			134 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| 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
 | |
| }
 |