func (c *Client) hijack(method, path string, setRawTerminal bool, in io.Reader, stderr, stdout io.Writer) error { if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil { err := c.checkApiVersion() if err != nil { return err } } 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 } defer dial.Close() clientconn := httputil.NewClientConn(dial, nil) clientconn.Do(req) rwc, br := clientconn.Hijack() var wg sync.WaitGroup wg.Add(2) errs := make(chan error, 2) go func() { var err error if setRawTerminal { _, err = io.Copy(stdout, br) } else { _, err = utils.StdCopy(stdout, stderr, br) } errs <- err wg.Done() }() go func() { var err error if in != nil { _, err = io.Copy(rwc, in) } rwc.(interface { CloseWrite() error }).CloseWrite() errs <- err wg.Done() }() wg.Wait() close(errs) if err := <-errs; err != nil { return err } return nil }
func (c *Client) hijack(method, path string, success chan struct{}, 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 } defer dial.Close() clientconn := httputil.NewClientConn(dial, nil) clientconn.Do(req) if success != nil { success <- struct{}{} <-success } rwc, br := clientconn.Hijack() var wg sync.WaitGroup wg.Add(2) errs := make(chan error, 2) go func() { var err error if in != nil { _, err = io.Copy(out, br) } else { _, err = utils.StdCopy(out, errStream, br) } errs <- err wg.Done() }() go func() { var err error if in != nil { _, err = io.Copy(rwc, in) } rwc.(interface { CloseWrite() error }).CloseWrite() errs <- err wg.Done() }() wg.Wait() close(errs) if err := <-errs; err != nil { return err } return nil }
func (c *Client) hijack(method, path string, success chan struct{}, 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 } defer dial.Close() clientconn := httputil.NewClientConn(dial, nil) clientconn.Do(req) if success != nil { success <- struct{}{} <-success } rwc, br := clientconn.Hijack() errStdout := make(chan error, 1) go func() { var err error if in != nil { _, err = io.Copy(out, br) } else { _, err = utils.StdCopy(out, errStream, br) } errStdout <- err }() 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) stream(method, path string, setRawTerminal bool, headers map[string]string, in io.Reader, stdout, stderr io.Writer) error { if (method == "POST" || method == "PUT") && in == nil { in = bytes.NewReader(nil) } if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil { err := c.checkApiVersion() if err != nil { return err } } req, err := http.NewRequest(method, c.getURL(path), in) if err != nil { return err } req.Header.Set("User-Agent", userAgent) if method == "POST" { req.Header.Set("Content-Type", "plain/text") } for key, val := range headers { req.Header.Set(key, val) } var resp *http.Response protocol := c.endpointURL.Scheme address := c.endpointURL.Path if stdout == nil { stdout = ioutil.Discard } if stderr == nil { stderr = ioutil.Discard } if protocol == "unix" { dial, err := net.Dial(protocol, address) if err != nil { return err } clientconn := httputil.NewClientConn(dial, nil) resp, err = clientconn.Do(req) defer clientconn.Close() } else { resp, err = c.client.Do(req) } if err != nil { if strings.Contains(err.Error(), "connection refused") { return ErrConnectionRefused } return err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 400 { body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } return newError(resp.StatusCode, body) } if resp.Header.Get("Content-Type") == "application/json" { dec := json.NewDecoder(resp.Body) for { var m jsonMessage if err := dec.Decode(&m); err == io.EOF { break } else if err != nil { return err } if m.Stream != "" { fmt.Fprint(stdout, m.Stream) } else if m.Progress != "" { fmt.Fprintf(stdout, "%s %s\r", m.Status, m.Progress) } else if m.Error != "" { return errors.New(m.Error) } if m.Status != "" { fmt.Fprintln(stdout, m.Status) } } } else { if setRawTerminal { _, err = io.Copy(stdout, resp.Body) } else { _, err = utils.StdCopy(stdout, stderr, resp.Body) } return err } return nil }
func (c *Client) hijack(method, path string, success chan struct{}, setRawTerminal bool, in io.Reader, stderr, stdout io.Writer) error { if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil { err := c.checkApiVersion() if err != nil { return err } } if stdout == nil { stdout = ioutil.Discard } if stderr == nil { stderr = ioutil.Discard } 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 } defer dial.Close() clientconn := httputil.NewClientConn(dial, nil) clientconn.Do(req) if success != nil { success <- struct{}{} <-success } rwc, br := clientconn.Hijack() errs := make(chan error, 2) exit := make(chan bool) go func() { defer close(exit) var err error if setRawTerminal { _, err = io.Copy(stdout, br) } else { _, err = utils.StdCopy(stdout, stderr, br) } errs <- err }() go func() { var err error if in != nil { _, err = io.Copy(rwc, in) } rwc.(interface { CloseWrite() error }).CloseWrite() errs <- err }() <-exit return <-errs }