...

Source file src/github.com/moby/term/proxy.go

Documentation: github.com/moby/term

     1  package term
     2  
     3  import (
     4  	"io"
     5  )
     6  
     7  // EscapeError is special error which returned by a TTY proxy reader's Read()
     8  // method in case its detach escape sequence is read.
     9  type EscapeError struct{}
    10  
    11  func (EscapeError) Error() string {
    12  	return "read escape sequence"
    13  }
    14  
    15  // escapeProxy is used only for attaches with a TTY. It is used to proxy
    16  // stdin keypresses from the underlying reader and look for the passed in
    17  // escape key sequence to signal a detach.
    18  type escapeProxy struct {
    19  	escapeKeys   []byte
    20  	escapeKeyPos int
    21  	r            io.Reader
    22  	buf          []byte
    23  }
    24  
    25  // NewEscapeProxy returns a new TTY proxy reader which wraps the given reader
    26  // and detects when the specified escape keys are read, in which case the Read
    27  // method will return an error of type EscapeError.
    28  func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader {
    29  	return &escapeProxy{
    30  		escapeKeys: escapeKeys,
    31  		r:          r,
    32  	}
    33  }
    34  
    35  func (r *escapeProxy) Read(buf []byte) (n int, err error) {
    36  	if len(r.escapeKeys) > 0 && r.escapeKeyPos == len(r.escapeKeys) {
    37  		return 0, EscapeError{}
    38  	}
    39  
    40  	if len(r.buf) > 0 {
    41  		n = copy(buf, r.buf)
    42  		r.buf = r.buf[n:]
    43  	}
    44  
    45  	nr, err := r.r.Read(buf[n:])
    46  	n += nr
    47  	if len(r.escapeKeys) == 0 {
    48  		return n, err
    49  	}
    50  
    51  	for i := 0; i < n; i++ {
    52  		if buf[i] == r.escapeKeys[r.escapeKeyPos] {
    53  			r.escapeKeyPos++
    54  
    55  			// Check if the full escape sequence is matched.
    56  			if r.escapeKeyPos == len(r.escapeKeys) {
    57  				n = i + 1 - r.escapeKeyPos
    58  				if n < 0 {
    59  					n = 0
    60  				}
    61  				return n, EscapeError{}
    62  			}
    63  			continue
    64  		}
    65  
    66  		// If we need to prepend a partial escape sequence from the previous
    67  		// read, make sure the new buffer size doesn't exceed len(buf).
    68  		// Otherwise, preserve any extra data in a buffer for the next read.
    69  		if i < r.escapeKeyPos {
    70  			preserve := make([]byte, 0, r.escapeKeyPos+n)
    71  			preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...)
    72  			preserve = append(preserve, buf[:n]...)
    73  			n = copy(buf, preserve)
    74  			i += r.escapeKeyPos
    75  			r.buf = append(r.buf, preserve[n:]...)
    76  		}
    77  		r.escapeKeyPos = 0
    78  	}
    79  
    80  	// If we're in the middle of reading an escape sequence, make sure we don't
    81  	// let the caller read it. If later on we find that this is not the escape
    82  	// sequence, we'll prepend it back to buf.
    83  	n -= r.escapeKeyPos
    84  	if n < 0 {
    85  		n = 0
    86  	}
    87  	return n, err
    88  }
    89  

View as plain text