xmlrpc.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. {
  2. $Id$
  3. XML-RPC server and client library
  4. Copyright (c) 2003-2004 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. }
  12. unit XMLRPC;
  13. interface
  14. uses SysUtils, Classes, fpAsync, ssockets, DOM, HTTPClient, HTTPSvlt;
  15. type
  16. EXMLRPCParser = class(Exception);
  17. TXMLRPCParams = class(TDOMElement);
  18. TXMLRPCValue = class(TDOMElement);
  19. TXMLRPCStruct = class(TXMLRPCValue);
  20. TXMLRPCArray = class(TXMLRPCValue);
  21. TXMLRPCWriter = class
  22. private
  23. Doc: TXMLDocument;
  24. protected
  25. function CreateValueEl: TXMLRPCValue;
  26. public
  27. constructor Create;
  28. destructor Destroy; override;
  29. function MakeStream: TMemoryStream;
  30. procedure WriteMethodCall(const AMethodName: DOMString;
  31. Params: TXMLRPCParams);
  32. procedure WriteResponse(Value: TXMLRPCValue);
  33. procedure WriteFaultResponse(FaultCode: LongInt;
  34. const FaultString: DOMString);
  35. function CreateParams: TXMLRPCParams;
  36. procedure AddParam(Params: TXMLRPCParams; Value: TXMLRPCValue);
  37. function CreateIntValue(i: LongInt): TXMLRPCValue;
  38. function CreateBooleanValue(b: Boolean): TXMLRPCValue;
  39. function CreateStringValue(const s: DOMString): TXMLRPCValue;
  40. function CreateDoubleValue(d: Double): TXMLRPCValue;
  41. function CreateDateTimeValue(dt: TDateTime): TXMLRPCValue;
  42. function CreateStruct: TXMLRPCStruct;
  43. procedure AddStructMember(Struct: TXMLRPCStruct; const Name: DOMString;
  44. Member: TXMLRPCValue);
  45. function CreateArray: TXMLRPCArray;
  46. procedure AddArrayElement(AArray: TXMLRPCArray; Value: TXMLRPCValue);
  47. // !!!: Missing: Binary data
  48. end;
  49. TXMLRPCPostType = (
  50. xmlrpcInvalid, // Invalid post type
  51. xmlrpcMethodCall, // Method call
  52. xmlrpcResponse, // Method call response (successfull)
  53. xmlrpcFaultResponse); // Method call response (failed)
  54. TXMLRPCParser = class
  55. private
  56. Doc: TXMLDocument;
  57. CurDataNode: TDOMNode;
  58. InArray: Boolean;
  59. procedure NextNode;
  60. procedure PrevNode;
  61. function GetValue: String;
  62. function FindStructMember(AStruct: TXMLRPCStruct;
  63. const AMemberName: String): TDOMElement;
  64. function GetStructMemberValue(MemberNode: TDOMElement): String;
  65. public
  66. constructor Create(AStream: TStream);
  67. destructor Destroy; override;
  68. function GetPostType: TXMLRPCPostType;
  69. function GetMethodName: String;
  70. procedure ResetValueCursor;
  71. // Simple values
  72. function GetNextInt: LongInt;
  73. function GetPrevInt: LongInt;
  74. function GetNextBoolean: Boolean;
  75. function GetPrevBoolean: Boolean;
  76. function GetNextString: String;
  77. function GetPrevString: String;
  78. function GetNextDouble: Double;
  79. function GetPrevDouble: Double;
  80. // !!!: Missing: DateTime, Binary data
  81. // Struct values
  82. function GetNextStruct: TXMLRPCStruct;
  83. function GetIntMember(AStruct: TXMLRPCStruct; const AName: String;
  84. ADefault: Integer): Integer;
  85. function GetBooleanMember(AStruct: TXMLRPCStruct; const AName: String;
  86. ADefault: Boolean): Boolean;
  87. function GetStringMember(AStruct: TXMLRPCStruct; const AName: String;
  88. const ADefault: String): String;
  89. function GetDoubleMember(AStruct: TXMLRPCStruct; const AName: String;
  90. ADefault: Double): Double;
  91. // Array values
  92. procedure BeginArray;
  93. procedure EndArray;
  94. end;
  95. { TOnXMLRPCCallCompleted = procedure(AParser: TXMLRPCParser) of object;
  96. TXMLRPCClient = class
  97. private
  98. FEventLoop: TEventLoop;
  99. FServerURL: String;
  100. FOnBeginRPC, FOnEndRPC: TNotifyEvent;
  101. RequestStream, ResponseStream: TMemoryStream;
  102. CurCallback: TOnXMLRPCCallCompleted;
  103. LocalEventLoop: TEventLoop;
  104. Connection: TCustomHttpClient;
  105. procedure MakeRequest(const AProcName: String; AArgs: array of const);
  106. procedure ProcessAnswer;
  107. procedure StreamSent(Sender: TObject);
  108. procedure DataAvailable(Sender: TObject);
  109. public
  110. constructor Create(AEventLoop: TEventLoop);
  111. procedure Call(ACallback: TOnXMLRPCCallCompleted;
  112. const AProcName: String; AArgs: array of const);
  113. procedure CallAsync(ACallback: TOnXMLRPCCallCompleted;
  114. const AProcName: String; AArgs: array of const);
  115. property EventLoop: TEventLoop read FEventLoop;
  116. property ServerURL: String read FServerURL write FServerURL;
  117. property OnBeginRPC: TNotifyEvent read FOnBeginRPC write FOnBeginRPC;
  118. property OnEndRPC: TNotifyEvent read FOnEndRPC write FOnEndRPC;
  119. end;}
  120. TCheckCallEvent = procedure(AParser: TXMLRPCParser; const APath: TStrings;
  121. var ExecCall: Boolean) of object;
  122. TExceptionEvent = procedure(e: Exception) of object;
  123. TXMLRPCServlet = class(THttpServlet)
  124. private
  125. FOnCheckCall: TCheckCallEvent;
  126. FOnException: TExceptionEvent;
  127. protected
  128. procedure DoPost(Req: THttpServletRequest; Resp: THttpServletResponse);
  129. override;
  130. public
  131. procedure Dispatch(AParser: TXMLRPCParser; AWriter: TXMLRPCWriter;
  132. APath: TStrings); virtual; abstract;
  133. property OnCheckCall: TCheckCallEvent read FOnCheckCall write FOnCheckCall;
  134. property OnException: TExceptionEvent read FOnException write FOnException;
  135. end;
  136. implementation
  137. uses XMLWrite, XMLRead;
  138. // Debugging stuff
  139. {$IFDEF XMLRPCDebug}
  140. const
  141. NodeNames: array[ELEMENT_NODE..NOTATION_NODE] of String = (
  142. 'Element',
  143. 'Attribute',
  144. 'Text',
  145. 'CDATA section',
  146. 'Entity reference',
  147. 'Entity',
  148. 'Processing instruction',
  149. 'Comment',
  150. 'Document',
  151. 'Document type',
  152. 'Document fragment',
  153. 'Notation'
  154. );
  155. procedure DumpNode(node: TDOMNode; spc: String);
  156. var
  157. i: Integer;
  158. attr: TDOMNode;
  159. begin
  160. Write(spc, NodeNames[node.NodeType]);
  161. if Copy(node.NodeName, 1, 1) <> '#' then
  162. Write(' "', node.NodeName, '"');
  163. if node.NodeValue <> '' then
  164. Write(' "', node.NodeValue, '"');
  165. if (node.Attributes <> nil) and (node.Attributes.Length > 0) then begin
  166. Write(',');
  167. for i := 0 to node.Attributes.Length - 1 do begin
  168. attr := node.Attributes.Item[i];
  169. Write(' ', attr.NodeName, ' = "', attr.NodeValue, '"');
  170. end;
  171. end;
  172. WriteLn;
  173. node := node.FirstChild;
  174. while Assigned(node) do
  175. begin
  176. DumpNode(node, spc + ' ');
  177. node := node.NextSibling;
  178. end;
  179. end;
  180. {$ENDIF}
  181. // XML-RPC Writer
  182. constructor TXMLRPCWriter.Create;
  183. begin
  184. inherited Create;
  185. Doc := TXMLDocument.Create;
  186. end;
  187. destructor TXMLRPCWriter.Destroy;
  188. begin
  189. Doc.Free;
  190. inherited Destroy;
  191. end;
  192. function TXMLRPCWriter.MakeStream: TMemoryStream;
  193. begin
  194. Result := TMemoryStream.Create;
  195. try
  196. WriteXMLFile(Doc, Result);
  197. // WriteXMLFile(Doc, THandleStream.Create(StdOutputHandle));
  198. Result.Position := 0;
  199. except
  200. on e: Exception do
  201. Result.Free;
  202. end;
  203. end;
  204. procedure TXMLRPCWriter.WriteMethodCall(const AMethodName: DOMString;
  205. Params: TXMLRPCParams);
  206. var
  207. El, El2: TDOMElement;
  208. begin
  209. El := Doc.CreateElement('methodCall');
  210. Doc.AppendChild(El);
  211. El2 := Doc.CreateElement('methodName');
  212. El.AppendChild(El2);
  213. El2.AppendChild(Doc.CreateTextNode(AMethodName));
  214. El.AppendChild(Params);
  215. end;
  216. procedure TXMLRPCWriter.WriteResponse(Value: TXMLRPCValue);
  217. var
  218. El, El2: TDOMElement;
  219. begin
  220. ASSERT(Value is TXMLRPCValue);
  221. El := Doc.CreateElement('methodResponse');
  222. Doc.AppendChild(El);
  223. El2 := Doc.CreateElement('params');
  224. El.AppendChild(El2);
  225. if not Assigned(Value) then
  226. Value := CreateBooleanValue(True);
  227. El := Doc.CreateElement('param');
  228. El2.AppendChild(El);
  229. El.AppendChild(Value);
  230. end;
  231. procedure TXMLRPCWriter.WriteFaultResponse(FaultCode: LongInt;
  232. const FaultString: DOMString);
  233. var
  234. El, El2: TDOMElement;
  235. Struct: TXMLRPCStruct;
  236. begin
  237. El := Doc.CreateElement('methodResponse');
  238. Doc.AppendChild(El);
  239. El2 := Doc.CreateElement('fault');
  240. El.AppendChild(El2);
  241. Struct := CreateStruct;
  242. AddStructMember(Struct, 'faultCode', CreateIntValue(FaultCode));
  243. AddStructMember(Struct, 'faultString', CreateStringValue(FaultString));
  244. El2.AppendChild(Struct);
  245. end;
  246. function TXMLRPCWriter.CreateParams: TXMLRPCParams;
  247. begin
  248. Result := TXMLRPCParams(Doc.CreateElement('params'));
  249. end;
  250. procedure TXMLRPCWriter.AddParam(Params: TXMLRPCParams; Value: TXMLRPCValue);
  251. var
  252. El: TDOMElement;
  253. begin
  254. ASSERT((Params is TXMLRPCParams) and (Value is TXMLRPCValue));
  255. El := Doc.CreateElement('param');
  256. Params.AppendChild(El);
  257. El.AppendChild(Value);
  258. end;
  259. function TXMLRPCWriter.CreateIntValue(i: LongInt): TXMLRPCValue;
  260. var
  261. El: TDOMElement;
  262. begin
  263. Result := CreateValueEl;
  264. El := Doc.CreateElement('int');
  265. Result.AppendChild(El);
  266. El.AppendChild(Doc.CreateTextNode(IntToStr(i)));
  267. end;
  268. function TXMLRPCWriter.CreateBooleanValue(b: Boolean): TXMLRPCValue;
  269. var
  270. El: TDOMElement;
  271. begin
  272. Result := CreateValueEl;
  273. El := Doc.CreateElement('boolean');
  274. Result.AppendChild(El);
  275. El.AppendChild(Doc.CreateTextNode(IntToStr(Ord(b))));
  276. end;
  277. function TXMLRPCWriter.CreateStringValue(const s: DOMString): TXMLRPCValue;
  278. var
  279. El: TDOMElement;
  280. begin
  281. Result := CreateValueEl;
  282. El := Doc.CreateElement('string');
  283. Result.AppendChild(El);
  284. if Length(s) > 0 then
  285. El.AppendChild(Doc.CreateTextNode(s));
  286. end;
  287. function TXMLRPCWriter.CreateDoubleValue(d: Double): TXMLRPCValue;
  288. var
  289. El: TDOMElement;
  290. begin
  291. Result := CreateValueEl;
  292. El := Doc.CreateElement('double');
  293. Result.AppendChild(El);
  294. El.AppendChild(Doc.CreateTextNode(FloatToStr(d)));
  295. end;
  296. function TXMLRPCWriter.CreateDateTimeValue(dt: TDateTime): TXMLRPCValue;
  297. var
  298. El: TDOMElement;
  299. begin
  300. Result := CreateValueEl;
  301. El := Doc.CreateElement('dateTime.iso8601');
  302. Result.AppendChild(El);
  303. El.AppendChild(Doc.CreateTextNode(FormatDateTime('ddmmyyyyThh:nn:ss', dt)));
  304. end;
  305. function TXMLRPCWriter.CreateStruct: TXMLRPCStruct;
  306. begin
  307. Result := TXMLRPCStruct(CreateValueEl);
  308. Result.AppendChild(Doc.CreateElement('struct'));
  309. end;
  310. procedure TXMLRPCWriter.AddStructMember(Struct: TXMLRPCStruct;
  311. const Name: DOMString; Member: TXMLRPCValue);
  312. var
  313. MemberEl, El: TDOMElement;
  314. begin
  315. ASSERT((Struct is TXMLRPCStruct) and (Name <> '') and
  316. (Member is TXMLRPCValue));
  317. MemberEl := Doc.CreateElement('member');
  318. Struct.FirstChild.AppendChild(MemberEl);
  319. El := Doc.CreateElement('name');
  320. MemberEl.AppendChild(El);
  321. El.AppendChild(Doc.CreateTextNode(Name));
  322. MemberEl.AppendChild(Member);
  323. end;
  324. function TXMLRPCWriter.CreateArray: TXMLRPCArray;
  325. var
  326. ArrayEl: TDOMElement;
  327. begin
  328. Result := TXMLRPCArray(CreateValueEl);
  329. ArrayEl := Doc.CreateElement('array');
  330. Result.AppendChild(ArrayEl);
  331. ArrayEl.AppendChild(Doc.CreateElement('data'));
  332. end;
  333. procedure TXMLRPCWriter.AddArrayElement(AArray: TXMLRPCArray;
  334. Value: TXMLRPCValue);
  335. begin
  336. ASSERT((AArray is TXMLRPCArray) and (Value is TXMLRPCValue));
  337. AArray.FirstChild.FirstChild.AppendChild(Value);
  338. end;
  339. function TXMLRPCWriter.CreateValueEl: TXMLRPCValue;
  340. begin
  341. Result := TXMLRPCValue(Doc.CreateElement('value'));
  342. end;
  343. // XML-RPC Parser
  344. constructor TXMLRPCParser.Create(AStream: TStream);
  345. var
  346. Node: TDOMNode;
  347. begin
  348. inherited Create;
  349. ReadXMLFile(Doc, AStream);
  350. Node := Doc.DocumentElement;
  351. {$IFDEF XMLRPCDebug}DumpNode(Node, 'Parser> ');{$ENDIF}
  352. if (Node.NodeName = 'methodCall') or (Node.NodeName = 'methodResponse') then
  353. begin
  354. Node := Node.FirstChild;
  355. while Assigned(Node) and (Node.NodeName <> 'params') do
  356. Node := Node.NextSibling;
  357. if Assigned(Node) then
  358. begin
  359. Node := Node.FirstChild;
  360. while Assigned(Node) and (Node.NodeName <> 'param') do
  361. Node := Node.NextSibling;
  362. CurDataNode := Node;
  363. end;
  364. end;
  365. end;
  366. destructor TXMLRPCParser.Destroy;
  367. begin
  368. Doc.Free;
  369. inherited Destroy;
  370. end;
  371. function TXMLRPCParser.GetPostType: TXMLRPCPostType;
  372. var
  373. Node: TDOMNode;
  374. begin
  375. Result := xmlrpcInvalid;
  376. Node := Doc.DocumentElement;
  377. if Node.NodeName = 'methodCall' then
  378. Result := xmlrpcMethodCall
  379. else if Node.NodeName = 'methodResponse' then
  380. begin
  381. Node := Node.FirstChild;
  382. while Assigned(Node) and (Node.NodeType <> ELEMENT_NODE) do
  383. Node := Node.NextSibling;
  384. if Assigned(Node) then
  385. if Node.NodeName = 'params' then
  386. Result := xmlrpcResponse
  387. else if Node.NodeName = 'fault' then
  388. Result := xmlrpcFaultResponse;
  389. end;
  390. end;
  391. function TXMLRPCParser.GetMethodName: String;
  392. var
  393. Node: TDOMNode;
  394. begin
  395. SetLength(Result, 0);
  396. Node := Doc.DocumentElement;
  397. if (not Assigned(Node)) or (Node.NodeName <> 'methodCall') then
  398. exit;
  399. Node := Node.FindNode('methodName');
  400. if not Assigned(Node) then
  401. exit;
  402. Node := Node.FirstChild;
  403. while Assigned(Node) do
  404. begin
  405. if Node.NodeType = TEXT_NODE then
  406. Result := Result + Node.NodeValue;
  407. Node := Node.NextSibling;
  408. end;
  409. end;
  410. procedure TXMLRPCParser.ResetValueCursor;
  411. begin
  412. CurDataNode := CurDataNode.ParentNode.FirstChild;
  413. {$IFDEF XMLRPCDebug}DumpNode(CurDataNode, 'ResetValueCursor> ');{$ENDIF}
  414. end;
  415. function TXMLRPCParser.GetNextInt: LongInt;
  416. begin
  417. Result := StrToInt(GetValue);
  418. NextNode;
  419. end;
  420. function TXMLRPCParser.GetPrevInt: LongInt;
  421. begin
  422. PrevNode;
  423. Result := StrToInt(GetValue);
  424. end;
  425. function TXMLRPCParser.GetNextBoolean: Boolean;
  426. begin
  427. Result := GetValue = '1';
  428. NextNode;
  429. end;
  430. function TXMLRPCParser.GetPrevBoolean: Boolean;
  431. begin
  432. PrevNode;
  433. Result := GetValue = '1';
  434. end;
  435. function TXMLRPCParser.GetNextString: String;
  436. begin
  437. Result := GetValue;
  438. NextNode;
  439. end;
  440. function TXMLRPCParser.GetPrevString: String;
  441. begin
  442. PrevNode;
  443. Result := GetValue;
  444. end;
  445. function TXMLRPCParser.GetNextDouble: Double;
  446. begin
  447. Result := StrToFloat(GetValue);
  448. NextNode;
  449. end;
  450. function TXMLRPCParser.GetPrevDouble: Double;
  451. begin
  452. PrevNode;
  453. Result := StrToFloat(GetValue);
  454. end;
  455. function TXMLRPCParser.GetNextStruct: TXMLRPCStruct;
  456. begin
  457. if Assigned(CurDataNode) and Assigned(CurDataNode.FirstChild) then
  458. begin
  459. Result := TXMLRPCStruct(CurDataNode.FirstChild);
  460. while Assigned(Result) and (Result.NodeName <> 'struct') do
  461. Result := TXMLRPCStruct(Result.NextSibling);
  462. NextNode;
  463. end else
  464. Result := nil;
  465. end;
  466. function TXMLRPCParser.GetIntMember(AStruct: TXMLRPCStruct;
  467. const AName: String; ADefault: Integer): Integer;
  468. var
  469. MemberNode: TDOMElement;
  470. begin
  471. MemberNode := FindStructMember(AStruct, AName);
  472. if Assigned(MemberNode) then
  473. Result := StrToInt(GetStructMemberValue(MemberNode))
  474. else
  475. Result := ADefault;
  476. end;
  477. function TXMLRPCParser.GetBooleanMember(AStruct: TXMLRPCStruct;
  478. const AName: String; ADefault: Boolean): Boolean;
  479. var
  480. MemberNode: TDOMElement;
  481. begin
  482. MemberNode := FindStructMember(AStruct, AName);
  483. if Assigned(MemberNode) then
  484. Result := GetStructMemberValue(MemberNode) = '1'
  485. else
  486. Result := ADefault;
  487. end;
  488. function TXMLRPCParser.GetStringMember(AStruct: TXMLRPCStruct;
  489. const AName: String; const ADefault: String): String;
  490. var
  491. MemberNode: TDOMElement;
  492. begin
  493. MemberNode := FindStructMember(AStruct, AName);
  494. if Assigned(MemberNode) then
  495. Result := GetStructMemberValue(MemberNode)
  496. else
  497. Result := ADefault;
  498. end;
  499. function TXMLRPCParser.GetDoubleMember(AStruct: TXMLRPCStruct;
  500. const AName: String; ADefault: Double): Double;
  501. var
  502. MemberNode: TDOMElement;
  503. begin
  504. MemberNode := FindStructMember(AStruct, AName);
  505. if Assigned(MemberNode) then
  506. Result := StrToFloat(GetStructMemberValue(MemberNode))
  507. else
  508. Result := ADefault;
  509. end;
  510. procedure TXMLRPCParser.BeginArray;
  511. begin
  512. if Assigned(CurDataNode) then
  513. begin
  514. CurDataNode := CurDataNode.FirstChild;
  515. while Assigned(CurDataNode) and (CurDataNode.NodeName <> 'array') do
  516. CurDataNode := CurDataNode.NextSibling;
  517. if Assigned(CurDataNode) then
  518. begin
  519. CurDataNode := CurDataNode.FirstChild;
  520. while Assigned(CurDataNode) and (CurDataNode.NodeName <> 'data') do
  521. CurDataNode := CurDataNode.NextSibling;
  522. { if Assigned(CurDataNode) then
  523. begin
  524. CurDataNodeParent := CurDataNode;
  525. CurDataNode := nil;
  526. ResetValueCursor;
  527. end;}
  528. end;
  529. //NextNode;
  530. end;
  531. end;
  532. procedure TXMLRPCParser.EndArray;
  533. begin
  534. end;
  535. procedure TXMLRPCParser.NextNode;
  536. begin
  537. repeat
  538. CurDataNode := CurDataNode.NextSibling;
  539. until (not Assigned(CurDataNode)) or (CurDataNode.NodeType = ELEMENT_NODE);
  540. end;
  541. procedure TXMLRPCParser.PrevNode;
  542. begin
  543. {$IFDEF XMLRPCDebug}DumpNode(CurDataNode, 'PrevNode before> ');{$ENDIF}
  544. if Assigned(CurDataNode.PreviousSibling) then
  545. CurDataNode := CurDataNode.PreviousSibling
  546. else
  547. CurDataNode := CurDataNode.ParentNode.LastChild;
  548. {$IFDEF XMLRPCDebug}DumpNode(CurDataNode, 'PrevNode result> ');{$ENDIF}
  549. end;
  550. function TXMLRPCParser.GetValue: String;
  551. var
  552. Node: TDOMNode;
  553. begin
  554. if not Assigned(CurDataNode) then
  555. Result := ''
  556. else
  557. begin
  558. Node := CurDataNode;
  559. if Node.NodeName <> 'value' then
  560. Node := Node.FirstChild;
  561. Node := Node.FirstChild;
  562. if Node.NodeType = TEXT_NODE then
  563. Result := Node.NodeValue
  564. else begin
  565. while Assigned(Node) and (Node.NodeType <> ELEMENT_NODE) do
  566. Node := Node.NextSibling;
  567. if Assigned(Node) then
  568. begin
  569. Node := Node.FirstChild;
  570. if Assigned(Node) and (Node.NodeType = TEXT_NODE) then
  571. Result := Node.NodeValue
  572. else
  573. Result := '';
  574. end;
  575. end;
  576. end;
  577. end;
  578. function TXMLRPCParser.FindStructMember(AStruct: TXMLRPCStruct;
  579. const AMemberName: String): TDOMElement;
  580. var
  581. Node: TDOMNode;
  582. begin
  583. Result := TDOMElement(AStruct.FirstChild);
  584. while Assigned(Result) and (Result.NodeName = 'member') do
  585. begin
  586. Node := Result.FirstChild;
  587. while Assigned(Node) do
  588. begin
  589. if Node.NodeName = 'name' then
  590. begin
  591. if Assigned(Node.FirstChild) and
  592. (CompareText(Node.FirstChild.NodeValue, AMemberName) = 0) then
  593. exit;
  594. end;
  595. Node := Node.NextSibling;
  596. end;
  597. Result := TDOMElement(Result.NextSibling);
  598. end;
  599. end;
  600. function TXMLRPCParser.GetStructMemberValue(MemberNode: TDOMElement): String;
  601. var
  602. Node, Subnode: TDOMNode;
  603. begin
  604. Node := MemberNode.FirstChild;
  605. while Assigned(Node) do
  606. begin
  607. if Node.NodeName = 'value' then
  608. begin
  609. Subnode := Node.FirstChild;
  610. if Assigned(Subnode) and (Subnode.NodeType = TEXT_NODE) then
  611. begin
  612. Result := Subnode.NodeValue;
  613. exit;
  614. end;
  615. while Assigned(Subnode) do
  616. begin
  617. if Subnode.NodeType = ELEMENT_NODE then
  618. begin
  619. if Assigned(Subnode.FirstChild) then
  620. Result := Subnode.FirstChild.NodeValue
  621. else
  622. Result := '';
  623. exit;
  624. end;
  625. Subnode := Subnode.NextSibling;
  626. end;
  627. end;
  628. Node := Node.NextSibling;
  629. end;
  630. end;
  631. // XML-RPC Client
  632. {
  633. constructor TXMLRPCClient.Create(AEventLoop: TEventLoop);
  634. begin
  635. inherited Create;
  636. FEventLoop := AEventLoop;
  637. end;
  638. procedure TXMLRPCClient.Call(ACallback: TOnXMLRPCCallCompleted;
  639. const AProcName: String; AArgs: array of const);
  640. var
  641. Host: String;
  642. Port: Word;
  643. Socket: TInetSocket;
  644. begin
  645. CurCallback := ACallback;
  646. MakeRequest(AProcName, AArgs);
  647. try
  648. ResponseStream := TMemoryStream.Create;
  649. if Assigned(OnBeginRPC) then
  650. OnBeginRPC(Self);
  651. Host := 'localhost';
  652. Port := 12345;
  653. Socket := TInetSocket.Create(Host, Port);
  654. try
  655. RequestStream.Position := 0;
  656. // Socket.Write(RequestStream.Memory^, RequestStream.Size);
  657. LocalEventLoop := TEventLoop.Create;
  658. try
  659. Connection := TCustomHttpClient.Create(LocalEventLoop, Socket);
  660. try
  661. Connection.HeaderToSend := THttpRequestHeader.Create;
  662. with THttpRequestHeader(Connection.HeaderToSend) do
  663. begin
  664. Command := 'POST';
  665. URI := '/xmlrpc';
  666. UserAgent := 'Free Pascal XML-RPC';
  667. ContentType := 'text/xml';
  668. ContentLength := RequestStream.Size;
  669. end;
  670. Connection.StreamToSend := RequestStream;
  671. Connection.ReceivedHeader := THttpResponseHeader.Create;
  672. Connection.ReceivedStream := ResponseStream;
  673. Connection.OnStreamSent := @StreamSent;
  674. Connection.Send;
  675. LocalEventLoop.Run;
  676. finally
  677. if Assigned(Connection) then
  678. begin
  679. Connection.HeaderToSend.Free;
  680. Connection.ReceivedHeader.Free;
  681. end;
  682. Connection.Free;
  683. end;
  684. finally
  685. LocalEventLoop.Free;
  686. end;
  687. finally
  688. Socket.Free;
  689. end;
  690. finally
  691. FreeAndNil(RequestStream);
  692. end;
  693. // HTTPConnection.Post(ServerURL, RequestStream, ResponseStream);
  694. ProcessAnswer;
  695. end;
  696. procedure TXMLRPCClient.CallAsync(ACallback: TOnXMLRPCCallCompleted;
  697. const AProcName: String; AArgs: array of const);
  698. begin
  699. CurCallback := ACallback;
  700. MakeRequest(AProcName, AArgs);
  701. ResponseStream := TMemoryStream.Create;
  702. if Assigned(OnBeginRPC) then
  703. OnBeginRPC(Self);
  704. // CurRPCThread := TRPCThread.Create(Self);
  705. end;
  706. procedure TXMLRPCClient.MakeRequest(const AProcName: String;
  707. AArgs: array of const);
  708. var
  709. Writer: TXMLRPCWriter;
  710. Params: TXMLRPCParams;
  711. i: Integer;
  712. begin
  713. Writer := TXMLRPCWriter.Create;
  714. try
  715. Params := Writer.CreateParams;
  716. try
  717. for i := Low(AArgs) to High(AArgs) do
  718. with AArgs[i] do
  719. case VType of
  720. vtInteger: Writer.AddParam(Params, Writer.CreateIntValue(VInteger));
  721. vtBoolean: Writer.AddParam(Params, Writer.CreateBooleanValue(VBoolean));
  722. vtChar: Writer.AddParam(Params, Writer.CreateStringValue(VChar));
  723. vtExtended: Writer.AddParam(Params, Writer.CreateDoubleValue(VExtended^));
  724. vtString: Writer.AddParam(Params, Writer.CreateStringValue(VString^));
  725. vtPChar: Writer.AddParam(Params, Writer.CreateStringValue(VPChar));
  726. } {$IFDEF HasWideStrings}
  727. { vtWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VWideChar));
  728. vtPWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VPWideChar));
  729. } {$ENDIF}
  730. { vtAnsiString: Writer.AddParam(Params, Writer.CreateStringValue(String(VAnsiString)));
  731. // vtCurrency: ?
  732. // vtVariant: ?
  733. } {$IFDEF HasWideStrings}
  734. { vtWideString: Writer.AddParam(Params, Writer.CreateStringValue(WideString(VWideString)));
  735. } {$ENDIF}
  736. { vtInt64: Writer.AddParam(Params, Writer.CreateIntValue(VInt64^));
  737. else
  738. raise Exception.Create('Unsupported data type in RPC argument list');
  739. end;
  740. Writer.WriteMethodCall(AProcName, Params);
  741. RequestStream := Writer.MakeStream;
  742. except
  743. Params.Free;
  744. end;
  745. finally
  746. Writer.Free;
  747. end;
  748. end;
  749. procedure TXMLRPCClient.ProcessAnswer;
  750. var
  751. Parser: TXMLRPCParser;
  752. begin
  753. ResponseStream.Position := 0;
  754. Parser := TXMLRPCParser.Create(ResponseStream);
  755. FreeAndNil(ResponseStream);
  756. try
  757. case Parser.GetPostType of
  758. xmlrpcFaultResponse:
  759. } {raise Exception.Create(Format('%d - %s', [Parser.GetNextInt,
  760. Parser.GetNextString]));}
  761. { raise Exception.Create('Fehler bei XML-RPC-Befehlsausführung');
  762. xmlrpcResponse:
  763. if Assigned(CurCallback) then
  764. CurCallback(Parser);
  765. else
  766. raise Exception.Create('Invalid response');
  767. end;
  768. finally
  769. Parser.Free;
  770. if Assigned(OnEndRPC) then
  771. OnEndRPC(Self);
  772. end;
  773. end;
  774. procedure TXMLRPCClient.StreamSent(Sender: TObject);
  775. begin
  776. // LocalEventLoop.Break;
  777. Connection.Receive;
  778. end;
  779. procedure TXMLRPCClient.DataAvailable(Sender: TObject);
  780. begin
  781. LocalEventLoop.Break;
  782. end;
  783. }
  784. // XML-RPC Server
  785. procedure TXMLRPCServlet.DoPost(Req: THttpServletRequest;
  786. Resp: THttpServletResponse);
  787. var
  788. Parser: TXMLRPCParser;
  789. Writer: TXMLRPCWriter;
  790. Path: TStringList;
  791. LastDot, i: Integer;
  792. s, PathStr: String;
  793. AnswerStream: TStream;
  794. ExecCall: Boolean;
  795. begin
  796. Parser := TXMLRPCParser.Create(Req.InputStream);
  797. try
  798. if Parser.GetPostType <> xmlrpcMethodCall then
  799. exit;
  800. Resp.ContentType := 'text/xml';
  801. Writer := TXMLRPCWriter.Create;
  802. try
  803. try
  804. // ...Header auswerten und zum Dispatcher springen...
  805. PathStr := Parser.GetMethodName + '.';
  806. Path := TStringList.Create;
  807. try
  808. LastDot := 1;
  809. for i := 1 to Length(PathStr) do
  810. if PathStr[i] = '.' then
  811. begin
  812. Path.Add(UpperCase(Copy(PathStr, LastDot, i - LastDot)));
  813. LastDot := i + 1;
  814. end;
  815. ExecCall := True;
  816. if Assigned(OnCheckCall) then
  817. OnCheckCall(Parser, Path, ExecCall);
  818. if ExecCall then
  819. Dispatch(Parser, Writer, Path)
  820. else
  821. Writer.WriteFaultResponse(2, 'May not execute request');
  822. finally
  823. Path.Free;
  824. end;
  825. except
  826. on e: Exception do
  827. begin
  828. if Assigned(OnException) then
  829. OnException(e);
  830. Writer.WriteFaultResponse(2,
  831. 'Execution error: ' + e.ClassName + ': ' + e.Message);
  832. end;
  833. end;
  834. AnswerStream := Writer.MakeStream;
  835. try
  836. Resp.ContentLength := AnswerStream.Size;
  837. Resp.OutputStream.CopyFrom(AnswerStream, AnswerStream.Size);
  838. finally
  839. AnswerStream.Free;
  840. end;
  841. finally
  842. Writer.Free;
  843. end;
  844. finally
  845. Parser.Free;
  846. end;
  847. end;
  848. end.
  849. {
  850. $Log$
  851. Revision 1.6 2004-08-14 20:33:45 sg
  852. * Added callback for RPC filtering etc. for XML-RPC servlets
  853. Revision 1.5 2004/02/02 17:12:01 sg
  854. * Some small fixes to get the code at least compiling again; the HTTP
  855. client class is not expected to work at the moment, and the XML-RPC
  856. client has been fully disabled for now.
  857. Revision 1.4 2003/11/27 11:28:44 sg
  858. * Debugging output is now enabled when the symbol "XMLRPCDebug" exists,
  859. and not generally when compiled in debug mode
  860. Revision 1.3 2003/11/22 12:10:27 sg
  861. * Just a small adaption to chages in HTTP unit
  862. Revision 1.2 2003/06/25 08:49:21 sg
  863. * Added OnException event to TXMLRPCServlet
  864. Revision 1.1 2002/04/25 19:30:29 sg
  865. * First version (with exception of the HTTP unit: This is an improved version
  866. of the old asyncio HTTP unit, now adapted to fpAsync)
  867. }