webjsonrpc.pp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. {
  2. This file is part of the Free Component Library
  3. JSON-RPC functionality - http dependant part
  4. Copyright (c) 2007 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit webjsonrpc;
  12. {$mode objfpc}{$H+}
  13. { $define debugjsonrpc}
  14. interface
  15. uses
  16. Classes, SysUtils, fpjson, fpjsonrpc, httpdefs, fphttp, jsonparser;
  17. Type
  18. { ---------------------------------------------------------------------
  19. HTTP handling and content producing methods
  20. ---------------------------------------------------------------------}
  21. { TCustomJSONRPCContentProducer }
  22. TCustomJSONRPCContentProducer = Class(THTTPContentProducer)
  23. Protected
  24. Function GetIDProperty : String; virtual;
  25. Procedure DoGetContent(ARequest : TRequest; Content : TStream; Var Handled : Boolean); override;
  26. Function GetDispatcher : TCustomJSONRPCDispatcher; virtual; abstract;
  27. end;
  28. { TJSONRPCContentProducer }
  29. TJSONRPCContentProducer = Class(TCustomJSONRPCContentProducer)
  30. private
  31. FDispatcher: TCustomJSONRPCDispatcher;
  32. procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher);
  33. Protected
  34. Function GetDispatcher : TCustomJSONRPCDispatcher; override;
  35. procedure Notification(AComponent: TComponent; Operation: TOperation);override;
  36. Published
  37. Property Dispatcher : TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher;
  38. end;
  39. { TJSONRPCSessionContext }
  40. TJSONRPCSessionContext = Class(TJSONRPCCallContext)
  41. private
  42. FSession: TCustomSession;
  43. Public
  44. Constructor CreateSession(ASession : TCustomSession);
  45. Property Session : TCustomSession Read FSession;
  46. end;
  47. { TSessionJSONRPCDispatcher }
  48. TSessionJSONRPCDispatcher = Class(TCustomJSONRPCDispatcher)
  49. Protected
  50. Function FindHandler(Const AClassName,AMethodName : TJSONStringType;AContext : TJSONRPCCallContext; Out FreeObject : TComponent) : TCustomJSONRPCHandler; override;
  51. Published
  52. Property OnStartBatch;
  53. Property OnDispatchRequest;
  54. Property OnFindHandler;
  55. Property OnEndBatch;
  56. Property Options;
  57. end;
  58. { TJSONRPCDispatchModule }
  59. TJSONRPCDispatchModule = Class(TSessionHTTPModule)
  60. protected
  61. Function CreateContext : TJSONRPCSessionContext;
  62. Function DispatchRequest(Const ARequest : TRequest; ADispatcher : TCustomJSONRPCDispatcher) : TJSONData;
  63. end;
  64. { TCustomJSONRPCModule }
  65. TCustomJSONRPCModule = Class(TJSONRPCDispatchModule)
  66. private
  67. FDispatcher: TCustomJSONRPCDispatcher;
  68. FOptions: TJSONRPCDispatchOptions;
  69. FRequest: TRequest;
  70. FResponse: TResponse;
  71. FResponseContentType: String;
  72. procedure SetDispatcher(const AValue: TCustomJSONRPCDispatcher);
  73. Protected
  74. Function GetResponseContentType : String;
  75. Function CreateDispatcher : TCustomJSONRPCDispatcher; virtual;
  76. procedure Notification(AComponent: TComponent; Operation: TOperation);override;
  77. Property Dispatcher : TCustomJSONRPCDispatcher Read FDispatcher Write SetDispatcher;
  78. Property DispatchOptions : TJSONRPCDispatchOptions Read FOptions Write FOptions default DefaultDispatchOptions;
  79. Public
  80. Constructor CreateNew(AOwner : TComponent; CreateMode : Integer); override;
  81. Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse); override;
  82. // Access to request
  83. Property Request: TRequest Read FRequest;
  84. // Access to response
  85. Property Response: TResponse Read FResponse;
  86. // Response Content-Type. If left empty, application/json is used.
  87. Property ResponseContentType : String Read FResponseContentType Write FResponseContentType;
  88. end;
  89. { TJSONRPCDataModule }
  90. { TJSONRPCModule }
  91. TJSONRPCModule = Class(TCustomJSONRPCModule)
  92. Published
  93. Property Dispatcher;
  94. Property DispatchOptions;
  95. Property ResponseContentType;
  96. end;
  97. implementation
  98. {$ifdef debugjsonrpc}
  99. uses dbugintf;
  100. {$endif}
  101. Const
  102. SApplicationJSON = 'application/json';
  103. { TCustomJSONRPCContentProducer }
  104. function TCustomJSONRPCContentProducer.GetIDProperty: String;
  105. begin
  106. Result:='id';
  107. end;
  108. procedure TCustomJSONRPCContentProducer.DoGetContent(ARequest: TRequest;
  109. Content: TStream; var Handled: Boolean);
  110. Var
  111. Disp : TCustomJSONRPCDispatcher;
  112. P : TJSONParser;
  113. Req,res : TJSONData;
  114. R : TJSONStringType;
  115. begin
  116. Disp:=Self.GetDispatcher;
  117. P:= TJSONParser.Create(ARequest.Content);
  118. try
  119. Res:=Nil;
  120. Req:=Nil;
  121. try
  122. try
  123. Req:=P.Parse;
  124. If (Disp<>Nil) then
  125. Res:=Disp.Execute(Req,Nil)
  126. else // No dispatcher, create error(s)
  127. Res:=CreateErrorForRequest(Req,CreateJSON2ErrorResponse(SErrNoDispatcher,EJSONRPCInternalError,Nil,GetIDProperty));
  128. except
  129. On E : Exception Do
  130. begin
  131. Res:=CreateJSON2ErrorResponse(E.Message,EJSONRPCParseError,Nil,GetIDProperty);
  132. end;
  133. end;
  134. try
  135. If Assigned(Res) then
  136. begin
  137. R:=Res.AsJSON;
  138. Content.WriteBuffer(R[1],Length(R));
  139. end;
  140. Handled:=True;
  141. finally
  142. FreeAndNil(Res);
  143. end;
  144. finally
  145. Req.Free;
  146. end;
  147. finally
  148. P.Free;
  149. end;
  150. end;
  151. { TJSONRPCContentProducer }
  152. procedure TJSONRPCContentProducer.SetDispatcher(
  153. const AValue: TCustomJSONRPCDispatcher);
  154. begin
  155. if FDispatcher=AValue then exit;
  156. If Assigned(FDispatcher) then
  157. FDispatcher.RemoveFreeNotification(Self);
  158. FDispatcher:=AValue;
  159. If Assigned(FDispatcher) then
  160. FDispatcher.FreeNotification(Self);
  161. end;
  162. function TJSONRPCContentProducer.GetDispatcher: TCustomJSONRPCDispatcher;
  163. begin
  164. Result:=FDispatcher;
  165. end;
  166. procedure TJSONRPCContentProducer.Notification(AComponent: TComponent;
  167. Operation: TOperation);
  168. begin
  169. inherited Notification(AComponent, Operation);
  170. If (Operation=opRemove) and (AComponent=FDispatcher) then
  171. FDispatcher:=Nil;
  172. end;
  173. { TCustomJSONRPCModule }
  174. procedure TCustomJSONRPCModule.SetDispatcher(
  175. const AValue: TCustomJSONRPCDispatcher);
  176. begin
  177. if FDispatcher=AValue then exit;
  178. If Assigned(FDispatcher) then
  179. FDispatcher.RemoveFreeNotification(Self);
  180. FDispatcher:=AValue;
  181. If Assigned(FDispatcher) then
  182. FDispatcher.FreeNotification(Self);
  183. end;
  184. function TCustomJSONRPCModule.GetResponseContentType: String;
  185. begin
  186. Result:=FResponseContentType;
  187. if Result='' then
  188. Result:=SApplicationJSON;
  189. end;
  190. function TCustomJSONRPCModule.CreateDispatcher: TCustomJSONRPCDispatcher;
  191. Var
  192. S : TSessionJSONRPCDispatcher;
  193. begin
  194. S:=TSessionJSONRPCDispatcher.Create(Self);
  195. S.Options:=DispatchOptions;
  196. Result:=S;
  197. end;
  198. procedure TCustomJSONRPCModule.Notification(AComponent: TComponent;
  199. Operation: TOperation);
  200. begin
  201. inherited Notification(AComponent, Operation);
  202. If (Operation=opRemove) and (AComponent=FDispatcher) then
  203. FDispatcher:=Nil;
  204. end;
  205. constructor TCustomJSONRPCModule.CreateNew(AOwner: TComponent;
  206. CreateMode: Integer);
  207. begin
  208. inherited CreateNew(AOwner, CreateMode);
  209. FOptions:=DefaultDispatchOptions+[jdoSearchRegistry];
  210. end;
  211. procedure TCustomJSONRPCModule.HandleRequest(ARequest: TRequest;
  212. AResponse: TResponse);
  213. Var
  214. Disp : TCustomJSONRPCDispatcher;
  215. res : TJSONData;
  216. R : TJSONStringType;
  217. begin
  218. If (Dispatcher=Nil) then
  219. Dispatcher:=CreateDispatcher;
  220. Disp:=Dispatcher;
  221. Res:=DispatchRequest(ARequest,Disp);
  222. try
  223. If Assigned(Res) then
  224. begin
  225. AResponse.FreeContentStream:=True;
  226. AResponse.ContentStream:=TMemoryStream.Create;
  227. R:=Res.AsJSON;
  228. AResponse.ContentStream.WriteBuffer(R[1],Length(R));
  229. AResponse.ContentLength:=AResponse.ContentStream.Size;
  230. R:=''; // Free up mem
  231. AResponse.ContentType:=GetResponseContentType;
  232. end;
  233. AResponse.SendResponse;
  234. finally
  235. Res.Free;
  236. end;
  237. end;
  238. { TJSONRPCSessionContext }
  239. constructor TJSONRPCSessionContext.CreateSession(ASession: TCustomSession);
  240. begin
  241. FSession:=ASession;
  242. end;
  243. { TJSONRPCDispatchModule }
  244. function TJSONRPCDispatchModule.CreateContext: TJSONRPCSessionContext;
  245. begin
  246. If CreateSession then
  247. Result:=TJSONRPCSessionContext.CreateSession(Session)
  248. else
  249. Result:=TJSONRPCSessionContext.CreateSession(Nil);
  250. end;
  251. Function TJSONRPCDispatchModule.DispatchRequest(const ARequest: TRequest;
  252. ADispatcher: TCustomJSONRPCDispatcher): TJSONData;
  253. var
  254. P : TJSONParser;
  255. Req : TJSONData;
  256. C : TJSONRPCSessionContext;
  257. begin
  258. P:= TJSONParser.Create(ARequest.Content);
  259. try
  260. Result:=Nil;
  261. Req:=Nil;
  262. try
  263. try
  264. Req:=P.Parse;
  265. C:=CreateContext;
  266. try
  267. {$ifdef debugjsonrpc}SendDebugFmt('Dispatching request : "%s"',[Req.AsJSON]);{$endif}
  268. Result:=ADispatcher.Execute(Req,C);
  269. finally
  270. C.Free;
  271. end;
  272. except
  273. On E : Exception Do
  274. Result:=CreateJSON2ErrorResponse(E.Message,EJSONRPCParseError,Nil,ADispatcher.TransactionProperty);
  275. end;
  276. finally
  277. Req.Free;
  278. end;
  279. finally
  280. P.Free;
  281. end;
  282. end;
  283. { TSessionJSONRPCDispatcher }
  284. function TSessionJSONRPCDispatcher.FindHandler(const AClassName,
  285. AMethodName: TJSONStringType; AContext: TJSONRPCCallContext; out
  286. FreeObject: TComponent): TCustomJSONRPCHandler;
  287. begin
  288. Result:=Inherited FindHandler(AClassName,AMethodName,AContext,FreeObject);
  289. If (AContext is TJSONRPCSessionContext) and (FreeObject is TCustomJSONRPCModule) then
  290. TCustomJSONRPCModule(FreeObject).Session:=TJSONRPCSessionContext(AContext).Session;
  291. end;
  292. end.