xmlrpc.pp 24 KB

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