summaryrefslogtreecommitdiff
path: root/vendor/github.com/moby/term/proxy.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/moby/term/proxy.go')
-rw-r--r--vendor/github.com/moby/term/proxy.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/vendor/github.com/moby/term/proxy.go b/vendor/github.com/moby/term/proxy.go
new file mode 100644
index 000000000..c47756b89
--- /dev/null
+++ b/vendor/github.com/moby/term/proxy.go
@@ -0,0 +1,88 @@
+package term
+
+import (
+ "io"
+)
+
+// EscapeError is special error which returned by a TTY proxy reader's Read()
+// method in case its detach escape sequence is read.
+type EscapeError struct{}
+
+func (EscapeError) Error() string {
+ return "read escape sequence"
+}
+
+// escapeProxy is used only for attaches with a TTY. It is used to proxy
+// stdin keypresses from the underlying reader and look for the passed in
+// escape key sequence to signal a detach.
+type escapeProxy struct {
+ escapeKeys []byte
+ escapeKeyPos int
+ r io.Reader
+ buf []byte
+}
+
+// NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
+// and detects when the specified escape keys are read, in which case the Read
+// method will return an error of type EscapeError.
+func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader {
+ return &escapeProxy{
+ escapeKeys: escapeKeys,
+ r: r,
+ }
+}
+
+func (r *escapeProxy) Read(buf []byte) (n int, err error) {
+ if len(r.escapeKeys) > 0 && r.escapeKeyPos == len(r.escapeKeys) {
+ return 0, EscapeError{}
+ }
+
+ if len(r.buf) > 0 {
+ n = copy(buf, r.buf)
+ r.buf = r.buf[n:]
+ }
+
+ nr, err := r.r.Read(buf[n:])
+ n += nr
+ if len(r.escapeKeys) == 0 {
+ return n, err
+ }
+
+ for i := 0; i < n; i++ {
+ if buf[i] == r.escapeKeys[r.escapeKeyPos] {
+ r.escapeKeyPos++
+
+ // Check if the full escape sequence is matched.
+ if r.escapeKeyPos == len(r.escapeKeys) {
+ n = i + 1 - r.escapeKeyPos
+ if n < 0 {
+ n = 0
+ }
+ return n, EscapeError{}
+ }
+ continue
+ }
+
+ // If we need to prepend a partial escape sequence from the previous
+ // read, make sure the new buffer size doesn't exceed len(buf).
+ // Otherwise, preserve any extra data in a buffer for the next read.
+ if i < r.escapeKeyPos {
+ preserve := make([]byte, 0, r.escapeKeyPos+n)
+ preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
+ preserve = append(preserve, buf[:n]...)
+ n = copy(buf, preserve)
+ i += r.escapeKeyPos
+ r.buf = append(r.buf, preserve[n:]...)
+ }
+ r.escapeKeyPos = 0
+ }
+
+ // If we're in the middle of reading an escape sequence, make sure we don't
+ // let the caller read it. If later on we find that this is not the escape
+ // sequence, we'll prepend it back to buf.
+ n -= r.escapeKeyPos
+ if n < 0 {
+ n = 0
+ }
+ return n, err
+}