xmlrpc.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  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, 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. 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 XMLRPCDebug}
  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 XMLRPCDebug}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 XMLRPCDebug}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 XMLRPCDebug}DumpNode(CurDataNode, 'PrevNode before> ');{$ENDIF}
  540. if Assigned(CurDataNode.PreviousSibling) then
  541. CurDataNode := CurDataNode.PreviousSibling
  542. else
  543. CurDataNode := CurDataNode.ParentNode.LastChild;
  544. {$IFDEF XMLRPCDebug}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. {
  629. constructor TXMLRPCClient.Create(AEventLoop: TEventLoop);
  630. begin
  631. inherited Create;
  632. FEventLoop := AEventLoop;
  633. end;
  634. procedure TXMLRPCClient.Call(ACallback: TOnXMLRPCCallCompleted;
  635. const AProcName: String; AArgs: array of const);
  636. var
  637. Host: String;
  638. Port: Word;
  639. Socket: TInetSocket;
  640. begin
  641. CurCallback := ACallback;
  642. MakeRequest(AProcName, AArgs);
  643. try
  644. ResponseStream := TMemoryStream.Create;
  645. if Assigned(OnBeginRPC) then
  646. OnBeginRPC(Self);
  647. Host := 'localhost';
  648. Port := 12345;
  649. Socket := TInetSocket.Create(Host, Port);
  650. try
  651. RequestStream.Position := 0;
  652. // Socket.Write(RequestStream.Memory^, RequestStream.Size);
  653. LocalEventLoop := TEventLoop.Create;
  654. try
  655. Connection := TCustomHttpClient.Create(LocalEventLoop, Socket);
  656. try
  657. Connection.HeaderToSend := THttpRequestHeader.Create;
  658. with THttpRequestHeader(Connection.HeaderToSend) do
  659. begin
  660. Command := 'POST';
  661. URI := '/xmlrpc';
  662. UserAgent := 'Free Pascal XML-RPC';
  663. ContentType := 'text/xml';
  664. ContentLength := RequestStream.Size;
  665. end;
  666. Connection.StreamToSend := RequestStream;
  667. Connection.ReceivedHeader := THttpResponseHeader.Create;
  668. Connection.ReceivedStream := ResponseStream;
  669. Connection.OnStreamSent := @StreamSent;
  670. Connection.Send;
  671. LocalEventLoop.Run;
  672. finally
  673. if Assigned(Connection) then
  674. begin
  675. Connection.HeaderToSend.Free;
  676. Connection.ReceivedHeader.Free;
  677. end;
  678. Connection.Free;
  679. end;
  680. finally
  681. LocalEventLoop.Free;
  682. end;
  683. finally
  684. Socket.Free;
  685. end;
  686. finally
  687. FreeAndNil(RequestStream);
  688. end;
  689. // HTTPConnection.Post(ServerURL, RequestStream, ResponseStream);
  690. ProcessAnswer;
  691. end;
  692. procedure TXMLRPCClient.CallAsync(ACallback: TOnXMLRPCCallCompleted;
  693. const AProcName: String; AArgs: array of const);
  694. begin
  695. CurCallback := ACallback;
  696. MakeRequest(AProcName, AArgs);
  697. ResponseStream := TMemoryStream.Create;
  698. if Assigned(OnBeginRPC) then
  699. OnBeginRPC(Self);
  700. // CurRPCThread := TRPCThread.Create(Self);
  701. end;
  702. procedure TXMLRPCClient.MakeRequest(const AProcName: String;
  703. AArgs: array of const);
  704. var
  705. Writer: TXMLRPCWriter;
  706. Params: TXMLRPCParams;
  707. i: Integer;
  708. begin
  709. Writer := TXMLRPCWriter.Create;
  710. try
  711. Params := Writer.CreateParams;
  712. try
  713. for i := Low(AArgs) to High(AArgs) do
  714. with AArgs[i] do
  715. case VType of
  716. vtInteger: Writer.AddParam(Params, Writer.CreateIntValue(VInteger));
  717. vtBoolean: Writer.AddParam(Params, Writer.CreateBooleanValue(VBoolean));
  718. vtChar: Writer.AddParam(Params, Writer.CreateStringValue(VChar));
  719. vtExtended: Writer.AddParam(Params, Writer.CreateDoubleValue(VExtended^));
  720. vtString: Writer.AddParam(Params, Writer.CreateStringValue(VString^));
  721. vtPChar: Writer.AddParam(Params, Writer.CreateStringValue(VPChar));
  722. } {$IFDEF HasWideStrings}
  723. { vtWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VWideChar));
  724. vtPWideChar: Writer.AddParam(Params, Writer.CreateStringValue(VPWideChar));
  725. } {$ENDIF}
  726. { vtAnsiString: Writer.AddParam(Params, Writer.CreateStringValue(String(VAnsiString)));
  727. // vtCurrency: ?
  728. // vtVariant: ?
  729. } {$IFDEF HasWideStrings}
  730. { vtWideString: Writer.AddParam(Params, Writer.CreateStringValue(WideString(VWideString)));
  731. } {$ENDIF}
  732. { vtInt64: Writer.AddParam(Params, Writer.CreateIntValue(VInt64^));
  733. else
  734. raise Exception.Create('Unsupported data type in RPC argument list');
  735. end;
  736. Writer.WriteMethodCall(AProcName, Params);
  737. RequestStream := Writer.MakeStream;
  738. except
  739. Params.Free;
  740. end;
  741. finally
  742. Writer.Free;
  743. end;
  744. end;
  745. procedure TXMLRPCClient.ProcessAnswer;
  746. var
  747. Parser: TXMLRPCParser;
  748. begin
  749. ResponseStream.Position := 0;
  750. Parser := TXMLRPCParser.Create(ResponseStream);
  751. FreeAndNil(ResponseStream);
  752. try
  753. case Parser.GetPostType of
  754. xmlrpcFaultResponse:
  755. } {raise Exception.Create(Format('%d - %s', [Parser.GetNextInt,
  756. Parser.GetNextString]));}
  757. { raise Exception.Create('Fehler bei XML-RPC-Befehlsausführung');
  758. xmlrpcResponse:
  759. if Assigned(CurCallback) then
  760. CurCallback(Parser);
  761. else
  762. raise Exception.Create('Invalid response');
  763. end;
  764. finally
  765. Parser.Free;
  766. if Assigned(OnEndRPC) then
  767. OnEndRPC(Self);
  768. end;
  769. end;
  770. procedure TXMLRPCClient.StreamSent(Sender: TObject);
  771. begin
  772. // LocalEventLoop.Break;
  773. Connection.Receive;
  774. end;
  775. procedure TXMLRPCClient.DataAvailable(Sender: TObject);
  776. begin
  777. LocalEventLoop.Break;
  778. end;
  779. }
  780. // XML-RPC Server
  781. procedure TXMLRPCServlet.DoPost(Req: THttpServletRequest;
  782. Resp: THttpServletResponse);
  783. var
  784. Parser: TXMLRPCParser;
  785. Writer: TXMLRPCWriter;
  786. Path: TStringList;
  787. LastDot, i: Integer;
  788. s, PathStr: String;
  789. AnswerStream: TStream;
  790. begin
  791. Parser := TXMLRPCParser.Create(Req.InputStream);
  792. try
  793. if Parser.GetPostType <> xmlrpcMethodCall then
  794. exit;
  795. Resp.ContentType := 'text/xml';
  796. Writer := TXMLRPCWriter.Create;
  797. try
  798. try
  799. // ...Header auswerten und zum Dispatcher springen...
  800. PathStr := Parser.GetMethodName + '.';
  801. Path := TStringList.Create;
  802. try
  803. LastDot := 1;
  804. for i := 1 to Length(PathStr) do
  805. if PathStr[i] = '.' then
  806. begin
  807. Path.Add(UpperCase(Copy(PathStr, LastDot, i - LastDot)));
  808. LastDot := i + 1;
  809. end;
  810. Dispatch(Parser, Writer, Path);
  811. finally
  812. Path.Free;
  813. end;
  814. except
  815. on e: Exception do
  816. begin
  817. if Assigned(OnException) then
  818. OnException(e);
  819. Writer.WriteFaultResponse(2,
  820. 'Execution error: ' + e.ClassName + ': ' + e.Message);
  821. end;
  822. end;
  823. AnswerStream := Writer.MakeStream;
  824. try
  825. Resp.ContentLength := AnswerStream.Size;
  826. Resp.OutputStream.CopyFrom(AnswerStream, AnswerStream.Size);
  827. finally
  828. AnswerStream.Free;
  829. end;
  830. finally
  831. Writer.Free;
  832. end;
  833. finally
  834. Parser.Free;
  835. end;
  836. end;
  837. end.
  838. {
  839. $Log$
  840. Revision 1.5 2004-02-02 17:12:01 sg
  841. * Some small fixes to get the code at least compiling again; the HTTP
  842. client class is not expected to work at the moment, and the XML-RPC
  843. client has been fully disabled for now.
  844. Revision 1.4 2003/11/27 11:28:44 sg
  845. * Debugging output is now enabled when the symbol "XMLRPCDebug" exists,
  846. and not generally when compiled in debug mode
  847. Revision 1.3 2003/11/22 12:10:27 sg
  848. * Just a small adaption to chages in HTTP unit
  849. Revision 1.2 2003/06/25 08:49:21 sg
  850. * Added OnException event to TXMLRPCServlet
  851. Revision 1.1 2002/04/25 19:30:29 sg
  852. * First version (with exception of the HTTP unit: This is an improved version
  853. of the old asyncio HTTP unit, now adapted to fpAsync)
  854. }