// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } version := httputils.VersionFromContext(ctx) if versions.GreaterThan(version, "1.21") { if err := httputils.CheckForJSON(r); err != nil { return err } } var ( execName = vars["name"] stdin, inStream io.ReadCloser stdout, stderr, outStream io.Writer ) execStartCheck := &types.ExecStartCheck{} if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { return err } if exists, err := s.backend.ExecExists(execName); !exists { return err } if !execStartCheck.Detach { var err error // Setting up the streaming http interface. inStream, outStream, err = httputils.HijackConnection(w) if err != nil { return err } defer httputils.CloseStreams(inStream, outStream) if _, ok := r.Header["Upgrade"]; ok { fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") } else { fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } stdin = inStream stdout = outStream if !execStartCheck.Tty { stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } } // Now run the user process in container. if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { if execStartCheck.Detach { return err } stdout.Write([]byte(err.Error() + "\r\n")) logrus.Errorf("Error running exec in container: %v", err) } return nil }
func (s *containerRouter) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { err := httputils.ParseForm(r) if err != nil { return err } containerName := vars["name"] _, upgrade := r.Header["Upgrade"] keys := []byte{} detachKeys := r.FormValue("detachKeys") if detachKeys != "" { keys, err = term.ToBytes(detachKeys) if err != nil { logrus.Warnf("Invalid escape keys provided (%s) using default : ctrl-p ctrl-q", detachKeys) } } hijacker, ok := w.(http.Hijacker) if !ok { return derr.ErrorCodeNoHijackConnection.WithArgs(containerName) } setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) { conn, _, err := hijacker.Hijack() if err != nil { return nil, nil, nil, err } // set raw mode conn.Write([]byte{}) if upgrade { fmt.Fprintf(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") } else { fmt.Fprintf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } closer := func() error { httputils.CloseStreams(conn) return nil } return ioutils.NewReadCloserWrapper(conn, closer), conn, conn, nil } attachConfig := &backend.ContainerAttachConfig{ GetStreams: setupStreams, UseStdin: httputils.BoolValue(r, "stdin"), UseStdout: httputils.BoolValue(r, "stdout"), UseStderr: httputils.BoolValue(r, "stderr"), Logs: httputils.BoolValue(r, "logs"), Stream: httputils.BoolValue(r, "stream"), DetachKeys: keys, MuxStreams: true, } return s.backend.ContainerAttach(containerName, attachConfig) }
func (s *containerRouter) postContainerAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } container := r.Form.Get("container") // Setting up the streaming http interface. inStream, outStream, err := httputils.HijackConnection(w) if err != nil { return err } defer httputils.CloseStreams(inStream, outStream) fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") return s.backend.CmdAttach(inStream, outStream.(io.WriteCloser), container) }
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start. func (s *router) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } var ( execName = vars["name"] stdin, inStream io.ReadCloser stdout, stderr, outStream io.Writer ) execStartCheck := &types.ExecStartCheck{} if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil { return err } if !execStartCheck.Detach { var err error // Setting up the streaming http interface. inStream, outStream, err = httputils.HijackConnection(w) if err != nil { return err } defer httputils.CloseStreams(inStream, outStream) if _, ok := r.Header["Upgrade"]; ok { fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") } else { fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } stdin = inStream stdout = outStream if !execStartCheck.Tty { stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) } } else { outStream = w } // Now run the user process in container. if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil { fmt.Fprintf(outStream, "Error running exec in container: %v\n", err) } return nil }
func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } containerName := vars["name"] if !s.daemon.Exists(containerName) { return derr.ErrorCodeNoSuchContainer.WithArgs(containerName) } if s.daemon.IsPaused(containerName) { return derr.ErrorCodePausedContainer.WithArgs(containerName) } inStream, outStream, err := httputils.HijackConnection(w) if err != nil { return err } defer httputils.CloseStreams(inStream, outStream) if _, ok := r.Header["Upgrade"]; ok { fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") } else { fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{ InStream: inStream, OutStream: outStream, UseStdin: httputils.BoolValue(r, "stdin"), UseStdout: httputils.BoolValue(r, "stdout"), UseStderr: httputils.BoolValue(r, "stderr"), Logs: httputils.BoolValue(r, "logs"), Stream: httputils.BoolValue(r, "stream"), } if err := s.daemon.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil { fmt.Fprintf(outStream, "Error attaching: %s\n", err) } return nil }
func (s *containerRouter) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { err := httputils.ParseForm(r) if err != nil { return err } containerName := vars["name"] _, upgrade := r.Header["Upgrade"] detachKeys := r.FormValue("detachKeys") hijacker, ok := w.(http.Hijacker) if !ok { return fmt.Errorf("error attaching to container %s, hijack connection missing", containerName) } setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) { conn, _, err := hijacker.Hijack() if err != nil { return nil, nil, nil, err } // set raw mode conn.Write([]byte{}) if upgrade { fmt.Fprintf(conn, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n") } else { fmt.Fprintf(conn, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n") } closer := func() error { httputils.CloseStreams(conn) return nil } return ioutils.NewReadCloserWrapper(conn, closer), conn, conn, nil } attachConfig := &backend.ContainerAttachConfig{ GetStreams: setupStreams, UseStdin: httputils.BoolValue(r, "stdin"), UseStdout: httputils.BoolValue(r, "stdout"), UseStderr: httputils.BoolValue(r, "stderr"), Logs: httputils.BoolValue(r, "logs"), Stream: httputils.BoolValue(r, "stream"), DetachKeys: detachKeys, MuxStreams: true, } if err = s.backend.ContainerAttach(containerName, attachConfig); err != nil { logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err) // Remember to close stream if error happens conn, _, errHijack := hijacker.Hijack() if errHijack == nil { statusCode := httputils.GetHTTPErrorStatusCode(err) statusText := http.StatusText(statusCode) fmt.Fprintf(conn, "HTTP/1.1 %d %s\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n%s\r\n", statusCode, statusText, err.Error()) httputils.CloseStreams(conn) } else { logrus.Errorf("Error Hijacking: %v", err) } } return nil }