mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 10:59:18 +02:00
* Patch from Simon Ameis to actually implement parameter checking
git-svn-id: trunk@44142 -
This commit is contained in:
parent
12d015a935
commit
d295ee3427
@ -54,7 +54,7 @@ Type
|
|||||||
function GetP(AIndex : Integer): TJSONParamDef;
|
function GetP(AIndex : Integer): TJSONParamDef;
|
||||||
procedure SetP(AIndex : Integer; const AValue: TJSONParamDef);
|
procedure SetP(AIndex : Integer; const AValue: TJSONParamDef);
|
||||||
Public
|
Public
|
||||||
Function AddParamDef(Const AName : TJSONStringType; AType : TJSONType = jtString) : TJSONParamDef;
|
Function AddParamDef(Const AName : TJSONStringType; AType : TJSONType = jtString; ARequired: Boolean = False) : TJSONParamDef;
|
||||||
Function IndexOfParamDef(Const AName : TJSONStringType) : Integer;
|
Function IndexOfParamDef(Const AName : TJSONStringType) : Integer;
|
||||||
Function FindParamDef(Const AName : TJSONStringType) : TJSONParamDef;
|
Function FindParamDef(Const AName : TJSONStringType) : TJSONParamDef;
|
||||||
Function ParamDefByName(Const AName : TJSONStringType) : TJSONParamDef;
|
Function ParamDefByName(Const AName : TJSONStringType) : TJSONParamDef;
|
||||||
@ -63,7 +63,7 @@ Type
|
|||||||
|
|
||||||
{ TCustomJSONRPCHandler }
|
{ TCustomJSONRPCHandler }
|
||||||
TJSONParamErrorEvent = Procedure (Sender : TObject; Const E : Exception; Var Fatal : boolean) of Object;
|
TJSONParamErrorEvent = Procedure (Sender : TObject; Const E : Exception; Var Fatal : boolean) of Object;
|
||||||
TJSONRPCOption = (jroCheckParams,jroObjectParams,jroArrayParams);
|
TJSONRPCOption = (jroCheckParams,jroObjectParams,jroArrayParams,jroIgnoreExtraFields);
|
||||||
TJSONRPCOptions = set of TJSONRPCOption;
|
TJSONRPCOptions = set of TJSONRPCOption;
|
||||||
|
|
||||||
{ TJSONRPCCallContext }
|
{ TJSONRPCCallContext }
|
||||||
@ -94,6 +94,8 @@ Type
|
|||||||
Protected
|
Protected
|
||||||
function CreateParamDefs: TJSONParamDefs; virtual;
|
function CreateParamDefs: TJSONParamDefs; virtual;
|
||||||
Procedure DoCheckParams(Const Params : TJSONData); virtual;
|
Procedure DoCheckParams(Const Params : TJSONData); virtual;
|
||||||
|
Procedure DoCheckParamDefsOnObject(Const ParamObject: TJSONObject); virtual;
|
||||||
|
Procedure DoCheckParamArray(const ParamArray: TJSONArray); virtual;
|
||||||
Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; virtual;
|
Function DoExecute(Const Params : TJSONData; AContext : TJSONRPCCallContext): TJSONData; virtual;
|
||||||
Property BeforeExecute : TNotifyEvent Read FBeforeExecute Write FBeforeExecute;
|
Property BeforeExecute : TNotifyEvent Read FBeforeExecute Write FBeforeExecute;
|
||||||
Property AfterExecute : TNotifyEvent Read FAfterExecute Write FAfterExecute;
|
Property AfterExecute : TNotifyEvent Read FAfterExecute Write FAfterExecute;
|
||||||
@ -332,8 +334,10 @@ Type
|
|||||||
TJSONErrorObject = Class(TJSONObject);
|
TJSONErrorObject = Class(TJSONObject);
|
||||||
|
|
||||||
// Raise EJSONRPC exceptions.
|
// Raise EJSONRPC exceptions.
|
||||||
Procedure JSONRPCError(Msg : String);
|
Procedure JSONRPCError(const Msg : String);
|
||||||
Procedure JSONRPCError(Fmt : String; Args : Array of const);
|
Procedure JSONRPCError(const Fmt : String; const Args : Array of const);
|
||||||
|
Procedure JSONRPCParamError(const Msg: String);
|
||||||
|
Procedure JSONRPCParamError(const Fmt: String; const Args: array of const);
|
||||||
|
|
||||||
// Create an 'Error' object for an error response.
|
// Create an 'Error' object for an error response.
|
||||||
function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
|
function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
|
||||||
@ -371,6 +375,10 @@ resourcestring
|
|||||||
SErrParamsMustBeArrayorObject = 'Parameters must be passed in an object or an array.';
|
SErrParamsMustBeArrayorObject = 'Parameters must be passed in an object or an array.';
|
||||||
SErrParamsMustBeObject = 'Parameters must be passed in an object.';
|
SErrParamsMustBeObject = 'Parameters must be passed in an object.';
|
||||||
SErrParamsMustBeArray = 'Parameters must be passed in an array.';
|
SErrParamsMustBeArray = 'Parameters must be passed in an array.';
|
||||||
|
SErrParamsRequiredParamNotFound = 'Required parameter "%s" not found.';
|
||||||
|
SErrParamsDataTypeMismatch = 'Expected parameter "%s" having type "%s", got "%s".';
|
||||||
|
SErrParamsNotAllowd = 'Parameter "%s" is not allowed.';
|
||||||
|
SErrParamsOnlyObjectsInArray = 'Array elements must be objects, got %s at position %d.';
|
||||||
SErrRequestMustBeObject = 'JSON-RPC Request must be an object.';
|
SErrRequestMustBeObject = 'JSON-RPC Request must be an object.';
|
||||||
SErrNoIDProperty = 'No "id" property found in request.';
|
SErrNoIDProperty = 'No "id" property found in request.';
|
||||||
SErrInvalidIDProperty = 'Type of "id" property is not correct.';
|
SErrInvalidIDProperty = 'Type of "id" property is not correct.';
|
||||||
@ -402,13 +410,15 @@ implementation
|
|||||||
uses dbugintf;
|
uses dbugintf;
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
function CreateJSONErrorObject(Const AMessage : String; Const ACode : Integer) : TJSONObject;
|
function CreateJSONErrorObject(const AMessage: String; const ACode: Integer
|
||||||
|
): TJSONObject;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=TJSONErrorObject.Create(['code',ACode,'message',AMessage])
|
Result:=TJSONErrorObject.Create(['code',ACode,'message',AMessage])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CreateJSON2ErrorResponse(Const AMessage : String; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
|
function CreateJSON2ErrorResponse(const AMessage: String; const ACode: Integer;
|
||||||
|
ID: TJSONData; idname: TJSONStringType): TJSONObject;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
If (ID=Nil) then
|
If (ID=Nil) then
|
||||||
@ -418,7 +428,8 @@ begin
|
|||||||
Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(AMessage,ACode),idname,ID]);
|
Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(AMessage,ACode),idname,ID]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CreateJSON2ErrorResponse(Const AFormat : String; Args : Array of const; Const ACode : Integer; ID : TJSONData = Nil; idname : TJSONStringType = 'id' ) : TJSONObject;
|
function CreateJSON2ErrorResponse(const AFormat: String; Args: array of const;
|
||||||
|
const ACode: Integer; ID: TJSONData; idname: TJSONStringType): TJSONObject;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
If (ID=Nil) then
|
If (ID=Nil) then
|
||||||
@ -428,7 +439,7 @@ begin
|
|||||||
Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(Format(AFormat,Args),ACode),idname,ID]);
|
Result:=TJSONErrorObject.Create(['jsonrpc','2.0','error',CreateJSONErrorObject(Format(AFormat,Args),ACode),idname,ID]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function CreateErrorForRequest(Const Req,Error : TJSONData) : TJSONData;
|
function CreateErrorForRequest(const Req, Error: TJSONData): TJSONData;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
I : Integer;
|
I : Integer;
|
||||||
@ -456,18 +467,29 @@ begin
|
|||||||
JSONRPCHandlerManager:=TheHandler;
|
JSONRPCHandlerManager:=TheHandler;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure JSONRPCError(Msg : String);
|
procedure JSONRPCError(const Msg: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Raise EJSONRPC.Create(Msg);
|
Raise EJSONRPC.Create(Msg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure JSONRPCError(Fmt : String; Args : Array of const);
|
procedure JSONRPCError(const Fmt: String; const Args: array of const);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Raise EJSONRPC.CreateFmt(Fmt,Args);
|
Raise EJSONRPC.CreateFmt(Fmt,Args);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure JSONRPCParamError(const Msg: String);
|
||||||
|
begin
|
||||||
|
raise EJSONRPC.CreateFmt(SErrParams, [Msg]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure JSONRPCParamError(const Fmt: String; const Args: array of const);
|
||||||
|
begin
|
||||||
|
raise EJSONRPC.CreateFmt(SErrParams, [Format(Fmt, Args)]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TJSONParamDef }
|
{ TJSONParamDef }
|
||||||
|
|
||||||
procedure TJSONParamDef.SetName(const AValue: TJSONStringType);
|
procedure TJSONParamDef.SetName(const AValue: TJSONStringType);
|
||||||
@ -529,13 +551,14 @@ begin
|
|||||||
Items[AIndex]:=AValue;
|
Items[AIndex]:=AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJSONParamDefs.AddParamDef(const AName: TJSONStringType; AType: TJSONType
|
function TJSONParamDefs.AddParamDef(const AName: TJSONStringType;
|
||||||
): TJSONParamDef;
|
AType: TJSONType; ARequired: Boolean): TJSONParamDef;
|
||||||
begin
|
begin
|
||||||
Result:=Add as TJSONParamDef;
|
Result:=Add as TJSONParamDef;
|
||||||
try
|
try
|
||||||
Result.Name:=AName;
|
Result.Name:=AName;
|
||||||
Result.DataType:=Atype;
|
Result.DataType:=Atype;
|
||||||
|
Result.Required:=ARequired;
|
||||||
except
|
except
|
||||||
FReeAndNil(Result);
|
FReeAndNil(Result);
|
||||||
Raise;
|
Raise;
|
||||||
@ -626,10 +649,76 @@ end;
|
|||||||
|
|
||||||
procedure TCustomJSONRPCHandler.DoCheckParams(const Params: TJSONData);
|
procedure TCustomJSONRPCHandler.DoCheckParams(const Params: TJSONData);
|
||||||
begin
|
begin
|
||||||
If (jroObjectParams in Options) and Not (Params is TJSONobject) then
|
if (Params is TJSONObject) then
|
||||||
JSONRPCError(SErrParams,[SErrParamsMustBeObject]);
|
begin
|
||||||
If (jroArrayParams in Options) and Not (Params is TJSONArray) then
|
if (jroArrayParams in Options) then
|
||||||
JSONRPCError(SErrParams,[SErrParamsMustBeArray]);
|
JSONRPCParamError(SErrParamsMustBeArray);
|
||||||
|
|
||||||
|
DoCheckParamDefsOnObject(Params as TJSONObject);
|
||||||
|
end else
|
||||||
|
if (Params is TJSONArray) then
|
||||||
|
begin
|
||||||
|
If (jroObjectParams in Options) then
|
||||||
|
JSONRPCParamError(SErrParamsMustBeArray);
|
||||||
|
|
||||||
|
DoCheckParamArray(Params as TJSONArray);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomJSONRPCHandler.DoCheckParamDefsOnObject(
|
||||||
|
const ParamObject: TJSONObject);
|
||||||
|
var
|
||||||
|
def: TJSONParamDef;
|
||||||
|
Param: TJSONData;
|
||||||
|
PropEnum: TJSONEnum;
|
||||||
|
begin
|
||||||
|
for TCollectionItem(def) in ParamDefs do
|
||||||
|
begin
|
||||||
|
// assert the typecast in for loop
|
||||||
|
Assert(def is TJSONParamDef,'Unexpected ParamDef item class.');
|
||||||
|
|
||||||
|
Param:=ParamObject.Find(def.Name);
|
||||||
|
// check required parameters
|
||||||
|
if not Assigned(Param) then
|
||||||
|
begin
|
||||||
|
if def.Required then
|
||||||
|
JSONRPCParamError(SErrParamsRequiredParamNotFound,[def.Name])
|
||||||
|
else
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// jtUnkown accepts all data types
|
||||||
|
if (def.DataType<>jtUnknown) and not (Param.JSONType=def.DataType) then
|
||||||
|
JSONRPCParamError(SErrParamsDataTypeMismatch,[def.Name,JSONTypeName(def.DataType),JSONTypeName(Param.JSONType)]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// check if additional parameters are given
|
||||||
|
if not (jroIgnoreExtraFields in Options) then
|
||||||
|
begin
|
||||||
|
for PropEnum in ParamObject do
|
||||||
|
begin
|
||||||
|
// only check for name is required other specs are checked before
|
||||||
|
if ParamDefs.FindParamDef(PropEnum.Key)=nil then
|
||||||
|
JSONRPCParamError(SErrParamsNotAllowd,[PropEnum.Key]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomJSONRPCHandler.DoCheckParamArray(const ParamArray: TJSONArray);
|
||||||
|
var
|
||||||
|
element: TJSONEnum;
|
||||||
|
begin
|
||||||
|
for element in ParamArray do
|
||||||
|
begin
|
||||||
|
// check object parameters if objects given
|
||||||
|
if (element.Value.JSONType=jtObject) then
|
||||||
|
begin
|
||||||
|
DoCheckParamDefsOnObject(element.Value as TJSONObject);
|
||||||
|
end else
|
||||||
|
// not an object
|
||||||
|
if (jroObjectParams in Options) then
|
||||||
|
JSONRPCParamError(SErrParamsOnlyObjectsInArray,[JSONTypeName(element.Value.JSONType),element.KeyNum]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCustomJSONRPCHandler.DoExecute(Const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
|
function TCustomJSONRPCHandler.DoExecute(Const Params: TJSONData;AContext : TJSONRPCCallContext): TJSONData;
|
||||||
|
Loading…
Reference in New Issue
Block a user