Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

349 lines
7.3 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // L O C K M E T A . C P P
  4. //
  5. // HTTP 1.1/DAV 1.0 request handling via ISAPI
  6. //
  7. //
  8. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  9. //
  10. #include <_davprs.h>
  11. #include <tchar.h> //_strspnp
  12. #include <gencache.h>
  13. #include <sz.h>
  14. #include <xemit.h>
  15. #include <xlock.h>
  16. #include <statetok.h>
  17. #include <nonimpl.h>
  18. // LockDiscovery -------------------------------------------------------------
  19. //
  20. SCODE
  21. ScAddInLockToken (CEmitterNode& en, LPCWSTR pwszLockToken)
  22. {
  23. // Outer nodes must be declared first
  24. //
  25. CEmitterNode enLToken;
  26. CEmitterNode enToken;
  27. SCODE sc = S_OK;
  28. WCHAR rgwsz[MAX_LOCKTOKEN_LENGTH];
  29. LPCWSTR pwsz;
  30. // Make sure they give us a locktoken string.
  31. //
  32. Assert(pwszLockToken);
  33. // AND remove the quote marks (currently <>)
  34. //
  35. if (L'<' == pwszLockToken[0])
  36. pwszLockToken++;
  37. pwsz = wcschr(pwszLockToken, L'>');
  38. if (pwsz)
  39. {
  40. UINT cch = static_cast<UINT>(pwsz - pwszLockToken);
  41. if (MAX_LOCKTOKEN_LENGTH - 1 < cch)
  42. {
  43. sc = E_FAIL;
  44. goto ret;
  45. }
  46. Assert(MAX_LOCKTOKEN_LENGTH > cch);
  47. memcpy(rgwsz, pwszLockToken, cch * sizeof(WCHAR));
  48. rgwsz[cch] = L'\0';
  49. pwszLockToken = rgwsz;
  50. }
  51. // Create and add a locktoken node under activelock.
  52. // (locktoken node contains a single href node.)
  53. //
  54. sc = en.ScAddNode (gc_wszLockToken, enLToken);
  55. if (FAILED (sc))
  56. goto ret;
  57. sc = enLToken.ScAddNode (gc_wszXML__Href, enToken, pwszLockToken);
  58. if (FAILED (sc))
  59. goto ret;
  60. ret:
  61. return sc;
  62. }
  63. // ========================================================================
  64. //
  65. // ScBuildLockDiscovery
  66. //
  67. // Takes an emitter and an already-constructed lockdiscovery node,
  68. // and adds an activelock node under it.
  69. // May be called multiple times -- each call will add a new activelock
  70. // node under the lockdiscovery node in en.
  71. //
  72. SCODE
  73. ScBuildLockDiscovery (CXMLEmitter& emitter,
  74. CEmitterNode& en,
  75. LPCWSTR pwszLockToken,
  76. LPCWSTR pwszLockType,
  77. LPCWSTR pwszLockScope,
  78. BOOL fRollback,
  79. BOOL fDepthInfinity,
  80. DWORD dwTimeout,
  81. LPCWSTR pwszOwnerComment,
  82. LPCWSTR pwszSubType)
  83. {
  84. CEmitterNode enActive;
  85. SCODE sc = S_OK;
  86. WCHAR wsz[50];
  87. // Zero is an invalid timeout.
  88. //
  89. Assert(dwTimeout);
  90. // Add in the 'DAV:activelock' node
  91. //
  92. sc = en.ScAddNode (gc_wszLockActive, enActive);
  93. if (FAILED (sc))
  94. goto ret;
  95. // Create a node for the locktype.
  96. //
  97. {
  98. CEmitterNode enLType;
  99. sc = enActive.ScAddNode (gc_wszLockType, enLType);
  100. if (FAILED (sc))
  101. goto ret;
  102. {
  103. CEmitterNode enType;
  104. sc = enLType.ScAddNode (pwszLockType, enType);
  105. if (FAILED (sc))
  106. goto ret;
  107. if (pwszSubType)
  108. {
  109. CEmitterNode enSubLType;
  110. sc = enType.ScAddNode (pwszSubType, enSubLType);
  111. if (FAILED (sc))
  112. goto ret;
  113. }
  114. }
  115. }
  116. // Create a node for the lockscope
  117. //
  118. {
  119. CEmitterNode enLScope;
  120. sc = enActive.ScAddNode (gc_wszLockScope, enLScope);
  121. if (FAILED (sc))
  122. goto ret;
  123. {
  124. CEmitterNode enScope;
  125. sc = enLScope.ScAddNode (pwszLockScope, enScope);
  126. if (FAILED (sc))
  127. goto ret;
  128. }
  129. }
  130. // Create a node for the owner. The comment is well contructed XML already
  131. //
  132. if (pwszOwnerComment)
  133. {
  134. sc = enActive.Pxn()->ScSetFormatedXML (pwszOwnerComment, static_cast<UINT>(wcslen(pwszOwnerComment)));
  135. if (FAILED (sc))
  136. goto ret;
  137. }
  138. // If this is a rollback lock...
  139. //
  140. if (fRollback)
  141. {
  142. CEmitterNode enRollback;
  143. sc = enActive.ScAddNode (gc_wszLockRollback, enRollback);
  144. if (FAILED (sc))
  145. goto ret;
  146. }
  147. // Add in the lock token
  148. //
  149. sc = ScAddInLockToken (enActive, pwszLockToken);
  150. if (FAILED (sc))
  151. goto ret;
  152. // Add an appropriate depth node.
  153. //
  154. {
  155. CEmitterNode enDepth;
  156. if (fDepthInfinity)
  157. {
  158. sc = enActive.ScAddNode (gc_wszLockDepth, enDepth, gc_wszInfinity);
  159. if (FAILED (sc))
  160. goto ret;
  161. }
  162. else
  163. {
  164. sc = enActive.ScAddNode (gc_wszLockDepth, enDepth, gc_wsz0);
  165. if (FAILED (sc))
  166. goto ret;
  167. }
  168. }
  169. // Finally, create and add a timeout node
  170. //
  171. {
  172. CEmitterNode enTimeout;
  173. wsprintfW (wsz, L"Second-%d", dwTimeout);
  174. sc = enActive.ScAddNode (gc_wszLockTimeout, enTimeout, wsz);
  175. if (FAILED (sc))
  176. goto ret;
  177. }
  178. ret:
  179. return sc;
  180. }
  181. // ========================================================================
  182. //
  183. // Lock utility functions
  184. //
  185. //$REVIEW: This should really be common impl code. Move to _davcom later.
  186. //
  187. // ------------------------------------------------------------------------
  188. //
  189. // FGetLockTimeout
  190. //
  191. // Fetches and parses an incoming Time-Out header on the request.
  192. // Returns FALSE if an invalid option was encountered.
  193. // Returns TRUE with *pdwSeconds=gc_cSecondsDefaultLock
  194. // if NO Time-Out header was present.
  195. //
  196. BOOL
  197. FGetLockTimeout (LPMETHUTIL pmu, DWORD * pdwSeconds, DWORD dwMaxOverride)
  198. {
  199. LPCWSTR pwsz;
  200. DWORD dwMax = gc_cSecondsMaxLock;
  201. Assert (pmu);
  202. Assert (pdwSeconds);
  203. *pdwSeconds = gc_cSecondsDefaultLock;
  204. // If there is NO Time-Out header, leave our timeout set to the default,
  205. // which was set at construction time.
  206. // NOTE: It IS valid to have NO Time-Out header. Just use the defaults.
  207. //
  208. pwsz = pmu->LpwszGetRequestHeader (gc_szTimeout, FALSE);
  209. if (!pwsz)
  210. {
  211. LockTrace ("Dav: No Timeout header found.\n");
  212. goto ret;
  213. }
  214. // Skip any initial whitespace.
  215. //
  216. pwsz = _wcsspnp(pwsz, gc_wszLWS);
  217. if (!pwsz)
  218. {
  219. LockTrace ("Dav: No params found in LOCK Time-Out header.\n");
  220. return FALSE;
  221. }
  222. Assert(pwsz);
  223. // Check for a new-style timeout header.
  224. //
  225. // Load a header iterator -- there could be multiple values here.
  226. //
  227. {
  228. HDRITER_W hdr(pwsz);
  229. pwsz = hdr.PszNext();
  230. if (!pwsz)
  231. {
  232. // No data found. That's an error.
  233. //
  234. return FALSE;
  235. }
  236. if (dwMaxOverride)
  237. dwMax = dwMaxOverride;
  238. while (pwsz)
  239. {
  240. // Loop until we find an acceptable time.
  241. // (Ignore any header values we don't understand.)
  242. // If no acceptable time is found, it's okay.
  243. // dwSeconds stays zero, and return TRUE.
  244. //
  245. if (!_wcsnicmp (gc_wszSecondDash, pwsz, gc_cchSecondDash))
  246. {
  247. DWORD dwSeconds;
  248. pwsz += gc_cchSecondDash;
  249. if (!*pwsz)
  250. return FALSE;
  251. dwSeconds = _wtol(pwsz);
  252. if (dwSeconds > dwMax)
  253. {
  254. // Remember that they asked for something huge.
  255. //
  256. *pdwSeconds = dwMax;
  257. }
  258. else
  259. {
  260. // We found a request that we'll grant.
  261. // Set it and stop looping.
  262. //
  263. *pdwSeconds = dwSeconds;
  264. break;
  265. }
  266. }
  267. else if (!_wcsnicmp (gc_wszInfinite, pwsz, gc_cchInfinite))
  268. {
  269. // We don't yet handle infinite timeouts.
  270. // Remember that they asked for something huge.
  271. // Skip to the next token.
  272. //
  273. *pdwSeconds = dwMax;
  274. }
  275. // else skip to next token
  276. // (ignore unrecognized tokens).
  277. //
  278. pwsz = hdr.PszNext();
  279. } // elihw
  280. }
  281. ret:
  282. //$HACK:ROSEBUD_OFFICE9_TIMEOUT_HACK
  283. // For the bug where rosebud waits until the last second
  284. // before issueing the refresh. Need to filter out this check with
  285. // the user agent string. The hack is to increase the timeout
  286. // by 30 seconds and return the actual timeout.
  287. //
  288. if (pmu->FIsOffice9Request())
  289. {
  290. *pdwSeconds += gc_dwSecondsHackTimeoutForRosebud;
  291. }
  292. //$HACK:END:ROSEBUD_OFFICE9_TIMEOUT_HACK
  293. return TRUE;
  294. }