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.

1275 lines
37 KiB

  1. #ifndef _DAVIMPL_H_
  2. #define _DAVIMPL_H_
  3. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4. //
  5. // DAVIMPL.H
  6. //
  7. // Header for DAV implementation methods interface
  8. //
  9. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  10. //
  11. #include <objbase.h> // For common C/C++ interface macros
  12. #include <httpext.h>
  13. #include <ex\oldhack.h> // This file is so that we build as there are some definitions in old headers that are not in new. Will go away.
  14. #include <autoptr.h> // For CMTRefCounted base class
  15. #include <ecb.h>
  16. #include <request.h>
  17. #include <response.h>
  18. #include <sgstruct.h>
  19. #include <vrenum.h>
  20. #include <davsc.h>
  21. #include <body.h> // For async stream interfaces, CRefHandle, etc.
  22. #include <sz.h>
  23. #include <ex\calcom.h>
  24. #include <url.h>
  25. #include <ex\xml.h>
  26. // Resource types ------------------------------------------------------------
  27. //
  28. typedef enum {
  29. RT_NULL = 0,
  30. RT_DOCUMENT,
  31. RT_STRUCTURED_DOCUMENT,
  32. RT_COLLECTION
  33. } RESOURCE_TYPE;
  34. enum { MAX_VERSION_LEN = 20*4 };
  35. // Access control scope ------------------------------------------------------
  36. //
  37. // The acl scope is used when asking the metabase for the IIS access applied
  38. // to a specific resource.
  39. //
  40. // The following enum actually represents bit flags.
  41. //
  42. // STRICT: resource access must have all requested access bits
  43. // LOOSE: resource access must have at least one requested access bit
  44. // INHERIT: resource access may be inherited from parent.
  45. //
  46. enum {
  47. ACS_STRICT = 0x00,
  48. ACS_LOOSE = 0x01,
  49. ACS_INHERIT = 0x10
  50. };
  51. // Implementation-defined items ----------------------------------------------
  52. //
  53. #include <impldef.h>
  54. #include <implstub.h>
  55. // Parser-Defined items ------------------------------------------------------
  56. //
  57. // Content-type --------------------------------------------------------------
  58. //
  59. // Content-type is stored in the metabase for HTTPEXT. Each resource, if it
  60. // has a content-type that is different than the default content-type, is store
  61. // explicitly on the resource. If the content-type is the default value, then
  62. // there is no explicit setting in the metabase. Instead, the mapping of a
  63. // resource's extension to the default content-type is stored.
  64. //
  65. BOOL FGetContentTypeFromURI(
  66. /* [in] */ const IEcb& ecb,
  67. /* [in] */ LPCWSTR pwszUrl,
  68. /* [i/o] */ LPWSTR pwszContentType,
  69. /* [i/o] */ UINT * pcchContentType,
  70. /* [i/o] */ BOOL * pfIsGlobalMapping = NULL );
  71. BOOL FGetContentTypeFromPath( const IEcb& ecb,
  72. LPCWSTR pwszPath,
  73. LPWSTR pwszContentType,
  74. UINT * pcchContentType );
  75. SCODE ScSetContentType(
  76. /* [in] */ const IEcb& ecb,
  77. /* [in] */ LPCWSTR pwszUrl,
  78. /* [in] */ LPCWSTR pwszContentType );
  79. // Method ID's ---------------------------------------------------------------
  80. //
  81. // Each DAV method has its own ID for use in scriptmap inclusion lists.
  82. //
  83. typedef enum {
  84. MID_UNKNOWN = -1,
  85. MID_OPTIONS,
  86. MID_GET,
  87. MID_HEAD,
  88. MID_PUT,
  89. MID_POST,
  90. MID_DELETE,
  91. MID_MOVE,
  92. MID_COPY,
  93. MID_MKCOL,
  94. MID_PROPFIND,
  95. MID_PROPPATCH,
  96. MID_SEARCH,
  97. MID_LOCK,
  98. MID_UNLOCK,
  99. MID_SUBSCRIBE,
  100. MID_UNSUBSCRIBE,
  101. MID_POLL,
  102. MID_BATCHDELETE,
  103. MID_BATCHCOPY,
  104. MID_BATCHMOVE,
  105. MID_BATCHPROPFIND,
  106. MID_BATCHPROPPATCH,
  107. MID_X_MS_ENUMATTS
  108. } METHOD_ID;
  109. // Note: The method name handed to us from IIS is skinny, and there is no
  110. // real reason why it should be widened for this call. However, when the
  111. // scriptmap metabase cache goes wide, we may want to do something smarter
  112. // here.
  113. //
  114. METHOD_ID MidMethod (LPCSTR pszMethod);
  115. METHOD_ID MidMethod (LPCWSTR pwszMethod);
  116. // Custom error suberrors ----------------------------------------------------
  117. //
  118. typedef enum {
  119. // Default
  120. //
  121. CSE_NONE = 0,
  122. // 401
  123. //
  124. CSE_401_LOGON_FAILED = 1, // "Logon Failed"
  125. CSE_401_SERVER_CONFIG = 2, // "Logon Failed due to server configuration"
  126. CSE_401_ACL = 3, // "Unauthorized access due to ACL on resource"
  127. CSE_401_FILTER = 4, // "Authorization failed by filter"
  128. CSE_401_ISAPI = 5, // "Authorization failed by ISAPI/CGI app"
  129. // 403
  130. //
  131. CSE_403_EXECUTE = 1, // "Execute Access Forbidden"
  132. CSE_403_READ = 2, // "Read Access Forbidden"
  133. CSE_403_WRITE = 3, // "Write Access Forbidden"
  134. CSE_403_SSL = 4, // "SSL Required"
  135. CSE_403_SSL_128 = 5, // "SSL 128 Required"
  136. CSE_403_IP = 6, // "IP Address Rejected"
  137. CSE_403_CERT_REQUIRED = 7, // "Client Certificate Required"
  138. CSE_403_SITE = 8, // "Site Access Denied"
  139. CSE_403_TOO_MANY_USERS = 9, // "Too many users are connected"
  140. CSE_403_INVALID_CONFIG = 10, // "Invalid configuration"
  141. CSE_403_PASSWORD_CHANGE = 11, // "Password change"
  142. CSE_403_MAPPER = 12, // "Mapper access denied"
  143. CSE_403_CERT_REVOKED = 13, // "Client certificate revoked"
  144. CSE_403_FOURTEEN, // There is no suberror for this one.
  145. CSE_403_CALS_EXCEEDED = 15, // "Client Access Licenses exceeded"
  146. CSE_403_CERT_INVALID = 16, // "Client certificate untrusted or invalid"
  147. CSE_403_CERT_EXPIRED = 17, // "Client certificate expired"
  148. // 500
  149. //
  150. CSE_500_SHUTDOWN = 11, // "Server shutting down"
  151. CSE_500_RESTART = 12, // "Application restarting"
  152. CSE_500_TOO_BUSY = 13, // "Server too busy"
  153. CSE_500_INVALID_APP = 14, // "Invalid application"
  154. CSE_500_GLOBAL_ASA = 15, // "Requests for global.asa not allowed"
  155. CSE_500_ASP_ERROR = 100, // "ASP error"
  156. };
  157. // ========================================================================
  158. //
  159. // CLASS IAsyncIStreamObserver
  160. //
  161. // Interface to async I/O completion mechanism for IStreams capable of
  162. // returning E_PENDING from IStream::Read() and IStream::CopyTo().
  163. // A client would typically associate an IAsyncIStreamObserver with
  164. // an IStream when creating the latter. When one of the IStream calls
  165. // returns E_PENDING, the IAsyncIStreamObserver will be called when
  166. // the pending operation completes.
  167. //
  168. class IAsyncIStreamObserver
  169. {
  170. // NOT IMPLEMENTED
  171. //
  172. IAsyncIStreamObserver& operator=( const IAsyncIStreamObserver& );
  173. public:
  174. // CREATORS
  175. //
  176. virtual ~IAsyncIStreamObserver() = 0;
  177. // MANIPULATORS
  178. //
  179. virtual VOID AsyncIOComplete() = 0;
  180. };
  181. // ========================================================================
  182. //
  183. // DAV IMPL UTILITY CLASS
  184. //
  185. // Utility class for use by the DAV impl.
  186. // ALL methods here are inlined on retail builds. DON'T ADD NON-TRIVIAL METHODS!
  187. //
  188. class IBodyPart;
  189. class IMethUtilBase : public CMTRefCounted
  190. {
  191. private:
  192. // NOT IMPLEMENTED
  193. IMethUtilBase(const IMethUtilBase&);
  194. IMethUtilBase& operator=(const IMethUtilBase&);
  195. protected:
  196. auto_ref_ptr<IEcbBase> m_pecb;
  197. auto_ref_ptr<IResponseBase> m_presponse;
  198. IMethUtilBase(IEcbBase& ecb, IResponseBase& response) :
  199. m_pecb(&ecb),
  200. m_presponse(&response)
  201. {
  202. }
  203. public:
  204. void AddResponseText( UINT cbText,
  205. LPCSTR pszText )
  206. {
  207. m_presponse->AddBodyText(cbText, pszText);
  208. }
  209. void AddResponseText( UINT cchText,
  210. LPCWSTR pwszText )
  211. {
  212. m_presponse->AddBodyText(cchText, pwszText);
  213. }
  214. void AddResponseFile( const auto_ref_handle& hf,
  215. UINT64 ib64 = 0,
  216. UINT64 cb64 = 0xFFFFFFFFFFFFFFFF )
  217. {
  218. m_presponse->AddBodyFile(hf, ib64, cb64);
  219. }
  220. ULONG LcidAccepted() const { return m_pecb->LcidAccepted(); }
  221. VOID SetLcidAccepted(LCID lcid) { m_pecb->SetLcidAccepted(lcid); }
  222. LPCWSTR LpwszRequestUrl() const { return m_pecb->LpwszRequestUrl(); }
  223. BOOL FSsl() const { return m_pecb->FSsl(); }
  224. BOOL FFrontEndSecured() const { return m_pecb->FFrontEndSecured(); }
  225. UINT CchUrlPrefix( LPCSTR * ppszPrefix ) const
  226. {
  227. return m_pecb->CchUrlPrefix( ppszPrefix );
  228. }
  229. UINT CchServerName( LPCSTR * ppszServer ) const
  230. {
  231. return m_pecb->CchGetServerName( ppszServer );
  232. }
  233. UINT CchGetVirtualRootW( LPCWSTR * ppwszVroot ) const
  234. {
  235. return m_pecb->CchGetVirtualRootW(ppwszVroot);
  236. }
  237. UINT CchGetMatchingPathW( LPCWSTR * ppwszVroot ) const
  238. {
  239. return m_pecb->CchGetMatchingPathW(ppwszVroot);
  240. }
  241. LPCWSTR LpwszPathTranslated() const { return m_pecb->LpwszPathTranslated(); }
  242. SCODE ScUrlFromStoragePath( LPCWSTR pwszPath,
  243. LPWSTR pwszUrl,
  244. UINT* pcch )
  245. {
  246. return ::ScUrlFromStoragePath( *m_pecb,
  247. pwszPath,
  248. pwszUrl,
  249. pcch );
  250. }
  251. // Instance data lookup --------------------------------------------------
  252. //
  253. CInstData& InstData() const
  254. {
  255. return m_pecb->InstData();
  256. }
  257. //$NOTE
  258. //$REVIEW
  259. // I had to pull HitUser into here as pure virtual because we needed access
  260. // to it in CWMRenderer class (which has IMethBaseUtil * as a member) in
  261. // order to do a Revert. This was the only way to get davex and the forms
  262. // stuff to build without touching lots core headers this late in the Beta3
  263. // game. We should revisit this in RC1 to try and remove this from the vtable.
  264. // (9/1/99 - russsi)
  265. //
  266. virtual HANDLE HitUser() const = 0;
  267. virtual LPCSTR LpszServerName() const = 0;
  268. virtual BOOL FAuthenticated() const = 0;
  269. };
  270. class CMethUtil : public IMethUtilBase
  271. {
  272. private:
  273. auto_ref_ptr<IEcb> m_pecb;
  274. auto_ref_ptr<IRequest> m_prequest;
  275. auto_ref_ptr<IResponse> m_presponse;
  276. // Method ID
  277. //
  278. METHOD_ID m_mid;
  279. // Translation
  280. //
  281. enum { TRANS_UNKNOWN = -1, TRANS_FALSE, TRANS_TRUE };
  282. mutable LONG m_lTrans;
  283. // Overwrite
  284. //
  285. mutable LONG m_lOverwrite;
  286. // Depth
  287. //
  288. // The values for this member are defined in EX\CALCOM.H
  289. //
  290. mutable LONG m_lDepth;
  291. // Destination url
  292. //
  293. mutable auto_heap_ptr<WCHAR> m_pwszDestinationUrl;
  294. mutable auto_heap_ptr<WCHAR> m_pwszDestinationPath;
  295. mutable UINT m_cchDestinationPath;
  296. mutable auto_ref_ptr<CVRoot> m_pcvrDestination;
  297. // CREATORS
  298. //
  299. // Only create this object through the construction function!
  300. //
  301. CMethUtil( IEcb& ecb, IRequest& request, IResponse& response, METHOD_ID mid ) :
  302. IMethUtilBase(ecb,response),
  303. m_pecb(&ecb),
  304. m_prequest(&request),
  305. m_presponse(&response),
  306. m_mid(mid),
  307. m_lTrans(TRANS_UNKNOWN),
  308. m_lOverwrite(OVERWRITE_UNKNOWN),
  309. m_lDepth(DEPTH_UNKNOWN),
  310. m_cchDestinationPath(0)
  311. { }
  312. // NOT IMPLEMENTED
  313. //
  314. CMethUtil( const CMethUtil& );
  315. CMethUtil& operator=( const CMethUtil& );
  316. public:
  317. // CREATORS
  318. //
  319. // NOTE: Virtual destructor already provided by parent CMTRefCounted.
  320. //
  321. static CMethUtil * NewMethUtil( IEcb& ecb,
  322. IRequest& request,
  323. IResponse& response,
  324. METHOD_ID mid )
  325. {
  326. return new CMethUtil( ecb, request, response, mid );
  327. }
  328. // Get the pointer to ECB so the we could pass it to the objects that
  329. // will need to query it for data. This object holds a ref on ECB, so
  330. // make sure it is used only as long as this object is alive.
  331. //
  332. const IEcb * GetEcb() { return m_pecb.get(); }
  333. // REQUEST ACCESSORS -----------------------------------------------------
  334. //
  335. // Common header evaluation ----------------------------------------------
  336. //
  337. // FTranslate():
  338. //
  339. // Gets the value of the translate header.
  340. //
  341. BOOL FTranslated () const
  342. {
  343. // If we don't have a value yet...
  344. //
  345. if (TRANS_UNKNOWN == m_lTrans)
  346. {
  347. // Translation is expected when:
  348. //
  349. // The "translate" header is not present or
  350. // The "translate" header has a value other than "f" or "F"
  351. //
  352. // NOTE: The draft says the valid values are "t" or "f". So, we
  353. // are draft compliant if we check only the first char. This way
  354. // we are faster and/or more flexible.
  355. //
  356. // BTW: this is also an IIS-approved way to check boolean strings.
  357. // -- BeckyAn (BA:js)
  358. //
  359. LPCSTR psz = m_prequest->LpszGetHeader (gc_szTranslate);
  360. if (!psz || (*psz != 'f' && *psz != 'F'))
  361. m_lTrans = TRANS_TRUE;
  362. else
  363. m_lTrans = TRANS_FALSE;
  364. }
  365. return (TRANS_TRUE == m_lTrans);
  366. }
  367. // LOverwrite():
  368. //
  369. // Gets the enumerated value of the Overwrite/Allow-Rename headers.
  370. //
  371. LONG LOverwrite () const
  372. {
  373. // If we don't have a value yet...
  374. //
  375. if (OVERWRITE_UNKNOWN == m_lOverwrite)
  376. {
  377. // Overwrite is expected when:
  378. //
  379. // The "overwrite" header has a value of "t"
  380. //
  381. // NOTE: The draft says the valid values are "t" or "f". So, we
  382. // are draft compliant if we check only the first char. This way
  383. // we are faster and/or more flexible.
  384. //
  385. // BTW: this is also an IIS-approved way to check boolean strings.
  386. // -- BeckyAn (BA:js)
  387. //
  388. // NOTE also: the default value if there is no Overwrite: header
  389. // is TRUE -- DO overwrite. Allow-rename if "f", when header is
  390. // absent.
  391. //
  392. LPCSTR pszOverWrite = m_prequest->LpszGetHeader (gc_szOverwrite);
  393. if ((!pszOverWrite) || (*pszOverWrite == 't' || *pszOverWrite == 'T'))
  394. {
  395. m_lOverwrite |= OVERWRITE_YES;
  396. }
  397. LPCSTR pszAllowRename = m_prequest->LpszGetHeader (gc_szAllowRename);
  398. if (pszAllowRename && (*pszAllowRename == 't' || *pszAllowRename == 'T'))
  399. m_lOverwrite |= OVERWRITE_RENAME;
  400. }
  401. return (m_lOverwrite);
  402. }
  403. // LDepth ():
  404. //
  405. // Returns an enumerated value identifying the contents of the
  406. // depth header.
  407. //
  408. // The values for the enumeration are defined in EX\CALCOM.H
  409. //
  410. LONG __fastcall LDepth (LONG lDefault) const
  411. {
  412. // If we do not have a value yet...
  413. //
  414. if (DEPTH_UNKNOWN == m_lDepth)
  415. {
  416. // Depth can have several values:
  417. //
  418. // DEPTH_ZERO corresponds to "0"
  419. // DEPTH_ONE corresponds to "1"
  420. // DEPTH_INFINITY corresponds to "Infinity"
  421. // DEPTH_ONE_NOROOT corresponds to "1,NoRoot"
  422. // DEPTH_INFINITY_NOROOT corresponds to "Infinty,NoRoot"
  423. //
  424. // In the case there is no depth header specified, there
  425. // is a default that applies to each method. The default
  426. // is not the same from method to method, so the caller
  427. // must pass in a default value.
  428. //
  429. LPCSTR psz = m_prequest->LpszGetHeader (gc_szDepth);
  430. if (NULL == psz)
  431. {
  432. m_lDepth = lDefault;
  433. }
  434. else
  435. {
  436. switch (*psz)
  437. {
  438. case '0':
  439. if (!_stricmp (psz, gc_sz0))
  440. m_lDepth = DEPTH_ZERO;
  441. break;
  442. case '1':
  443. if (!_stricmp(psz, gc_sz1))
  444. m_lDepth = DEPTH_ONE;
  445. else if (!_stricmp(psz, gc_sz1NoRoot))
  446. m_lDepth = DEPTH_ONE_NOROOT;
  447. break;
  448. case 'i':
  449. case 'I':
  450. if (!_stricmp(psz, gc_szInfinity))
  451. m_lDepth = DEPTH_INFINITY;
  452. else if (!_stricmp(psz, gc_szInfinityNoRoot))
  453. m_lDepth = DEPTH_INFINITY_NOROOT;
  454. break;
  455. }
  456. }
  457. }
  458. return m_lDepth;
  459. }
  460. // FBrief():
  461. //
  462. // Gets the value of the Brief header.
  463. //
  464. BOOL FBrief () const { return m_pecb->FBrief(); }
  465. // FIsOffice9Request()
  466. // Finds out if the request is comming from Rosebud as shipped
  467. // in Office9.
  468. //
  469. BOOL FIsOffice9Request () const
  470. {
  471. // Get the User-Agent header
  472. //
  473. LPCSTR pszUserAgent = m_prequest->LpszGetHeader(gc_szUser_Agent);
  474. // If there is User-Agent header search for the product token of Office9
  475. //
  476. if (pszUserAgent)
  477. {
  478. LPCSTR pszProductToken = strstr(pszUserAgent, gc_szOffice9UserAgent);
  479. // If we have found the Office9 product token, and it is the
  480. // last token in the string, then the request is from Office9.
  481. //
  482. // Important Note: Office9's entire User-Agent is "Microsoft Data
  483. // Access Internet Publishing Provider DAV". We want to make sure
  484. // and NOT match "Microsoft Data Access Internet Publishing Provider
  485. // DAV 1.1 (for instance). So we require the token on the end of
  486. // the string. NOTE: Exprox currently adds itself BEFORE any
  487. // User-Agent string, so we're okay here.
  488. //
  489. if (pszProductToken &&
  490. ((pszProductToken == pszUserAgent) || FIsWhiteSpace(pszProductToken - 1)) &&
  491. ('\0' == (pszProductToken[gc_cchOffice9UserAgent])))
  492. {
  493. return TRUE;
  494. }
  495. }
  496. return FALSE;
  497. }
  498. // FIsRosebudNT5Request()
  499. // Finds out if the request is comming from Rosebud as shipped
  500. // in NT5.
  501. //
  502. BOOL FIsRosebudNT5Request () const
  503. {
  504. // Get the User-Agent header
  505. //
  506. LPCSTR pszUserAgent = m_prequest->LpszGetHeader(gc_szUser_Agent);
  507. // If there is User-Agent header search for the product token of Rosebud-NT5.
  508. //
  509. if (pszUserAgent)
  510. {
  511. LPCSTR pszProductToken = strstr(pszUserAgent, gc_szRosebudNT5UserAgent);
  512. // If we have found the Rosebud product token, and it is the
  513. // last token in the string, then the request is from Rosebud.
  514. //
  515. // Important Note: Rosebud-NT5's entire User-Agent is "Microsoft Data
  516. // Access Internet Publishing Provider DAV 1.1". We want to make sure
  517. // and NOT match "Microsoft Data Access Internet Publishing Provider
  518. // DAV 1.1 refresh" (for instance). So we require the token on the end of
  519. // the string. NOTE: Exprox currently adds itself BEFORE any
  520. // User-Agent string, so we're okay here.
  521. //
  522. if (pszProductToken &&
  523. ((pszProductToken == pszUserAgent) || FIsWhiteSpace(pszProductToken - 1)) &&
  524. ('\0' == (pszProductToken[gc_cchRosebudNT5UserAgent])))
  525. {
  526. return TRUE;
  527. }
  528. }
  529. return FALSE;
  530. }
  531. // Request item access ---------------------------------------------------
  532. //
  533. HANDLE HitUser() const { return m_pecb->HitUser(); }
  534. LPCSTR LpszMethod() const { return m_pecb->LpszMethod(); }
  535. LPCWSTR LpwszMethod() const { return m_pecb->LpwszMethod(); }
  536. METHOD_ID MidMethod() const { return m_mid; }
  537. LPCSTR LpszQueryString() const { return m_pecb->LpszQueryString(); }
  538. LPCSTR LpszServerName() const
  539. {
  540. LPCSTR pszServer;
  541. (void) m_pecb->CchGetServerName(&pszServer);
  542. return pszServer;
  543. }
  544. LPCSTR LpszVersion() const { return m_pecb->LpszVersion(); }
  545. BOOL FAuthenticated() const { return m_pecb->FAuthenticated(); }
  546. BOOL FGetServerVariable(LPCSTR pszName,
  547. LPSTR pszValue,
  548. DWORD * pcbValue) const
  549. { return m_pecb->FGetServerVariable(pszName, pszValue, pcbValue); }
  550. DWORD CbTotalRequestBytes() const { return m_pecb->CbTotalBytes(); }
  551. DWORD CbAvailableRequestBytes() const { return m_pecb->CbAvailable(); }
  552. // Destination url access ------------------------------------------------
  553. //
  554. SCODE __fastcall ScGetDestination( LPCWSTR* ppwszUrl,
  555. LPCWSTR* ppwszPath,
  556. UINT* pcchPath,
  557. CVRoot** ppcvr = NULL) const;
  558. // Uncommon header access wide -------------------------------------------
  559. //
  560. LPCWSTR LpwszGetRequestHeader( LPCSTR pszName, BOOL fUrlConversion ) const
  561. {
  562. // Assert that this is not one of the common headers handled above
  563. //
  564. Assert (_stricmp (gc_szTranslate, pszName));
  565. Assert (_stricmp (gc_szOverwrite, pszName));
  566. Assert (_stricmp (gc_szDepth, pszName));
  567. Assert (_stricmp (gc_szDestination, pszName));
  568. return m_prequest->LpwszGetHeader(pszName, fUrlConversion);
  569. }
  570. // IIS Access ------------------------------------------------------------
  571. //
  572. SCODE ScIISAccess( LPCWSTR pwszURI,
  573. DWORD dwAccessRequested,
  574. DWORD* pdwAccessOut = NULL) const;
  575. // Utility function to tell whether the scriptmap has an
  576. // applicable entry for a given URI and access.
  577. //
  578. BOOL FInScriptMap( LPCWSTR pwszURI,
  579. DWORD dwAccess,
  580. BOOL * pfCGI = NULL,
  581. SCODE * pscMatch = NULL) const;
  582. // Child ISAPI invocation ------------------------------------------------
  583. //
  584. // fForward = FALSE means just check if there's a scriptmap entry
  585. // fCheckISAPIAccess means do extra ACL checking (workaround the ASP access bug)
  586. // fKeepQueryString should only be set to FALSE on default doc processing
  587. // pszQueryPrefix allows the query string to be prefixed with new data
  588. // fIgnoreTFAccess if set to TRUE will ignore the access bits checking in translate: f case,
  589. // is handy when the acces bits are to be ignored by security checking functions
  590. // and function is used solely to redirect to the child ISAPI.
  591. // Example: we have real urls, constructed both from request URL
  592. // and relative URL parts from XML body (like B* methods). The object specified: t
  593. // by the request URL might need to be redirected to child ISAPI in the translate
  594. // case, while actual (constructed) URL-s might look like:
  595. //
  596. // /exchange/user1/Inbox.asp/message.eml (where message.eml was relative part)
  597. //
  598. // if we do not disable the security checking on the request URL in translate: f case
  599. // we might be failed out up front in case for example script source access was disabled
  600. // and it turned to be that directory was named INBOX.ASP.
  601. // NOTE: of course later the security is being checked on each constructed URL separately,
  602. // that is why we do not open the security hole.
  603. //
  604. // fDoNotForward if set to TRUE instead of forwarding request to child ISAPI it will return bad gateway,
  605. // which is necessary in the case there would be an attempt to execute child ISAPI on the
  606. // URL that is a construct of the request URL and the relative URL that comes in the request
  607. // body (like in B* methods)
  608. //
  609. SCODE ScApplyChildISAPI( LPCWSTR pwszURI,
  610. DWORD dwAccess,
  611. BOOL fCheckISAPIAccess = FALSE,
  612. BOOL fKeepQueryString = TRUE) const;
  613. // Apply child ISAPI if necessary, if not, verify if desired access
  614. // is granted
  615. //
  616. SCODE ScIISCheck ( LPCWSTR pwszURI,
  617. DWORD dwDesired = 0,
  618. BOOL fCheckISAPIAccess = FALSE) const;
  619. // Move/Copy/Delete access
  620. //
  621. SCODE ScCheckMoveCopyDeleteAccess (
  622. /* [in] */ LPCWSTR pwszUrl,
  623. /* [in] */ CVRoot* pcvr,
  624. /* [in] */ BOOL fDirectory,
  625. /* [in] */ BOOL fCheckScriptmaps,
  626. /* [in] */ DWORD dwAccess);
  627. // Url parsing/construction ----------------------------------------------
  628. //
  629. BOOL __fastcall FIsVRoot (LPCWSTR pwszURI);
  630. // Exchange and FS uses different URL to path mappers.
  631. //
  632. SCODE ScStoragePathFromUrl( LPCWSTR pwszUrl,
  633. LPWSTR pwszPath,
  634. UINT * pcch ) const
  635. {
  636. return ::ScStoragePathFromUrl(
  637. *m_pecb,
  638. pwszUrl,
  639. pwszPath,
  640. pcch );
  641. }
  642. // Construct the redirect url given the server name
  643. //
  644. SCODE ScConstructRedirectUrl( BOOL fNeedSlash,
  645. LPSTR * ppszUrl,
  646. LPCWSTR pwszServer = NULL ) const
  647. {
  648. return ::ScConstructRedirectUrl( *m_pecb,
  649. fNeedSlash,
  650. ppszUrl,
  651. pwszServer );
  652. }
  653. SCODE ScStripAndCheckHttpPrefix( LPCWSTR * ppwszUrl ) const
  654. {
  655. return ::ScStripAndCheckHttpPrefix( *m_pecb,
  656. ppwszUrl );
  657. }
  658. // Fetch the metadata for the request URI
  659. //
  660. IMDData& MetaData() const
  661. {
  662. return m_pecb->MetaData();
  663. }
  664. // Fetch the metadata for an aribtrary URI.
  665. // Note: use the MetaData() accessor above
  666. // to get the metadata for the request URI.
  667. //
  668. HRESULT HrMDGetData( LPCWSTR pwszURI,
  669. IMDData ** ppMDData )
  670. {
  671. Assert(m_pecb.get());
  672. return ::HrMDGetData( *m_pecb,
  673. pwszURI,
  674. ppMDData );
  675. }
  676. HRESULT HrMDGetData( LPCWSTR pwszMDPathAccess,
  677. LPCWSTR pwszMDPathOpen,
  678. IMDData ** ppMDData )
  679. {
  680. Assert(m_pecb.get());
  681. return ::HrMDGetData( *m_pecb,
  682. pwszMDPathAccess,
  683. pwszMDPathOpen,
  684. ppMDData );
  685. }
  686. HRESULT HrMDIsAuthorViaFrontPageNeeded( BOOL * pfFrontPageWeb ) const
  687. {
  688. Assert( pfFrontPageWeb );
  689. return ::HrMDIsAuthorViaFrontPageNeeded(*m_pecb,
  690. m_pecb->PwszMDPathVroot(),
  691. pfFrontPageWeb);
  692. }
  693. BOOL FGetContentType( LPCWSTR pwszURI,
  694. LPWSTR pwszContentType,
  695. UINT * pcchContentType ) const
  696. {
  697. return ::FGetContentTypeFromURI( *m_pecb,
  698. pwszURI,
  699. pwszContentType,
  700. pcchContentType );
  701. }
  702. SCODE ScSetContentType( LPCWSTR pwszURI,
  703. LPCWSTR pwszContentType )
  704. {
  705. return ::ScSetContentType( *m_pecb,
  706. pwszURI,
  707. pwszContentType );
  708. }
  709. // Url and child virtual directories -------------------------------------
  710. //
  711. SCODE ScFindChildVRoots( LPCWSTR pwszUri,
  712. ChainedStringBuffer<WCHAR>& sb,
  713. CVRList& vrl )
  714. {
  715. // Get the wide metapath, and make sure the URL is
  716. // stripped before we call into the MDPath processing
  717. //
  718. Assert (pwszUri == PwszUrlStrippedOfPrefix (pwszUri));
  719. UINT cb = ::CbMDPathW(*m_pecb, pwszUri);
  720. CStackBuffer<WCHAR,MAX_PATH> pwszMetaPath;
  721. if (NULL == pwszMetaPath.resize(cb))
  722. return E_OUTOFMEMORY;
  723. // Find the vroot
  724. //
  725. MDPathFromURIW (*m_pecb, pwszUri, pwszMetaPath.get());
  726. return CChildVRCache::ScFindChildren( *m_pecb, pwszMetaPath.get(), sb, vrl );
  727. }
  728. BOOL FGetChildVRoot( LPCWSTR pwszMetaPath, auto_ref_ptr<CVRoot>& cvr )
  729. {
  730. return CChildVRCache::FFindVroot( *m_pecb, pwszMetaPath, cvr );
  731. }
  732. BOOL FFindVRootFromUrl( LPCWSTR pwszUri, auto_ref_ptr<CVRoot>& cvr )
  733. {
  734. // Get the wide metapath, and make sure the URL is
  735. // stripped before we call into the MDPath processing
  736. //
  737. Assert (pwszUri == PwszUrlStrippedOfPrefix (pwszUri));
  738. UINT cb = ::CbMDPathW(*m_pecb, pwszUri);
  739. CStackBuffer<WCHAR,MAX_PATH> pwszMetaPath(cb);
  740. if (NULL == pwszMetaPath.resize(cb))
  741. return FALSE;
  742. // Build the path and go...
  743. //
  744. MDPathFromURIW (*m_pecb, pwszUri, pwszMetaPath.get());
  745. _wcslwr (pwszMetaPath.get());
  746. // If the last char of the metabase path is a slash, trim
  747. // it.
  748. //
  749. cb = static_cast<UINT>(wcslen(pwszMetaPath.get()));
  750. if (L'/' == pwszMetaPath[cb - 1])
  751. pwszMetaPath[cb - 1] = L'\0';
  752. // Find the vroot
  753. //
  754. return CChildVRCache::FFindVroot( *m_pecb, pwszMetaPath.get(), cvr );
  755. }
  756. // Exception handler -----------------------------------------------------
  757. //
  758. // Impls must call this function whenever they catch an exception on
  759. // a thread other than the thread on which the request initially
  760. // executed. This call causes a 500 Server Error response to be sent
  761. // if no other response is already in the process of being sent (only
  762. // a problem for chunked responses). It also ensures that the
  763. // EXTENSION_CONTROL_BLOCK from IIS will be properly cleaned up
  764. // regardless whether the pmu or any other object gets leaked as a result
  765. // of the exception. This last function keeps IIS from hanging on
  766. // shutdown.
  767. //
  768. void HandleException()
  769. {
  770. //
  771. // Just forward the exception handling to the ECB and hope it works.
  772. // If it doesn't then there is nothing we can do about it -- we
  773. // may leak the ECB which would cause IIS to hang on shutdown.
  774. //
  775. (VOID) m_pecb->HSEHandleException();
  776. }
  777. // Async error response handler ------------------------------------------
  778. //
  779. // Used to handle non-exception asynchronous error responses. The main
  780. // distinction between the exception and non-exception case is that in
  781. // the exception case we force a cleanup of the ECB, but here we don't.
  782. // Also, the exception case is hardwired to 500 Internal Server Error,
  783. // but this function can be used to send any 500 level error (e.g. a
  784. // 503 Service Unavailable).
  785. //
  786. VOID SendAsyncErrorResponse( DWORD dwStatusCode,
  787. LPCSTR pszBody = NULL,
  788. DWORD cchzBody = 0,
  789. LPCSTR pszStatusDescription = NULL,
  790. DWORD cchzStatusDescription = 0 )
  791. {
  792. m_pecb->SendAsyncErrorResponse( dwStatusCode,
  793. pszBody,
  794. cchzBody,
  795. pszStatusDescription,
  796. cchzStatusDescription );
  797. }
  798. // Request body access ---------------------------------------------------
  799. //
  800. BOOL FExistsRequestBody() const
  801. {
  802. return m_prequest->FExistsBody();
  803. }
  804. IStream * GetRequestBodyIStream( IAsyncIStreamObserver& obs ) const
  805. {
  806. return m_prequest->GetBodyIStream(obs);
  807. }
  808. VOID AsyncPersistRequestBody( IAsyncStream& stm,
  809. IAsyncPersistObserver& obs ) const
  810. {
  811. m_prequest->AsyncImplPersistBody( stm, obs );
  812. }
  813. // Response manipulators -------------------------------------------------
  814. //
  815. SCODE ScRedirect( LPCSTR pszURI )
  816. {
  817. return m_presponse->ScRedirect(pszURI);
  818. }
  819. void RestartResponse()
  820. {
  821. m_presponse->ClearHeaders();
  822. m_presponse->ClearBody();
  823. }
  824. void SupressBody()
  825. {
  826. // This should only be called by an IMPL. in response to a HEAD
  827. // request...
  828. //
  829. Assert (MID_HEAD == MidMethod());
  830. m_presponse->SupressBody();
  831. }
  832. void SetResponseCode( ULONG ulCode,
  833. LPCSTR lpszBodyDetail,
  834. UINT uiBodyDetail,
  835. UINT uiCustomSubError = CSE_NONE )
  836. {
  837. m_presponse->SetStatus( ulCode,
  838. NULL,
  839. uiCustomSubError,
  840. lpszBodyDetail,
  841. uiBodyDetail );
  842. }
  843. void SetResponseHeader( LPCSTR pszName,
  844. LPCSTR pszValue,
  845. BOOL fMultiple = FALSE )
  846. {
  847. m_presponse->SetHeader(pszName, pszValue, fMultiple);
  848. }
  849. void SetResponseHeader( LPCSTR pszName,
  850. LPCWSTR pwszValue,
  851. BOOL fMultiple = FALSE )
  852. {
  853. m_presponse->SetHeader(pszName, pwszValue, fMultiple);
  854. }
  855. void AddResponseStream( LPSTREAM pstm )
  856. {
  857. Assert( !IsBadReadPtr(pstm, sizeof(IStream)) );
  858. m_presponse->AddBodyStream(*pstm);
  859. }
  860. void AddResponseStream( LPSTREAM pstm,
  861. UINT ibOffset,
  862. UINT cbSize )
  863. {
  864. Assert( cbSize > 0 );
  865. Assert( !IsBadReadPtr(pstm, sizeof(IStream)) );
  866. m_presponse->AddBodyStream(*pstm, ibOffset, cbSize);
  867. }
  868. void AddResponseBodyPart( IBodyPart * pBodyPart )
  869. {
  870. m_presponse->AddBodyPart( pBodyPart );
  871. }
  872. // Common response emission routines -------------------------------------
  873. //
  874. void __fastcall EmitLocation ( LPCSTR pszHeader,
  875. LPCWSTR pwszURI,
  876. BOOL fCollection);
  877. void __fastcall EmitLastModified (FILETIME * pft);
  878. void __fastcall EmitCacheControlAndExpires (LPCWSTR pwszUrl);
  879. SCODE __fastcall ScEmitHeader (LPCWSTR pwszContent,
  880. LPCWSTR pwszURI = NULL,
  881. FILETIME* pftLastModification = NULL);
  882. // Etags -----------------------------------------------------------------
  883. //
  884. void __fastcall EmitETag (FILETIME * pft);
  885. void __fastcall EmitETag (LPCWSTR pwszPath);
  886. // Deferred Sends --------------------------------------------------------
  887. //
  888. //
  889. // DeferResponse()
  890. //
  891. // If called in an implementation method, this function prevents the
  892. // default automatic sending of the response upon the implementation
  893. // method's return.
  894. //
  895. // After calling this function the implementation must call either
  896. // SendPartialResponse() or SendCompleteResponse() to send the response.
  897. //
  898. void DeferResponse() { m_presponse->Defer(); }
  899. //
  900. // SendPartialResponse()
  901. //
  902. // Starts sending accumulated response data. The impl is expected to
  903. // continue adding response data after calling this function. The impl
  904. // must call SendCompleteResponse() to indicate when it is done adding
  905. // response data.
  906. //
  907. void SendPartialResponse() { m_presponse->SendPartial(); }
  908. //
  909. // SendCompleteResponse()
  910. //
  911. // Starts sending accumulated response data. Indicates that the impl
  912. // is done adding response data. The impl must not add response data
  913. // after calling this function.
  914. //
  915. void SendCompleteResponse() { m_presponse->SendComplete(); }
  916. // Expiration/Cache-Control ----------------------------------------------
  917. //
  918. SCODE ScGetExpirationTime( IN LPCWSTR pwszURI,
  919. IN LPWSTR pwszExpire,
  920. IN OUT UINT * pcch);
  921. // Allow header ----------------------------------------------------------
  922. //
  923. void SetAllowHeader (RESOURCE_TYPE rt);
  924. // Metadata helpers ------------------------------------------------------
  925. //
  926. UINT CbMDPathW(LPCWSTR pwszUrl) const { return ::CbMDPathW(*m_pecb, pwszUrl); }
  927. VOID MDPathFromUrlW( LPCWSTR pwszUrl, LPWSTR pwszMDPath )
  928. {
  929. ::MDPathFromURIW (*m_pecb, pwszUrl, pwszMDPath);
  930. }
  931. };
  932. typedef CMethUtil * LPMETHUTIL;
  933. typedef CMethUtil IMethUtil;
  934. // ========================================================================
  935. //
  936. // STRUCT SImplMethods
  937. //
  938. // Implementation methods
  939. //
  940. typedef void (DAVMETHOD)( LPMETHUTIL );
  941. extern DAVMETHOD DAVOptions;
  942. extern DAVMETHOD DAVGet;
  943. extern DAVMETHOD DAVHead;
  944. extern DAVMETHOD DAVPut;
  945. extern DAVMETHOD DAVPost;
  946. extern DAVMETHOD DAVDelete;
  947. extern DAVMETHOD DAVMove;
  948. extern DAVMETHOD DAVCopy;
  949. extern DAVMETHOD DAVMkCol;
  950. extern DAVMETHOD DAVPropFind;
  951. extern DAVMETHOD DAVPropPatch;
  952. extern DAVMETHOD DAVSearch;
  953. extern DAVMETHOD DAVLock;
  954. extern DAVMETHOD DAVUnlock;
  955. extern DAVMETHOD DAVSubscribe;
  956. extern DAVMETHOD DAVUnsubscribe;
  957. extern DAVMETHOD DAVPoll;
  958. extern DAVMETHOD DAVBatchDelete;
  959. extern DAVMETHOD DAVBatchMove;
  960. extern DAVMETHOD DAVBatchCopy;
  961. extern DAVMETHOD DAVBatchPropFind;
  962. extern DAVMETHOD DAVBatchPropPatch;
  963. extern DAVMETHOD DAVEnumAtts;
  964. extern DAVMETHOD DAVUnsupported; // Returns 501 Not Supported
  965. // ========================================================================
  966. //
  967. // IIS ISAPI Extension interface
  968. //
  969. class CDAVExt
  970. {
  971. public:
  972. static BOOL FInitializeDll( HINSTANCE, DWORD );
  973. static BOOL FVersion ( HSE_VERSION_INFO * );
  974. static BOOL FTerminate();
  975. static VOID LogECBString( LPEXTENSION_CONTROL_BLOCK, LONG, LPCSTR );
  976. static DWORD DwMain( LPEXTENSION_CONTROL_BLOCK, BOOL fUseRawUrlMappings = FALSE );
  977. };
  978. // Map last error to HTTP response code --------------------------------------
  979. //
  980. UINT HscFromLastError (DWORD dwErr);
  981. UINT HscFromHresult (HRESULT hr);
  982. UINT CSEFromHresult (HRESULT hr);
  983. // Virtual root mappings -----------------------------------------------------
  984. //
  985. BOOL FWchFromHex (LPCWSTR pwsz, WCHAR * pwch);
  986. // Lock header lookup --------------------------------------------------------
  987. //
  988. BOOL FGetLockTimeout (LPMETHUTIL pmu, DWORD * pdwSeconds, DWORD dwMaxOverride = 0);
  989. // Content type mappings -----------------------------------------------------
  990. //
  991. SCODE ScIsAcceptable (IMethUtil * pmu, LPCWSTR pwszContent);
  992. SCODE ScIsContentType (IMethUtil * pmu, LPCWSTR pwszType, LPCWSTR pwszTypeAnother = NULL);
  993. inline SCODE ScIsContentTypeXML(IMethUtil * pmu)
  994. {
  995. return ScIsContentType(pmu, gc_wszText_XML, gc_wszApplication_XML);
  996. }
  997. // Range header processors ---------------------------------------------------
  998. //
  999. class CRangeParser;
  1000. SCODE
  1001. ScProcessByteRanges(
  1002. /* [in] */ IMethUtil * pmu,
  1003. /* [in] */ LPCWSTR pwszPath,
  1004. /* [in] */ DWORD dwSizeLow,
  1005. /* [in] */ DWORD dwSizeHigh,
  1006. /* [in] */ CRangeParser * pByteRange );
  1007. SCODE
  1008. ScProcessByteRangesFromEtagAndTime (
  1009. /* [in] */ IMethUtil * pmu,
  1010. /* [in] */ DWORD dwSizeLow,
  1011. /* [in] */ DWORD dwSizeHigh,
  1012. /* [in] */ CRangeParser *pByteRange,
  1013. /* [in] */ LPCWSTR pwszEtag,
  1014. /* [in] */ FILETIME * pft );
  1015. // Non-Async IO on Top of Overlapped Files -----------------------------------
  1016. //
  1017. BOOL ReadFromOverlapped (HANDLE hf,
  1018. LPVOID pvBuf,
  1019. ULONG cbToRead,
  1020. ULONG * pcbRead,
  1021. OVERLAPPED * povl);
  1022. BOOL WriteToOverlapped (HANDLE hf,
  1023. const void * pvBuf,
  1024. ULONG cbToRead,
  1025. ULONG * pcbRead,
  1026. OVERLAPPED * povl);
  1027. // DAVEX LOCK Support routines -----------------------------------------------
  1028. //
  1029. class CXMLEmitter;
  1030. class CEmitterNode;
  1031. SCODE ScBuildLockDiscovery (CXMLEmitter& emitter,
  1032. CEmitterNode& en,
  1033. LPCWSTR wszLockToken,
  1034. LPCWSTR wszLockType,
  1035. LPCWSTR wszLockScope,
  1036. BOOL fRollback,
  1037. BOOL fDepthInfinity,
  1038. DWORD dwTimeout,
  1039. LPCWSTR pwszOwnerComment,
  1040. LPCWSTR pwszSubType);
  1041. // ========================================================================
  1042. //
  1043. // CLASS CXMLBody
  1044. // This class is wrapper around CTextBodyPart, it collects small XML pieces
  1045. // and save them in a CTextBodyPart, the body part will be added to body part
  1046. // list when it grow large enough. This avoid contructing CTextBodyPart too
  1047. // frequently.
  1048. //
  1049. class CXMLBody : public IXMLBody
  1050. {
  1051. private:
  1052. auto_ptr<CTextBodyPart> m_ptbp;
  1053. auto_ref_ptr<IMethUtil> m_pmu;
  1054. BOOL m_fChunked;
  1055. // non-implemented
  1056. //
  1057. CXMLBody(const CXMLBody& p);
  1058. CXMLBody& operator=(const CXMLBody& p);
  1059. // Helper
  1060. //
  1061. VOID SendCurrentChunk()
  1062. {
  1063. XmlTrace ("Dav: Xml: adding %ld bytes to body\n", m_ptbp->CbSize64());
  1064. m_pmu->AddResponseBodyPart (m_ptbp.relinquish());
  1065. //$REVIEW: The auto_ptr clas defined in \inc\autoptr.h is different from
  1066. //$REVIEW: the one defined in \inc\ex\autoptr.h. it does not set px
  1067. //$REVIEW: to zero when it relinquish. I believe this is a bug. I am not
  1068. //$REVIEW: sure if anyone is relying on this behavior, so I did not go ahead
  1069. //$REVIEW: fix the relinquish(), a better/complete fix will be moving
  1070. //$REVIEW: everyoen to \inc\ex\autoptr.h
  1071. //$REVIEW:
  1072. m_ptbp.clear();
  1073. // Send the data from this chunk back to the client before
  1074. // we go fetch the next chunk.
  1075. //
  1076. if (m_fChunked)
  1077. m_pmu->SendPartialResponse();
  1078. }
  1079. public:
  1080. // ctor & dtor
  1081. //
  1082. CXMLBody (IMethUtil * pmu, BOOL fChunked = TRUE)
  1083. : m_pmu(pmu),
  1084. m_fChunked(fChunked)
  1085. {
  1086. }
  1087. ~CXMLBody ()
  1088. {
  1089. }
  1090. // IXMLBody methods
  1091. //
  1092. SCODE ScAddTextBytes ( UINT cbText, LPCSTR lpszText );
  1093. VOID Done()
  1094. {
  1095. if (m_ptbp.get())
  1096. SendCurrentChunk();
  1097. }
  1098. };
  1099. SCODE ScAddTitledHref (CEmitterNode& enParent,
  1100. IMethUtil * pmu,
  1101. LPCWSTR pwszTag,
  1102. LPCWSTR pwszPath,
  1103. BOOL fCollection = FALSE,
  1104. CVRoot* pcvrTranslate = NULL);
  1105. inline
  1106. SCODE ScAddHref (CEmitterNode& enParent,
  1107. IMethUtil * pmu,
  1108. LPCWSTR pwszPath,
  1109. BOOL fCollection = FALSE,
  1110. CVRoot* pcvrTranslate = NULL)
  1111. {
  1112. return ScAddTitledHref (enParent,
  1113. pmu,
  1114. gc_wszXML__Href,
  1115. pwszPath,
  1116. fCollection,
  1117. pcvrTranslate);
  1118. }
  1119. //$HACK:ROSEBUD_TIMEOUT_HACK
  1120. // For the bug where rosebud waits until the last second
  1121. // before issueing the refresh. Need to filter out this check with
  1122. // the user agent string. The hack is to increase the timeout
  1123. // by 30 seconds and send back the requested timeout.
  1124. //
  1125. DEC_CONST gc_dwSecondsHackTimeoutForRosebud = 120;
  1126. //$HACK:END:ROSEBUD_TIMEOUT_HACK
  1127. //
  1128. #endif // !defined(_DAVIMPL_H_)