mirror of
https://github.com/dalbodeule/hop-gate.git
synced 2025-12-12 06:40:11 +09:00
[fix](protocol): improve Protobuf decoding with precise payload reading and clarification
- Refactored `Decode` to use `io.ReadFull` for accurate length-prefix and payload reading. - Simplified logic to avoid mismatched length issues and clarified comments for maintainability.
This commit is contained in:
@@ -108,33 +108,28 @@ func (protobufCodec) Encode(w io.Writer, env *Envelope) error {
|
|||||||
// Decode reads a length-prefixed protobuf Envelope and converts it into the internal Envelope.
|
// Decode reads a length-prefixed protobuf Envelope and converts it into the internal Envelope.
|
||||||
// For DTLS (UDP-based), we read the entire datagram in a single Read call.
|
// For DTLS (UDP-based), we read the entire datagram in a single Read call.
|
||||||
func (protobufCodec) Decode(r io.Reader, env *Envelope) error {
|
func (protobufCodec) Decode(r io.Reader, env *Envelope) error {
|
||||||
// DTLS는 메시지 경계가 보존되는 UDP 기반 프로토콜입니다.
|
// 1) 길이 prefix 4바이트를 정확히 읽는다.
|
||||||
// 한 번의 Read로 전체 데이터그램(length prefix + protobuf data)을 읽어야 합니다.
|
header := make([]byte, 4)
|
||||||
// DTLS is a UDP-based protocol that preserves message boundaries.
|
if _, err := io.ReadFull(r, header); err != nil {
|
||||||
// We must read the entire datagram (length prefix + protobuf data) in a single Read call.
|
return fmt.Errorf("protobuf codec: read length prefix: %w", err)
|
||||||
buf := make([]byte, maxProtoEnvelopeBytes+4)
|
|
||||||
n, err := r.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("protobuf codec: read frame: %w", err)
|
|
||||||
}
|
|
||||||
if n < 4 {
|
|
||||||
return fmt.Errorf("protobuf codec: frame too short: %d bytes", n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract and validate the length prefix
|
length := binary.BigEndian.Uint32(header)
|
||||||
length := binary.BigEndian.Uint32(buf[:4])
|
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
return fmt.Errorf("protobuf codec: zero-length envelope")
|
return fmt.Errorf("protobuf codec: zero-length envelope")
|
||||||
}
|
}
|
||||||
if length > maxProtoEnvelopeBytes {
|
if length > maxProtoEnvelopeBytes {
|
||||||
return fmt.Errorf("protobuf codec: envelope too large: %d bytes (max %d)", length, maxProtoEnvelopeBytes)
|
return fmt.Errorf("protobuf codec: envelope too large: %d bytes (max %d)", length, maxProtoEnvelopeBytes)
|
||||||
}
|
}
|
||||||
if int(length) != n-4 {
|
|
||||||
return fmt.Errorf("protobuf codec: length mismatch: expected %d, got %d", length, n-4)
|
// 2) payload 를 length 바이트만큼 정확히 읽는다.
|
||||||
|
payload := make([]byte, int(length))
|
||||||
|
if _, err := io.ReadFull(r, payload); err != nil {
|
||||||
|
return fmt.Errorf("protobuf codec: read payload: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pbEnv protocolpb.Envelope
|
var pbEnv protocolpb.Envelope
|
||||||
if err := proto.Unmarshal(buf[4:n], &pbEnv); err != nil {
|
if err := proto.Unmarshal(payload, &pbEnv); err != nil {
|
||||||
return fmt.Errorf("protobuf codec: unmarshal envelope: %w", err)
|
return fmt.Errorf("protobuf codec: unmarshal envelope: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user