From 8309e9cd64d01920a3201bf356f627e1275292ae Mon Sep 17 00:00:00 2001 From: Krisztian Litkey Date: Thu, 22 Aug 2024 13:22:06 +0300 Subject: [PATCH] channel: allow discovery of overflown message size. Use a dedicated, grpc Status-compatible error to wrap the unique grpc status code, the size of the rejected message and the maximum allowed size when a message is rejected due to size limitations by the sending side. Signed-off-by: Krisztian Litkey --- channel.go | 2 +- errors.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/channel.go b/channel.go index 1af2a8408..872261e6d 100644 --- a/channel.go +++ b/channel.go @@ -144,7 +144,7 @@ func (ch *channel) recv() (messageHeader, []byte, error) { func (ch *channel) send(streamID uint32, t messageType, flags uint8, p []byte) error { if len(p) > messageLengthMax { - return status.Errorf(codes.ResourceExhausted, "refusing to send, message length %v exceed maximum message size of %v", len(p), messageLengthMax) + return OversizedMessageError(len(p)) } if err := writeMessageHeader(ch.bw, ch.hwbuf[:], messageHeader{Length: uint32(len(p)), StreamID: streamID, Type: t, Flags: flags}); err != nil { diff --git a/errors.go b/errors.go index ec14b7952..b9d8eee73 100644 --- a/errors.go +++ b/errors.go @@ -16,7 +16,12 @@ package ttrpc -import "errors" +import ( + "errors" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) var ( // ErrProtocol is a general error in the handling the protocol. @@ -32,3 +37,44 @@ var ( // ErrStreamClosed is when the streaming connection is closed. ErrStreamClosed = errors.New("ttrpc: stream closed") ) + +// OversizedMessageErr is used to indicate refusal to send an oversized message. +// It wraps a ResourceExhausted grpc Status together with the offending message +// length. +type OversizedMessageErr struct { + messageLength int + err error +} + +// OversizedMessageError returns a wrapped ResourceExhausted grpc status code +// together with the offending message length. +func OversizedMessageError(messageLength int) error { + if messageLength <= messageLengthMax { + return nil + } + + return &OversizedMessageErr{ + messageLength: messageLength, + err: status.Errorf(codes.ResourceExhausted, "message length %v exceed maximum message size of %v", messageLength, messageLengthMax), + } +} + +// Error returns the error message for the corresponding grpc Status for the error. +func (e *OversizedMessageErr) Error() string { + return e.err.Error() +} + +// GRPCStatus returns the corresponding grpc Status for the error. +func (e *OversizedMessageErr) Unwrap() error { + return e.err +} + +// RejectedLength retrieves the rejected message length which triggered the error. +func (e *OversizedMessageErr) RejectedLength() int { + return e.messageLength +} + +// MaximumLength retrieves the maximum allowed message length that triggered the error. +func (*OversizedMessageErr) MaximumLength() int { + return messageLengthMax +}