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 <krisztian.litkey@intel.com>
This commit is contained in:
Krisztian Litkey 2024-08-22 13:22:06 +03:00
parent d8c00dfec3
commit b5cd6e4b32
No known key found for this signature in database
GPG Key ID: 637F2939D50AF85D
2 changed files with 48 additions and 2 deletions

View File

@ -144,7 +144,7 @@ func (ch *channel) recv() (messageHeader, []byte, error) {
func (ch *channel) send(streamID uint32, t messageType, flags uint8, p []byte) error { func (ch *channel) send(streamID uint32, t messageType, flags uint8, p []byte) error {
if len(p) > messageLengthMax { 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 { if err := writeMessageHeader(ch.bw, ch.hwbuf[:], messageHeader{Length: uint32(len(p)), StreamID: streamID, Type: t, Flags: flags}); err != nil {

View File

@ -16,7 +16,12 @@
package ttrpc package ttrpc
import "errors" import (
"errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var ( var (
// ErrProtocol is a general error in the handling the protocol. // ErrProtocol is a general error in the handling the protocol.
@ -32,3 +37,44 @@ var (
// ErrStreamClosed is when the streaming connection is closed. // ErrStreamClosed is when the streaming connection is closed.
ErrStreamClosed = errors.New("ttrpc: stream 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 an OversizedMessageErr error for the given message
// length if it exceeds the allowed maximum. Otherwise a nil error is returned.
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()
}
// Unwrap returns the corresponding error with our grpc status code.
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
}