IdWebDAV.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. unit IdWebDAV;
  17. //implements http://www.faqs.org/rfcs/rfc2518.html
  18. {
  19. general cleanup possibilities:
  20. todo change embedded strings to consts
  21. todo change depth param from infinity to -1? also string>integer?
  22. }
  23. interface
  24. {$i IdCompilerDefines.inc}
  25. uses
  26. Classes,
  27. IdHTTP;
  28. const
  29. Id_HTTPMethodPropFind = 'PROPFIND'; {do not localize}
  30. Id_HTTPMethodPropPatch = 'PROPPATCH'; {do not localize}
  31. Id_HTTPMethodOrderPatch = 'ORDERPATCH'; {do not localize}
  32. Id_HTTPMethodSearch = 'SEARCH'; {do not localize}
  33. Id_HTTPMethodMKCol = 'MKCOL'; {do not localize}
  34. Id_HTTPMethodMove = 'MOVE'; {do not localize}
  35. Id_HTTPMethodCopy = 'COPY'; {do not localize}
  36. Id_HTTPMethodCheckIn = 'CHECKIN'; {do not localize}
  37. Id_HTTPMethodCheckOut = 'CHECKOUT'; {do not localize}
  38. Id_HTTPMethodUnCheckOut = 'UNCHECKOUT'; {do not localize}
  39. Id_HTTPMethodLock = 'LOCK'; {do not localize}
  40. Id_HTTPMethodUnLock = 'UNLOCK'; {do not localize}
  41. Id_HTTPMethodReport = 'REPORT'; {do not localize}
  42. Id_HTTPMethodVersion = 'VERSION-CONTROL'; {do not localize}
  43. Id_HTTPMethodLabel = 'LABEL'; {do not localize}
  44. Id_HTTPMethodMakeCol = 'MKCOL'; {Do not localize}
  45. const
  46. //casing is according to rfc
  47. cTimeoutInfinite = 'Infinite'; {do not localize}
  48. cDepthInfinity = 'infinity'; {do not localize}
  49. type
  50. TIdWebDAV = class(TIdHTTP)
  51. public
  52. procedure DAVCheckIn(const AURL, AComment: string);
  53. procedure DAVCheckOut(const AURL: string; const AXMLQuery: TStream; const AComment: string);
  54. procedure DAVCopy(const AURL, DURL: string; const AResponseContent: TStream; const AOverWrite: boolean = True; const ADepth: string = cDepthInfinity);
  55. procedure DAVDelete(const AURL: string; const ALockToken: string);
  56. procedure DAVLabel(const AURL: string; const AXMLQuery: TStream);
  57. procedure DAVLock(const AURL: string; const AXMLQuery, AResponseContent: TStream; const ALockToken, ATags: string; const ATimeOut: string = cTimeoutInfinite; const AMustExist: Boolean = False; const ADepth: string = '0'); {do not localize}
  58. procedure DAVMove(const AURL, DURL: string; const AResponseContent: TStream; const AOverWrite: Boolean = True; const ADepth: string = cDepthInfinity);
  59. procedure DAVOrderPatch(const AURL: string; const AXMLQuery: TStream);
  60. procedure DAVPropFind(const AURL: string; const AXMLQuery, AResponseContent: TStream; const ADepth: string = '0'; const ARangeFrom: Integer = -1; const ARangeTo: Integer = -1); {do not localize}
  61. procedure DAVPropPatch(const AURL: string; const AXMLQuery, AResponseContent: TStream; const ADepth: string = '0'); {do not localize}
  62. procedure DAVPut(const AURL: string; const ASource: TStream; const ALockToken: String);
  63. procedure DAVReport(const AURL: string; const AXMLQuery, AResponseContent: TStream);
  64. procedure DAVSearch(const AURL: string; const ARangeFrom, ARangeTo: Integer; const AXMLQuery, AResponseContent: TStream; const ADepth: string = '0'); {do not localize}
  65. procedure DAVUnCheckOut(const AURL: String);
  66. procedure DAVUnLock(const AURL: string; const ALockToken: string);
  67. procedure DAVVersionControl(const AURL: string);
  68. procedure DAVMakeCollection(const AURL: string);
  69. end;
  70. implementation
  71. uses
  72. IdGlobal, SysUtils;
  73. procedure TIdWebDAV.DAVPropPatch(const AURL: string; const AXMLQuery, AResponseContent: TStream;
  74. const ADepth: string);
  75. begin
  76. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  77. try
  78. DoRequest(Id_HTTPMethodPropPatch, AURL, AXMLQuery, AResponseContent, []);
  79. finally
  80. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  81. end;
  82. end;
  83. procedure TIdWebDAV.DAVPropFind(const AURL: string; const AXMLQuery, AResponseContent: TStream;
  84. const ADepth: string; const ARangeFrom: Integer; const ARangeTo: Integer);
  85. begin
  86. if ARangeTo > -1 then begin
  87. Request.CustomHeaders.Values['Range'] := 'Rows=' + IntToStr(ARangeFrom) + '-' + IntToStr(ARangeTo); {do not localize}
  88. end else begin
  89. Request.CustomHeaders.Values['Range'] := ''; {do not localize}
  90. end;
  91. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  92. try
  93. DoRequest(Id_HTTPMethodPropfind, AURL, AXMLQuery, AResponseContent, []);
  94. finally
  95. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  96. if ARangeTo > -1 then begin
  97. Request.CustomHeaders.Values['Range'] := ''; {do not localize}
  98. end;
  99. end;
  100. end;
  101. procedure TIdWebDAV.DAVOrderPatch(const AURL: string; const AXMLQuery: TStream);
  102. begin
  103. DoRequest(Id_HTTPMethodOrderPatch, AURL, AXMLQuery, nil, []);
  104. end;
  105. procedure TIdWebDAV.DAVSearch(const AURL: string; const ARangeFrom, ARangeTo: Integer;
  106. const AXMLQuery, AResponseContent: TStream; const ADepth: string);
  107. begin
  108. if ARangeTo > -1 then begin
  109. Request.CustomHeaders.Values['Range'] := 'Rows=' + IntToStr(ARangeFrom) + '-' + IntToStr(ARangeTo); {do not localize}
  110. end else begin
  111. Request.CustomHeaders.Values['Range'] := ''; {do not localize}
  112. end;
  113. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  114. try
  115. DoRequest(Id_HTTPMethodSearch, AURL, AXMLQuery, AResponseContent, []);
  116. finally
  117. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  118. if ARangeTo > -1 then begin
  119. Request.CustomHeaders.Values['Range'] := ''; {do not localize}
  120. end;
  121. end;
  122. end;
  123. procedure TIdWebDAV.DAVMove(const AURL, DURL: string; const AResponseContent: TStream;
  124. const AOverWrite: Boolean; const ADepth: string);
  125. begin
  126. if not AOverWrite then begin
  127. Request.CustomHeaders.Values['Overwrite'] := 'F'; {do not localize}
  128. end else begin
  129. Request.CustomHeaders.Values['Overwrite'] := ''; {do not localize}
  130. end;
  131. Request.CustomHeaders.Values['Destination'] := DURL; {do not localize}
  132. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  133. try
  134. DoRequest(Id_HTTPMethodMove, AURL, nil, AResponseContent, []);
  135. finally
  136. Request.CustomHeaders.Values['Destination'] := ''; {do not localize}
  137. if not AOverWrite then begin
  138. Request.CustomHeaders.Values['Overwrite']; {do not localize}
  139. end;
  140. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  141. end;
  142. end;
  143. procedure TIdWebDAV.DAVCopy(const AURL, DURL: string; const AResponseContent: TStream;
  144. const AOverWrite: Boolean; const ADepth: string);
  145. begin
  146. Request.CustomHeaders.Values['Destination'] := DURL; {do not localize}
  147. Request.CustomHeaders.Values['Overwrite'] := iif(AOverWrite, 'T', 'F'); {do not localize}
  148. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  149. try
  150. DoRequest(Id_HTTPMethodCopy, AURL, nil, AResponseContent, []);
  151. finally
  152. Request.CustomHeaders.Values['Destination'] := ''; {do not localize}
  153. Request.CustomHeaders.Values['Overwrite'] := ''; {do not localize}
  154. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  155. end;
  156. end;
  157. procedure TIdWebDAV.DAVCheckIn(const AURL, AComment: string);
  158. var
  159. LXML: TMemoryStream;
  160. s: string;
  161. begin
  162. DoRequest(Id_HTTPMethodCheckIn, AURL, nil, nil, []);
  163. if AComment <> '' then
  164. begin
  165. s := '<?xml version="1.0" encoding="utf-8" ?>' + {do not localize}
  166. '<propertyupdate xmlns:D="DAV:"><set><prop>' + {do not localize}
  167. '<comment>' + AComment + '</comment></prop></set></propertyupdate>'; {do not localize}
  168. LXML := TMemoryStream.Create;
  169. try
  170. WriteStringToStream(LXML, s, IndyTextEncoding_UTF8);
  171. LXML.Position := 0;
  172. DoRequest(Id_HTTPMethodPropPatch, AURL, LXML, nil, []);
  173. finally
  174. LXML.Free;
  175. end;
  176. end;
  177. end;
  178. procedure TIdWebDAV.DAVCheckOut(const AURL: String; const AXMLQuery: TStream; const AComment: String);
  179. var
  180. LXML: TMemoryStream;
  181. s: string;
  182. begin
  183. DoRequest(Id_HTTPMethodCheckOut, AURL, AXMLQuery, nil, []);
  184. if AComment <> '' then
  185. begin
  186. s := '<?xml version="1.0" encoding="utf-8" ?>' + {do not localize}
  187. '<propertyupdate xmlns:D="DAV:"><set><prop>' + {do not localize}
  188. '<comment>' + AComment + '</comment></prop></set></propertyupdate>'; {do not localize}
  189. LXML := TMemoryStream.Create;
  190. try
  191. WriteStringToStream(LXML, s, IndyTextEncoding_UTF8);
  192. LXML.Position := 0;
  193. DoRequest(Id_HTTPMethodPropPatch, AURL, LXML, nil, []);
  194. finally
  195. LXML.Free;
  196. end;
  197. end;
  198. end;
  199. procedure TIdWebDAV.DAVUnCheckOut(const AURL: string);
  200. begin
  201. DoRequest(Id_HTTPMethodUnCheckOut, AURL, nil, nil, []);
  202. end;
  203. procedure TIdWebDAV.DAVLock(const AURL: string; const AXMLQuery, AResponseContent: TStream;
  204. const ALockToken, ATags: string; const ATimeOut: string; const AMustExist: Boolean;
  205. const ADepth: string);
  206. begin
  207. //NOTE - do not specify a LockToken and Tags value. If both exist then only
  208. //LockToken will be used. If you wish to use LockToken together with other
  209. //tags then concatenate and send via Tags value.
  210. //Also note that specifying the lock token in a lock request facilitates
  211. //a lock refresh
  212. Request.CustomHeaders.Values['Timeout'] := ATimeOut; {do not localize}
  213. if AMustExist then
  214. begin
  215. Request.CustomHeaders.Values['If-Match'] := '*'; {do not localize}
  216. Request.CustomHeaders.Values['If-None-Match'] := ''; {do not localize}
  217. end else
  218. begin
  219. Request.CustomHeaders.Values['If-Match'] := ''; {do not localize}
  220. Request.CustomHeaders.Values['If-None-Match'] := '*'; {do not localize}
  221. end;
  222. Request.CustomHeaders.Values['Depth'] := ADepth; {do not localize}
  223. if ALockToken <> '' then begin
  224. Request.CustomHeaders.Values['If'] := '(<'+ALockToken+'>)'; {do not localize}
  225. end
  226. else if ATags <> '' then begin
  227. Request.CustomHeaders.Values['If'] := '('+ATags+')'; {do not localize}
  228. end else begin
  229. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  230. end;
  231. try
  232. DoRequest(Id_HTTPMethodLock, AURL, AXMLQuery, AResponseContent, []);
  233. finally
  234. Request.CustomHeaders.Values['Timeout'] := ''; {do not localize}
  235. Request.CustomHeaders.Values['If-Match'] := ''; {do not localize}
  236. Request.CustomHeaders.Values['If-None-Match'] := ''; {do not localize}
  237. Request.CustomHeaders.Values['Depth'] := ''; {do not localize}
  238. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  239. end;
  240. end;
  241. procedure TIdWebDAV.DAVUnLock(const AURL: string; const ALockToken: string);
  242. begin
  243. Request.CustomHeaders.Values['Lock-Token'] := '<'+ALockToken+'>'; {do not localize}
  244. try
  245. DoRequest(Id_HTTPMethodUnLock, AURL, nil, nil, []);
  246. finally
  247. Request.CustomHeaders.Values['Lock-Token'] := ''; {do not localize}
  248. end;
  249. end;
  250. procedure TIdWebDAV.DAVReport(const AURL: string; const AXMLQuery, AResponseContent: TStream);
  251. begin
  252. DoRequest(Id_HTTPMethodReport, AURL, AXMLQuery, AResponseContent, []);
  253. end;
  254. procedure TIdWebDAV.DAVVersionControl(const AURL: string);
  255. begin
  256. DoRequest(Id_HTTPMethodVersion, AURL, nil, nil, []);
  257. end;
  258. procedure TIdWebDAV.DAVLabel(const AURL: string; const AXMLQuery: TStream);
  259. begin
  260. DoRequest(Id_HTTPMethodLabel, AURL, AXMLQuery, nil, []);
  261. end;
  262. procedure TIdWebDAV.DAVPut(const AURL: string; const ASource: TStream; const ALockToken: String);
  263. begin
  264. if ALockToken <> '' then begin
  265. Request.CustomHeaders.Values['If'] := '(<'+ALockToken+'>)'; {do not localize}
  266. end else begin
  267. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  268. end;
  269. try
  270. inherited Put(AURL, ASource, TStream(nil));
  271. finally
  272. if ALockToken <> '' then begin
  273. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  274. end;
  275. end;
  276. end;
  277. procedure TIdWebDAV.DAVDelete(const AURL: string; const ALockToken: string);
  278. begin
  279. if ALockToken <> '' then begin
  280. Request.CustomHeaders.Values['If'] := '(<'+ALockToken+'>)'; {do not localize}
  281. end else begin
  282. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  283. end;
  284. try
  285. inherited Delete(AURL);
  286. finally
  287. if ALockToken <> '' then begin
  288. Request.CustomHeaders.Values['If'] := ''; {do not localize}
  289. end;
  290. end;
  291. end;
  292. procedure TIdWebDAV.DAVMakeCollection(const AURL: string);
  293. begin
  294. DoRequest(Id_HTTPMethodMakeCol, AURL, nil, nil, []);
  295. end;
  296. end.