THRIFT-5007 Implement MAX_MESSAGE_SIZE and remaining read bytes control
Client: Delphi
Patch: Jens Geyer
This closes #1932
diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas
index 7c80221..94e6e18 100644
--- a/lib/delphi/src/Thrift.Protocol.pas
+++ b/lib/delphi/src/Thrift.Protocol.pas
@@ -196,7 +196,7 @@
end;
IProtocol = interface
- ['{602A7FFB-0D9E-4CD8-8D7F-E5076660588A}']
+ ['{7F3640D7-5082-49E7-B562-84202F323C3A}']
function GetTransport: ITransport;
procedure WriteMessageBegin( const msg: TThriftMessage);
procedure WriteMessageEnd;
@@ -248,6 +248,7 @@
function NextRecursionLevel : IProtocolRecursionTracker;
procedure IncrementRecursionDepth;
procedure DecrementRecursionDepth;
+ function GetMinSerializedSize( const aType : TType) : Integer;
property Transport: ITransport read GetTransport;
property RecursionLimit : Integer read GetRecursionLimit write SetRecursionLimit;
@@ -265,6 +266,12 @@
procedure IncrementRecursionDepth;
procedure DecrementRecursionDepth;
+ function GetMinSerializedSize( const aType : TType) : Integer; virtual; abstract;
+ procedure CheckReadBytesAvailable( const value : TThriftList); overload; inline;
+ procedure CheckReadBytesAvailable( const value : TThriftSet); overload; inline;
+ procedure CheckReadBytesAvailable( const value : TThriftMap); overload; inline;
+
+ procedure Reset; virtual;
function GetTransport: ITransport;
public
procedure WriteMessageBegin( const msg: TThriftMessage); virtual; abstract;
@@ -332,6 +339,7 @@
strict protected
FStrictRead : Boolean;
FStrictWrite : Boolean;
+ function GetMinSerializedSize( const aType : TType) : Integer; override;
strict private
function ReadAll( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer ): Integer; inline;
@@ -404,6 +412,9 @@
strict private
FWrappedProtocol : IProtocol;
+ strict protected
+ function GetMinSerializedSize( const aType : TType) : Integer; override;
+
public
// Encloses the specified protocol.
// All operations will be forward to the given protocol. Must be non-null.
@@ -583,6 +594,12 @@
Result := FTrans;
end;
+procedure TProtocolImpl.Reset;
+begin
+ if FTrans.TransportControl <> nil
+ then FTrans.TransportControl.ResetConsumedMessageSize;
+end;
+
function TProtocolImpl.ReadAnsiString: AnsiString;
var
b : TBytes;
@@ -623,6 +640,29 @@
WriteBinary( b );
end;
+
+procedure TProtocolImpl.CheckReadBytesAvailable( const value : TThriftList);
+begin
+ FTrans.CheckReadBytesAvailable( value.Count * GetMinSerializedSize(value.ElementType));
+end;
+
+
+procedure TProtocolImpl.CheckReadBytesAvailable( const value : TThriftSet);
+begin
+ FTrans.CheckReadBytesAvailable( value.Count * GetMinSerializedSize(value.ElementType));
+end;
+
+
+procedure TProtocolImpl.CheckReadBytesAvailable( const value : TThriftMap);
+var nPairSize : Integer
+;
+begin
+ nPairSize := GetMinSerializedSize(value.KeyType) + GetMinSerializedSize(value.ValueType);
+ FTrans.CheckReadBytesAvailable( value.Count * nPairSize);
+end;
+
+
+
{ TProtocolUtil }
class procedure TProtocolUtil.Skip( prot: IProtocol; type_: TType);
@@ -705,6 +745,7 @@
buf : TBytes;
begin
size := ReadI32;
+ FTrans.CheckReadBytesAvailable( size);
SetLength( buf, size);
FTrans.ReadAll( buf, 0, size);
Result := buf;
@@ -777,6 +818,7 @@
begin
result.ElementType := TType(ReadByte);
result.Count := ReadI32;
+ CheckReadBytesAvailable(result);
end;
procedure TBinaryProtocolImpl.ReadListEnd;
@@ -789,6 +831,7 @@
result.KeyType := TType(ReadByte);
result.ValueType := TType(ReadByte);
result.Count := ReadI32;
+ CheckReadBytesAvailable(result);
end;
procedure TBinaryProtocolImpl.ReadMapEnd;
@@ -801,6 +844,7 @@
size : Integer;
version : Integer;
begin
+ Reset;
Init( result);
size := ReadI32;
if (size < 0) then begin
@@ -832,6 +876,7 @@
begin
result.ElementType := TType(ReadByte);
result.Count := ReadI32;
+ CheckReadBytesAvailable(result);
end;
procedure TBinaryProtocolImpl.ReadSetEnd;
@@ -842,6 +887,7 @@
function TBinaryProtocolImpl.ReadStringBody( size: Integer): string;
var buf : TBytes;
begin
+ FTrans.CheckReadBytesAvailable( size);
SetLength( buf, size);
FTrans.ReadAll( buf, 0, size );
Result := TEncoding.UTF8.GetString( buf);
@@ -959,6 +1005,7 @@
procedure TBinaryProtocolImpl.WriteMessageBegin( const msg: TThriftMessage);
var version : Cardinal;
begin
+ Reset;
if FStrictWrite then begin
version := VERSION_1 or Cardinal( msg.Type_);
WriteI32( Integer( version) );
@@ -997,6 +1044,29 @@
end;
+function TBinaryProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer;
+// Return the minimum number of bytes a type will consume on the wire
+begin
+ case aType of
+ TType.Stop: result := 0;
+ TType.Void: result := 0;
+ TType.Bool_: result := SizeOf(Byte);
+ TType.Byte_: result := SizeOf(Byte);
+ TType.Double_: result := SizeOf(Double);
+ TType.I16: result := SizeOf(Int16);
+ TType.I32: result := SizeOf(Int32);
+ TType.I64: result := SizeOf(Int64);
+ TType.String_: result := SizeOf(Int32); // string length
+ TType.Struct: result := 0; // empty struct
+ TType.Map: result := SizeOf(Int32); // element count
+ TType.Set_: result := SizeOf(Int32); // element count
+ TType.List: result := SizeOf(Int32); // element count
+ else
+ raise TTransportExceptionBadArgs.Create('Unhandled type code');
+ end;
+end;
+
+
{ TProtocolException }
constructor TProtocolException.HiddenCreate(const Msg: string);
@@ -1363,6 +1433,12 @@
end;
+function TProtocolDecorator.GetMinSerializedSize( const aType : TType) : Integer;
+begin
+ result := FWrappedProtocol.GetMinSerializedSize(aType);
+end;
+
+
{ Init helper functions }
procedure Init( var rec : TThriftMessage; const AName: string; const AMessageType: TMessageType; const ASeqID: Integer);