diff --git a/go.mod b/go.mod index 31198e03572..b09159a0eea 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.16 require ( bou.ke/monkey v1.0.2 github.com/360EntSecGroup-Skylar/excelize/v2 v2.3.2 - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/GoogleCloudPlatform/spark-on-k8s-operator v0.0.0-20201215015655-2e8b733f5ad0 github.com/Masterminds/semver v1.5.0 @@ -23,6 +22,7 @@ require ( github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/bluele/gcache v0.0.2 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 + github.com/bugaolengdeyuxiaoer/go-ansiterm v0.0.0-20211108054157-9835e04f3693 // indirect github.com/buger/jsonparser v1.1.1 github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee github.com/caarlos0/env v0.0.0-20180521112546-3e0f30cbf50b diff --git a/go.sum b/go.sum index 6e37661d56c..1323e3a2b3a 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,7 @@ github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= @@ -246,6 +247,10 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/brancz/gojsontoyaml v0.0.0-20190425155809-e8bd32d46b3d/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0= github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugaolengdeyuxiaoer/go-ansiterm v0.0.0-20211105082458-a2d01f0f130b h1:9cMzzuEqaP6RhGdV3DvIh6rm/fHUdez8uMIwMZJblyQ= +github.com/bugaolengdeyuxiaoer/go-ansiterm v0.0.0-20211105082458-a2d01f0f130b/go.mod h1:zoCZuwF7bNiQYEVqIzNMPsWunfW6fAYiD606Td3x88Y= +github.com/bugaolengdeyuxiaoer/go-ansiterm v0.0.0-20211108054157-9835e04f3693 h1:bxbrP2gHOdx2T8cNFFcgpfbqcj8BLjs9mGOgsig+SjE= +github.com/bugaolengdeyuxiaoer/go-ansiterm v0.0.0-20211108054157-9835e04f3693/go.mod h1:zoCZuwF7bNiQYEVqIzNMPsWunfW6fAYiD606Td3x88Y= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= @@ -2105,6 +2110,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/modules/cmp/steve/middleware/audit.go b/modules/cmp/steve/middleware/audit.go index b299cf187ae..76c22e6f53d 100644 --- a/modules/cmp/steve/middleware/audit.go +++ b/modules/cmp/steve/middleware/audit.go @@ -29,9 +29,8 @@ import ( "strings" "time" - "github.com/Azure/go-ansiterm" + "github.com/bugaolengdeyuxiaoer/go-ansiterm" "github.com/sirupsen/logrus" - "golang.org/x/time/rate" "github.com/erda-project/erda/apistructs" "github.com/erda-project/erda/bundle" @@ -63,7 +62,7 @@ const ( AuditTargetLabel = "targetLabel" AuditCommands = "commands" - maxAuditLength = 40000 + maxAuditLength = 1 << 16 ) type Auditor struct { @@ -263,48 +262,42 @@ func (w *wrapWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { ctx: w.ctx, } go func(w *wrapWriter) { - limiter := rate.NewLimiter(1, 1) for { - select { - case <-w.ctx.Done(): - return - case <-closeChan: - return - default: - err = limiter.Wait(w.ctx) - if err != nil { - logrus.Errorf("audit with websocket limiter error, %v", err) - return - } - auditStr := "" - ticker := time.NewTicker(1 * time.Second) - LOOP: - for { - select { - case <-ticker.C: + auditStr := "" + LOOP: + for { + select { + case cmd := <-d.auditReqChan: + auditStr += fmt.Sprintf("%s: %s\n", cmd.start.Format(time.RFC3339), cmd.cmd) + if len(auditStr) > maxAuditLength { break LOOP - case cmd := <-d.auditReqChan: - auditStr += fmt.Sprintf("%s: %s\n", cmd.start.Format(time.RFC3339), cmd.cmd) - if len(auditStr) > 1024 { - break LOOP - } - default: - } - } - if len(auditStr) > 0 { - w.auditReq.Context[AuditCommands] = auditStr - if err := w.bdl.CreateAuditEvent(&w.auditReq); err != nil { - logrus.Errorf("faild to audit in steve audit, %v", err) - } else { - logrus.Infof("send audit message with websocket : %s", auditStr) } + case <-w.ctx.Done(): + w.sendWebsocketAudit(auditStr) + return + case <-closeChan: + w.sendWebsocketAudit(auditStr) + return } + w.sendWebsocketAudit(auditStr) } + } }(w) return wc, rw, nil } +func (w *wrapWriter) sendWebsocketAudit(auditStr string) { + if len(auditStr) > 0 { + w.auditReq.Context[AuditCommands] = auditStr + if err := w.bdl.CreateAuditEvent(&w.auditReq); err != nil { + logrus.Errorf("faild to audit in steve audit, %v", err) + } else { + logrus.Infof("send audit message with websocket ,length : %d,", len(auditStr)) + } + } +} + type wrapConn struct { net.Conn parser *ansiterm.AnsiParser @@ -326,18 +319,20 @@ func (w *wrapConn) Read(p []byte) (n int, err error) { logrus.Error(r) } }() - data := websocket.DecodeFrame(p) - if len(data) <= 1 || data[0] != '0' { - return - } - for _, d := range strings.Split(string(data), "\n") { - decoded, _ := base64.StdEncoding.DecodeString(d[1:]) - if err != nil || len(decoded) == 0 { + data := websocket.DecodeFrames(p[:n]) + for _, datum := range data { + if datum[0] != '0' { return } - _, err = w.parser.Parse(decoded) - if err != nil { - return 0, err + for _, d := range strings.Split(string(datum), "\n") { + decoded, _ := base64.StdEncoding.DecodeString(d[1:]) + if len(decoded) == 0 { + continue + } + _, err = w.parser.Parse(decoded) + if err != nil { + logrus.Errorf("audit message parse err :%v", err) + } } } return diff --git a/modules/cmp/steve/middleware/dispatcher.go b/modules/cmp/steve/middleware/dispatcher.go index ba4a11c64f2..4ad0b339484 100644 --- a/modules/cmp/steve/middleware/dispatcher.go +++ b/modules/cmp/steve/middleware/dispatcher.go @@ -42,10 +42,10 @@ const ( maxBufSize = 2048 ) const ( - // state - normal = iota - reverseSearch - reverseSearched +// state +//normal = iota +//reverseSearch +//reverseSearched ) // start with index 1 @@ -98,9 +98,12 @@ type dispatcher struct { queue Queue cursorLine int cursorIdx int + cursorBufIdx int length int buf []byte searchBuf []byte + inputBuf []byte + inputBufLength int searchIdx int BufferMaxSize int executeCommand string @@ -108,74 +111,240 @@ type dispatcher struct { state int } -func (d *dispatcher) Print(b byte) error { - if b == 127 { - d.state = normal +func (d *dispatcher) Close() error { + d.closeChan <- struct{}{} + return nil +} + +func (d *dispatcher) MoveLineHead() error { + return d.CUB(d.length + startIdx) +} + +func (d *dispatcher) MoveLineEnd() error { + return d.CUF(d.length + startIdx) +} + +func (d *dispatcher) QuitSearchMode() error { + d.searchIdx = startIdx + return nil +} + +func (d *dispatcher) Enter() error { + d.sendAuditReq() + d.reset() + return nil +} + +func (d *dispatcher) Reset() error { + d.reset() + return nil +} + +func (d *dispatcher) NextCommand() error { + return d.CUD(1) +} + +func (d *dispatcher) PreviousCommand() error { + return d.CUU(1) +} + +func (d *dispatcher) EnterWithRedisplay() error { + return d.sendAuditReq() +} + +func (d *dispatcher) ReverseSearch(c byte) error { + return d.reverseSearch(c) +} + +func (d *dispatcher) Search(c byte) error { + return d.search(c) +} + +func (d *dispatcher) ShowBuffer() error { + if d.inputBufLength+d.length > maxBufSize { + return nil } - switch d.state { - case reverseSearch: - return d.reverseSearch(b) - case normal: - // DEL - if b == 127 { - d.buf = append(d.buf[:d.cursorIdx-1], d.buf[d.cursorIdx:]...) - d.cursorIdx = mathutil.Max(d.cursorIdx-1, 1) - d.length = mathutil.Max(d.length-1, 0) - return nil + copy(d.buf[d.cursorIdx+d.inputBufLength:], d.buf[d.cursorIdx:]) + copy(d.buf[d.cursorIdx:], d.inputBuf[startIdx:d.inputBufLength+startIdx]) + d.length += d.inputBufLength + d.cursorIdx += d.inputBufLength + return nil +} + +func (d *dispatcher) Clean() error { + d.reset() + return nil +} + +func (d *dispatcher) RemoveForwardWord() error { + start, end := d.findForwardWord() + d.removeAndStore(start, end) + return nil +} + +func (d *dispatcher) RemoveBackwardWord() error { + start, end := d.findBackwardWord() + d.removeAndStore(start, end) + d.cursorIdx = start + return nil +} + +func (d *dispatcher) RemoveForwardAll() error { + d.removeAndStore(d.cursorIdx, d.length) + return nil +} + +func (d *dispatcher) RemoveBackwardAll() error { + d.removeAndStore(startIdx, d.cursorIdx-1) + d.cursorIdx = startIdx + return nil +} + +// removeAndStore remove buf [start,end] and store it +func (d *dispatcher) removeAndStore(start, end int) { + if end < start { + return + } + newLen := end - start + 1 + copy(d.inputBuf[startIdx+newLen:], d.inputBuf[startIdx:]) + copy(d.inputBuf[startIdx:], d.buf[start:end+1]) + copy(d.buf[start:], d.buf[end+1:]) + d.length -= newLen + d.inputBufLength += newLen +} + +func (d *dispatcher) findForwardWord() (int, int) { + start := d.cursorIdx + 1 + // skip any space + for ; start <= d.length && d.buf[start] == ' '; start++ { + } + // find space to the end + for ; start <= d.length; start++ { + if d.buf[start] == ' ' { + break } - if d.length >= d.BufferMaxSize { - d.reset() - return OutOfLengthSize + } + return d.cursorIdx + 1, start - 1 +} + +func (d *dispatcher) findBackwardWord() (int, int) { + start := d.cursorIdx - 1 + // skip any space + for ; start >= startIdx && d.buf[start] == ' '; start-- { + } + // find space to the head + for ; start >= startIdx; start-- { + if d.buf[start] == ' ' { + start++ + break } - for i := d.length; i >= d.cursorIdx; i-- { - d.buf[i+1] = d.buf[i] + } + if start == 0 { + start = startIdx + } + return start, mathutil.Max(d.cursorIdx-1, startIdx) +} + +func (d *dispatcher) RemoveForwardCharacterOrClose() error { + if d.length > 0 { + if d.cursorIdx < d.length+startIdx { + copy(d.buf[d.cursorIdx:], d.buf[d.cursorIdx+1:]) } - d.buf[d.cursorIdx] = b - d.cursorIdx++ - d.length++ + return nil } + return d.Close() +} + +func (d *dispatcher) RemoveBackwardCharacter() error { + d.buf = append(d.buf[:d.cursorIdx-1], d.buf[d.cursorIdx:]...) + d.cursorIdx = mathutil.Max(d.cursorIdx-1, 1) + d.length = mathutil.Max(d.length-1, 0) return nil } -func (d *dispatcher) Execute(b byte) error { - switch b { - // ctrl a - case 1: - return d.CUB(len(d.buf)) - // ctrl c - case 3: - d.state = normal - d.reset() +func (d *dispatcher) MoveForwardCharacter() error { + d.cursorIdx = mathutil.Min(d.cursorIdx+1, startIdx+d.length) + return nil +} + +func (d *dispatcher) MoveBackwardCharacter() error { + d.cursorIdx = mathutil.Max(d.cursorIdx-1, startIdx) + return nil +} + +func (d *dispatcher) MoveForwardWord() error { + _, end := d.findForwardWord() + d.cursorIdx = end + 1 + return nil +} + +func (d *dispatcher) MoveBackwardWord() error { + start, _ := d.findBackwardWord() + d.cursorIdx = start + return nil +} + +func (d *dispatcher) DoubleX() error { + if d.cursorBufIdx >= d.cursorIdx { + d.cursorBufIdx = d.cursorIdx + } + if d.cursorBufIdx == 0 { + d.cursorBufIdx = startIdx + } + d.cursorBufIdx, d.cursorIdx = d.cursorIdx, d.cursorBufIdx + return nil +} + +func (d *dispatcher) SwapLastTwoCharacter() error { + if d.cursorIdx == startIdx { return nil - case 4: - d.closeChan <- struct{}{} - // ctrl e - case 5: - return d.CUF(len(d.buf)) - case 13: - err := d.sendAuditReq() - if err != nil { - return err - } - // ctrl r - case 18: - d.searchIdx = 0 - d.state = reverseSearch } - d.reset() + if d.length > 1 && d.cursorIdx != d.length+1 { + d.buf[d.cursorIdx-1], d.buf[d.cursorIdx] = d.buf[d.cursorIdx], d.buf[d.cursorIdx-1] + } else { + d.buf[d.cursorIdx-2], d.buf[d.cursorIdx-1] = d.buf[d.cursorIdx-1], d.buf[d.cursorIdx-2] + } + d.cursorIdx = mathutil.Max(d.cursorIdx+1, d.length+1) + return nil +} + +// move bufCursor first,then move cursor +//func (d *dispatcher) moveBufCursor(i int) { +// if d.cursorBufIdx >= d.cursorIdx { +// d.cursorBufIdx += i +// } +//} + +func (d *dispatcher) Print(b byte) error { + if d.length >= d.BufferMaxSize { + d.resetWithCmdline() + return OutOfLengthSize + } + copy(d.buf[d.cursorIdx+1:], d.buf[d.cursorIdx:]) + d.buf[d.cursorIdx] = b + d.cursorIdx++ + d.length++ + return nil +} + +func (d *dispatcher) Execute(b byte) error { + err := d.sendAuditReq() + if err != nil { + return err + } + d.resetWithCmdline() recover() return nil } func (d *dispatcher) sendAuditReq() error { - d.state = normal d.executeCommand = string(d.buf[startIdx : startIdx+d.length]) + if d.executeCommand == "" { return nil } err := d.queue.pushFront(d.executeCommand) if err != nil { - d.reset() return err } d.auditReqChan <- &cmdWithTimestamp{ @@ -185,11 +354,18 @@ func (d *dispatcher) sendAuditReq() error { return nil } -func (d *dispatcher) reset() { +func (d *dispatcher) resetWithCmdline() { d.cursorLine = 0 + d.reset() +} + +func (d *dispatcher) reset() { d.cursorIdx = startIdx + d.searchIdx = startIdx d.length = 0 + d.inputBufLength = 0 d.executeCommand = "" + d.cursorBufIdx = 0 } func (d *dispatcher) reverseSearch(b byte) error { @@ -199,25 +375,48 @@ func (d *dispatcher) reverseSearch(b byte) error { d.reset() return OutOfLengthSize } - searchStr := string(d.searchBuf[:d.searchIdx]) - for i := d.queue.Begin(); i <= d.queue.Size(); i++ { - str, _ := d.queue.Get(i) - if strings.Contains(str, searchStr) { - copy(d.buf[startIdx:], str) - d.cursorIdx = len(str) + 1 - d.length = len(str) - d.cursorLine = i - return nil + allStr := string(d.searchBuf[startIdx : d.searchIdx+startIdx]) + for j := len(allStr); j >= 1; j-- { + searchStr := allStr[:j] + for i := d.queue.Begin(); i <= d.queue.Size(); i++ { + str, _ := d.queue.Get(i) + if strings.Contains(str, searchStr) { + copy(d.buf[startIdx:], str) + d.cursorIdx = len(str) + 1 + d.length = len(str) + d.cursorLine = i + return nil + } } } return nil } -func (d *dispatcher) CUU(i int) error { - switch d.state { - case reverseSearch: - d.state = normal +func (d *dispatcher) search(b byte) error { + d.searchBuf[d.searchIdx] = b + d.searchIdx++ + if d.searchIdx >= d.BufferMaxSize { + d.reset() + return OutOfLengthSize + } + allStr := string(d.searchBuf[startIdx : d.searchIdx+startIdx]) + for j := len(allStr); j >= 1; j-- { + searchStr := allStr[:j] + for i := d.queue.Size(); i >= d.queue.Begin(); i-- { + str, _ := d.queue.Get(i) + if strings.Contains(str, searchStr) { + copy(d.buf[startIdx:], str) + d.cursorIdx = len(str) + 1 + d.length = len(str) + d.cursorLine = i + return nil + } + } } + return nil +} + +func (d *dispatcher) CUU(i int) error { d.cursorLine = mathutil.Min(d.queue.Size(), d.cursorLine+i) c, err := d.queue.Get(d.cursorLine) if err != nil { @@ -225,15 +424,11 @@ func (d *dispatcher) CUU(i int) error { } copy(d.buf[startIdx:], c) d.length = len(c) - d.cursorIdx = len(c) + d.cursorIdx = len(c) + startIdx return nil } func (d *dispatcher) CUD(i int) error { - switch d.state { - case reverseSearch: - d.state = normal - } d.cursorLine = mathutil.Max(0, d.cursorLine-i) c, err := d.queue.Get(d.cursorLine) if err != nil { @@ -241,25 +436,17 @@ func (d *dispatcher) CUD(i int) error { } copy(d.buf[startIdx:], c) d.length = len(c) - d.cursorIdx = len(c) + d.cursorIdx = len(c) + startIdx return nil } func (d *dispatcher) CUF(i int) error { - switch d.state { - case reverseSearch: - d.state = normal - } - d.cursorIdx = mathutil.Min(d.cursorIdx+i, d.length) + d.cursorIdx = mathutil.Min(d.cursorIdx+i, d.length+startIdx) return nil } func (d *dispatcher) CUB(i int) error { - switch d.state { - case reverseSearch: - d.state = normal - } - d.cursorIdx = mathutil.Max(d.cursorIdx-i, 1) + d.cursorIdx = mathutil.Max(d.cursorIdx-i, startIdx) return nil } @@ -365,8 +552,9 @@ func NewDispatcher(auditReqChan chan *cmdWithTimestamp, closeChan chan struct{}) }, BufferMaxSize: maxBufSize, cursorIdx: startIdx, - buf: make([]byte, maxBufSize+1), - searchBuf: make([]byte, maxBufSize+1), + buf: make([]byte, maxBufSize+2), + searchBuf: make([]byte, maxBufSize+2), + inputBuf: make([]byte, maxBufSize+2), auditReqChan: auditReqChan, closeChan: closeChan, } diff --git a/modules/cmp/steve/middleware/dispatcher_test.go b/modules/cmp/steve/middleware/dispatcher_test.go index 3323e9110f3..d9025ae0e83 100644 --- a/modules/cmp/steve/middleware/dispatcher_test.go +++ b/modules/cmp/steve/middleware/dispatcher_test.go @@ -18,9 +18,16 @@ import ( "reflect" "testing" - "github.com/Azure/go-ansiterm" + "github.com/bugaolengdeyuxiaoer/go-ansiterm" ) +var testDispatcher *dispatcher + +func init() { + auditReqChan := make(chan *cmdWithTimestamp, 10) + closeChan := make(chan struct{}, 10) + testDispatcher = NewDispatcher(auditReqChan, closeChan) +} func TestNewDispatcher(t *testing.T) { closeChan := make(chan struct{}, 10) auditReqChan := make(chan *cmdWithTimestamp, 10) @@ -365,3 +372,47 @@ func Test_dispatcher_CUF(t *testing.T) { }) } } + +func Test_dispatcher_RemoveBackwardCharacter(t *testing.T) { + + tests := []struct { + name string + wantErr bool + }{ + { + name: "1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := testDispatcher.RemoveBackwardCharacter(); (err != nil) != tt.wantErr { + t.Errorf("RemoveBackwardCharacter() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_dispatcher_ReverseSearch(t *testing.T) { + type args struct { + b byte + } + tests := []struct { + name string + args args + wantErr bool + }{ + // TODO: Add test cases. + { + name: "1", + args: args{'a'}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := testDispatcher + if err := d.ReverseSearch(tt.args.b); (err != nil) != tt.wantErr { + t.Errorf("search() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/modules/cmp/steve/websocket/decode.go b/modules/cmp/steve/websocket/decode.go index f04fec83465..7953cfdf8fd 100644 --- a/modules/cmp/steve/websocket/decode.go +++ b/modules/cmp/steve/websocket/decode.go @@ -25,35 +25,39 @@ const ( maskBit = 1 << 7 ) -func DecodeFrame(data []byte) []byte { +func DecodeFrames(data []byte) [][]byte { buf := bytes.NewBuffer(data) - first2Bytes := make([]byte, 2) - buf.Read(first2Bytes) + frames := make([][]byte, 0) + for buf.Len() > 0 { + first2Bytes := make([]byte, 2) + buf.Read(first2Bytes) - mask := first2Bytes[1]&maskBit != 0 - length := uint64(first2Bytes[1] & 0x7f) - switch length { - case 126: - lenBytes := make([]byte, 2) - buf.Read(lenBytes) - length = binary.BigEndian.Uint64(lenBytes) - case 127: - lenBytes := make([]byte, 8) - buf.Read(lenBytes) - length = binary.BigEndian.Uint64(lenBytes) - } + mask := first2Bytes[1]&maskBit != 0 + length := uint64(first2Bytes[1] & 0x7f) + switch length { + case 126: + lenBytes := make([]byte, 2) + buf.Read(lenBytes) + length = binary.BigEndian.Uint64(lenBytes) + case 127: + lenBytes := make([]byte, 8) + buf.Read(lenBytes) + length = binary.BigEndian.Uint64(lenBytes) + } - maskKeyBytes := make([]byte, 4) - if mask { - buf.Read(maskKeyBytes) - } + maskKeyBytes := make([]byte, 4) + if mask { + buf.Read(maskKeyBytes) + } - payloadBytes := make([]byte, length) - buf.Read(payloadBytes) - if mask { - maskBytes(maskKeyBytes, 0, payloadBytes) + payloadBytes := make([]byte, length) + buf.Read(payloadBytes) + if mask { + maskBytes(maskKeyBytes, 0, payloadBytes) + } + frames = append(frames, payloadBytes) } - return payloadBytes + return frames } const wordSize = int(unsafe.Sizeof(uintptr(0))) diff --git a/modules/cmp/steve/websocket/decode_test.go b/modules/cmp/steve/websocket/decode_test.go index 3c8f33a4fd9..08b048ae9a2 100644 --- a/modules/cmp/steve/websocket/decode_test.go +++ b/modules/cmp/steve/websocket/decode_test.go @@ -23,8 +23,8 @@ func TestDecodeFrame(t *testing.T) { frame := []byte{129, 144, 155, 182, 186, 247, 250, 241, 236, 132, 249, 241, 130, 144, 255, 132, 131, 142, 249, 241, 235, 202, 0, 62, 249, 122, 86, 4, 248, 80, 11, 4, 165, 72, 17, 5, 140, 87, 44, } - data := DecodeFrame(frame) - res, err := base64.StdEncoding.DecodeString(string(data)) + data := DecodeFrames(frame) + res, err := base64.StdEncoding.DecodeString(string(data[0])) if err != nil { t.Error(err) }