github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/pkg/term/proxy.go (about) 1 package term // import "github.com/docker/docker/pkg/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 } 23 24 // NewEscapeProxy returns a new TTY proxy reader which wraps the given reader 25 // and detects when the specified escape keys are read, in which case the Read 26 // method will return an error of type EscapeError. 27 func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader { 28 return &escapeProxy{ 29 escapeKeys: escapeKeys, 30 r: r, 31 } 32 } 33 34 func (r *escapeProxy) Read(buf []byte) (int, error) { 35 nr, err := r.r.Read(buf) 36 37 if len(r.escapeKeys) == 0 { 38 return nr, err 39 } 40 41 preserve := func() { 42 // this preserves the original key presses in the passed in buffer 43 nr += r.escapeKeyPos 44 preserve := make([]byte, 0, r.escapeKeyPos+len(buf)) 45 preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...) 46 preserve = append(preserve, buf...) 47 r.escapeKeyPos = 0 48 copy(buf[0:nr], preserve) 49 } 50 51 if nr != 1 || err != nil { 52 if r.escapeKeyPos > 0 { 53 preserve() 54 } 55 return nr, err 56 } 57 58 if buf[0] != r.escapeKeys[r.escapeKeyPos] { 59 if r.escapeKeyPos > 0 { 60 preserve() 61 } 62 return nr, nil 63 } 64 65 if r.escapeKeyPos == len(r.escapeKeys)-1 { 66 return 0, EscapeError{} 67 } 68 69 // Looks like we've got an escape key, but we need to match again on the next 70 // read. 71 // Store the current escape key we found so we can look for the next one on 72 // the next read. 73 // Since this is an escape key, make sure we don't let the caller read it 74 // If later on we find that this is not the escape sequence, we'll add the 75 // keys back 76 r.escapeKeyPos++ 77 return nr - r.escapeKeyPos, nil 78 }