xmlrpc.pp 24 KB

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