1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-20 22:42:59 +03:00

fix(proto): fix notification parser

This commit is contained in:
Nedyalko Dyakov
2025-07-16 12:57:06 +03:00
parent 2681d6d034
commit 32bca83b3d
2 changed files with 56 additions and 13 deletions

View File

@ -3,6 +3,7 @@ package proto
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"math/rand"
"strings" "strings"
"testing" "testing"
) )
@ -215,9 +216,9 @@ func TestPeekPushNotificationName(t *testing.T) {
// This is acceptable behavior for malformed input // This is acceptable behavior for malformed input
name, err := reader.PeekPushNotificationName() name, err := reader.PeekPushNotificationName()
if err != nil { if err != nil {
t.Logf("PeekPushNotificationName errored for corrupted data %s: %v", tc.name, err) t.Logf("PeekPushNotificationName errored for corrupted data %s: %v (DATA: %s)", tc.name, err, tc.data)
} else { } else {
t.Logf("PeekPushNotificationName returned '%s' for corrupted data %s", name, tc.name) t.Logf("PeekPushNotificationName returned '%s' for corrupted data NAME: %s, DATA: %s", name, tc.name, tc.data)
} }
}) })
} }
@ -293,15 +294,27 @@ func TestPeekPushNotificationName(t *testing.T) {
func createValidPushNotification(notificationName, data string) *bytes.Buffer { func createValidPushNotification(notificationName, data string) *bytes.Buffer {
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
simpleOrString := rand.Intn(2) == 0
if data == "" { if data == "" {
// Single element notification // Single element notification
buf.WriteString(">1\r\n") buf.WriteString(">1\r\n")
if simpleOrString {
buf.WriteString(fmt.Sprintf("+%s\r\n", notificationName))
} else {
buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(notificationName), notificationName)) buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(notificationName), notificationName))
}
} else { } else {
// Two element notification // Two element notification
buf.WriteString(">2\r\n") buf.WriteString(">2\r\n")
if simpleOrString {
buf.WriteString(fmt.Sprintf("+%s\r\n", notificationName))
buf.WriteString(fmt.Sprintf("+%s\r\n", data))
} else {
buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(notificationName), notificationName)) buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(notificationName), notificationName))
buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(data), data)) buf.WriteString(fmt.Sprintf("$%d\r\n%s\r\n", len(notificationName), notificationName))
}
} }
return buf return buf

View File

@ -116,26 +116,55 @@ func (r *Reader) PeekPushNotificationName() (string, error) {
if buf[0] != RespPush { if buf[0] != RespPush {
return "", fmt.Errorf("redis: can't parse push notification: %q", buf) return "", fmt.Errorf("redis: can't parse push notification: %q", buf)
} }
// remove push notification type and length
buf = buf[2:] if len(buf) < 3 {
return "", fmt.Errorf("redis: can't parse push notification: %q", buf)
}
// remove push notification type
buf = buf[1:]
// remove first line - e.g. >2\r\n
for i := 0; i < len(buf)-1; i++ { for i := 0; i < len(buf)-1; i++ {
if buf[i] == '\r' && buf[i+1] == '\n' { if buf[i] == '\r' && buf[i+1] == '\n' {
buf = buf[i+2:] buf = buf[i+2:]
break break
} else {
if buf[i] < '0' || buf[i] > '9' {
return "", fmt.Errorf("redis: can't parse push notification: %q", buf)
} }
} }
}
if len(buf) < 2 {
return "", fmt.Errorf("redis: can't parse push notification: %q", buf)
}
// next line should be $<length><string>\r\n or +<length><string>\r\n
// should have the type of the push notification name and it's length // should have the type of the push notification name and it's length
if buf[0] != RespString { if buf[0] != RespString && buf[0] != RespStatus {
return "", fmt.Errorf("redis: can't parse push notification name: %q", buf)
}
typeOfName := buf[0]
// remove the type of the push notification name
buf = buf[1:]
if typeOfName == RespString {
// remove the length of the string
if len(buf) < 2 {
return "", fmt.Errorf("redis: can't parse push notification name: %q", buf) return "", fmt.Errorf("redis: can't parse push notification name: %q", buf)
} }
// skip the length of the string
for i := 0; i < len(buf)-1; i++ { for i := 0; i < len(buf)-1; i++ {
if buf[i] == '\r' && buf[i+1] == '\n' { if buf[i] == '\r' && buf[i+1] == '\n' {
buf = buf[i+2:] buf = buf[i+2:]
break break
} else {
if buf[i] < '0' || buf[i] > '9' {
return "", fmt.Errorf("redis: can't parse push notification name: %q", buf)
}
}
} }
} }
if len(buf) < 2 {
return "", fmt.Errorf("redis: can't parse push notification name: %q", buf)
}
// keep only the notification name // keep only the notification name
for i := 0; i < len(buf)-1; i++ { for i := 0; i < len(buf)-1; i++ {
if buf[i] == '\r' && buf[i+1] == '\n' { if buf[i] == '\r' && buf[i+1] == '\n' {
@ -143,6 +172,7 @@ func (r *Reader) PeekPushNotificationName() (string, error) {
break break
} }
} }
return util.BytesToString(buf), nil return util.BytesToString(buf), nil
} }