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.

273 lines
8.7 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // INSTDATA.CPP
  4. //
  5. // HTTP instance data cache implementation.
  6. //
  7. //
  8. // Copyright 1997 Microsoft Corporation, All Rights Reserved
  9. //
  10. #include "_davprs.h"
  11. #include <buffer.h>
  12. #include "instdata.h"
  13. // ========================================================================
  14. //
  15. // class CInstData
  16. //
  17. // ------------------------------------------------------------------------
  18. //
  19. // CInstData::CInstData()
  20. //
  21. // Constructor. Init all variables. Make a copy of the name string
  22. // for us to keep.
  23. //
  24. // NOTE: This object must be constructed while we are REVERTED.
  25. //
  26. CInstData::CInstData( LPCWSTR pwszName )
  27. {
  28. // Make copy of wide instance name
  29. //
  30. m_wszVRoot = WszDupWsz(pwszName);
  31. // Parse out and store service instance, otherwise
  32. // sometimes referred as the server ID.
  33. //
  34. m_lServerID = LInstFromVroot( m_wszVRoot );
  35. // Create our objects. Please read the notes about the
  36. // relative costs and reasons behind creating these objects
  37. // now rather than on demand. Don't create anything here that
  38. // can be created on demand unless at least one of the
  39. // following is true:
  40. //
  41. // 1. The object is lightweight and cheap to create.
  42. // Example: an empty cache.
  43. //
  44. // 2. The object is used in the processing of a vast
  45. // majority of HTTP requests.
  46. // Example: any object used on every GET request.
  47. //
  48. }
  49. // ========================================================================
  50. //
  51. // class CInstDataCache
  52. //
  53. // ------------------------------------------------------------------------
  54. //
  55. // CInstDataCache::GetInstData()
  56. //
  57. // Fetch a row from the cache.
  58. //
  59. CInstData& CInstDataCache::GetInstData( const IEcb& ecb )
  60. {
  61. auto_ref_ptr<CInstData> pinst;
  62. CStackBuffer<WCHAR> pwszMetaPath;
  63. UINT cchMetaPath;
  64. CStackBuffer<WCHAR> pwszVRoot;
  65. UINT cchVRoot;
  66. LPCWSTR pwszRootName;
  67. UINT cchRootName;
  68. // Build up a unique string from the vroot and instance:
  69. // lm/w3svc/<site id>/root/<vroot name>
  70. //
  71. // Get the virtual root from the ecb (/<vroot name>).
  72. //
  73. cchRootName = ecb.CchGetVirtualRootW( &pwszRootName );
  74. // pwszRootName should still be NULL-terminated. Check it, 'cause
  75. // we're going to put the next string after there, and we don't want
  76. // to get them mixed...
  77. //
  78. Assert( pwszRootName );
  79. Assert( L'\0' == pwszRootName[cchRootName] );
  80. // Ask IIS for the metabase prefix (lm/w3svc/<site id>) for the
  81. // virtual server (site) we're on...
  82. //
  83. cchMetaPath = pwszMetaPath.celems();
  84. if (!ecb.FGetServerVariable( "INSTANCE_META_PATH",
  85. pwszMetaPath.get(),
  86. reinterpret_cast<DWORD *>(&cchMetaPath) ))
  87. {
  88. if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
  89. {
  90. DebugTrace( "CInstDataCache::GetInstData() - FGetServerVariable() failed"
  91. " to get INSTANCE_META_PATH\n" );
  92. throw CLastErrorException();
  93. }
  94. if (NULL == pwszMetaPath.resize(cchMetaPath * sizeof(WCHAR)))
  95. {
  96. SetLastError(E_OUTOFMEMORY);
  97. DebugTrace( "CInstDataCache::GetInstData() - failed to allocate memory\n" );
  98. throw CLastErrorException();
  99. }
  100. if (!ecb.FGetServerVariable( "INSTANCE_META_PATH",
  101. pwszMetaPath.get(),
  102. reinterpret_cast<DWORD *>(&cchMetaPath) ))
  103. {
  104. DebugTrace( "CInstDataCache::GetInstData() - FGetServerVariable() failed"
  105. " to get INSTANCE_META_PATH\n" );
  106. throw CLastErrorException();
  107. }
  108. }
  109. // The function returning server variable returns total number of characters
  110. // written to the output buffer, so it will include '\0' termination. Let us make
  111. // sure that the return is what is expected.
  112. //
  113. Assert(0 == cchMetaPath ||
  114. L'\0' == pwszMetaPath[cchMetaPath - 1]);
  115. // Adjust the cchMetaPath to reflect the actual character count
  116. //
  117. if (0 != cchMetaPath)
  118. {
  119. cchMetaPath--;
  120. }
  121. // Check that the root name is either NULL (zero-length string)
  122. // or has its own separator.
  123. //
  124. // NOTE: This is conditional because IF we are installed at the ROOT
  125. // (on w3svc/1 or w3svc/1/root) and you throw a method against
  126. // a file that doesn't live under a registered K2 vroot
  127. // (like /default.asp) -- we DO get called, but the mi.cchMatchingURL
  128. // comes back as 0, so pwszRootName is a zero-len string.
  129. // (In IIS terms, you are not really hitting a virtual root,
  130. // so your vroot is "".)
  131. // I'm making this assert CONDITIONAL until we figure out more about
  132. // how we'll handle this particular install case.
  133. //$REVIEW: The installed-at-the-root case needs to be examined more
  134. //$REVIEW: becuase we DON'T always build the same instance string
  135. //$REVIEW: in that case -- we'll still get vroot strings when the URI
  136. //$REVIEW: hits a resource under a REGISTERED vroot, and so we'll
  137. //$REVIEW: build different strings for the different vroots, even though
  138. //$REVIEW: we are running from a single, global install of DAV.
  139. //$REVIEW: The name might need to be treated as a starting point for a lookup.
  140. // NTBug #168188: On OPTIONS, "*" is a valid URI. Need to handle this
  141. // special case without asserting.
  142. //
  143. AssertSz( (L'*' == pwszRootName[0] && 1 == cchRootName) ||
  144. (0 == cchRootName) ||
  145. (L'/' == pwszRootName[0]),
  146. "(Non-zero) VRoot name doesn't have expected slash delimiter. Instance name string may be malformed!" );
  147. // NTBug # 168188: Special case for OPTIONS * -- map us to the root
  148. // instdata name of "/w3svc/#/root" (don't want an instdata named
  149. // "/w3svc/#/root*" that noone else can ever use!).
  150. //
  151. cchVRoot = pwszVRoot.celems();
  152. if (cchVRoot < cchMetaPath + gc_cch_Root + cchRootName + 1)
  153. {
  154. cchVRoot = cchMetaPath + gc_cch_Root + cchRootName;
  155. if (NULL == pwszVRoot.resize(CbSizeWsz(cchVRoot)))
  156. {
  157. SetLastError(E_OUTOFMEMORY);
  158. DebugTrace( "CInstDataCache::GetInstData() - failed to allocate memory\n" );
  159. throw CLastErrorException();
  160. }
  161. }
  162. // Copy first 2 portions: 'lm/w3svc/<site id>' and '/root'
  163. //
  164. memcpy(pwszVRoot.get(), pwszMetaPath.get(), cchMetaPath * sizeof(WCHAR));
  165. memcpy(pwszVRoot.get() + cchMetaPath, gc_wsz_Root, gc_cch_Root * sizeof(WCHAR));
  166. // Copy remaining 3-rd portion: '/<vroot name>' and terminate the string.
  167. // NTBug # 168188: Special case for OPTIONS * -- map us to the root
  168. // instdata name of "/w3svc/#/root" (don't want an instdata named
  169. // "/w3svc/#/root*" that noone else can ever use!).
  170. //
  171. if (L'*' == pwszRootName[0] && 1 == cchRootName)
  172. {
  173. (pwszVRoot.get())[cchMetaPath + gc_cch_Root] = L'\0';
  174. }
  175. else
  176. {
  177. memcpy(pwszVRoot.get() + cchMetaPath + gc_cch_Root, pwszRootName, cchRootName * sizeof(WCHAR));
  178. (pwszVRoot.get())[cchMetaPath + gc_cch_Root + cchRootName] = L'\0';
  179. }
  180. // Slam the string to lower-case so that all variations on the vroot
  181. // name will match. (IIS doesn't allow vroots with the same name --
  182. // and "VRoot" and "vroot" count as the same!)
  183. //
  184. _wcslwr( pwszVRoot.get() );
  185. // Demand load the instance data for this vroot
  186. //
  187. {
  188. CRCWsz crcwszVRoot( pwszVRoot.get() );
  189. while ( !Instance().m_cache.FFetch( crcwszVRoot, &pinst ) )
  190. {
  191. CInitGate ig( L"DAV/CInstDataCache::GetInstData/", pwszVRoot.get() );
  192. if ( ig.FInit() )
  193. {
  194. // Setup instance data from the system security context,
  195. // not the client's security context.
  196. //
  197. safe_revert sr(ecb.HitUser());
  198. pinst = new CInstData(pwszVRoot.get());
  199. // Since we are going to use this crcsz as a key in a cache,
  200. // need to make sure that it's built on a name string that
  201. // WON'T EVER MOVE (go away, get realloc'd). The stack-based one
  202. // above just isn't good enough. SO, build a new little CRC-dude
  203. // on the UNMOVABLE name data in the inst object.
  204. // (And check that this new crc matches the old one!)
  205. //
  206. CRCWsz crcwszAdd( pinst->GetNameW() );
  207. AssertSz( crcwszVRoot.isequal(crcwszAdd),
  208. "Two CRC's from the same string don't match!" );
  209. Instance().m_cache.Add( crcwszAdd, pinst );
  210. // Log the fact that we've got a new instance pluged in.
  211. // Message DAVPRS_VROOT_ATTACH takes two parameters:
  212. // the signature of the impl and the vroot.
  213. //
  214. //$ RAID:NT:283650: Logging each attach causes a large
  215. // number of events to be registered. We really should
  216. // only Log one-time-startup/failure events.
  217. //
  218. #undef LOG_STARTUP_EVENT
  219. #ifdef LOG_STARTUP_EVENT
  220. {
  221. LPCWSTR pwszStrings[2];
  222. pwszStrings[0] = gc_wszSignature;
  223. pwszStrings[1] = pwszVRoot.get();
  224. LogEventW(DAVPRS_VROOT_ATTACH,
  225. EVENTLOG_INFORMATION_TYPE,
  226. 2,
  227. pwszStrings,
  228. 0,
  229. NULL );
  230. }
  231. #endif // LOG_STARTUP_EVENT
  232. //
  233. //$ RAID:X5:283650: end.
  234. break;
  235. }
  236. }
  237. }
  238. return *pinst;
  239. }