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.

664 lines
17 KiB

  1. /*
  2. * F S P U T . C P P
  3. *
  4. * Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
  5. */
  6. #include "_davfs.h"
  7. // ========================================================================
  8. //
  9. // CLASS CPutRequest
  10. //
  11. // Encapsulates the entire PUT request as an object which can be
  12. // can be reentered at various points for asynchronous processing.
  13. //
  14. class CPutRequest :
  15. public CMTRefCounted,
  16. private IAsyncStream,
  17. private IAsyncPersistObserver,
  18. private CDavWorkContext
  19. {
  20. //
  21. // Reference to the CMethUtil
  22. //
  23. auto_ref_ptr<CMethUtil> m_pmu;
  24. //
  25. // Cached request URI
  26. //
  27. LPCWSTR m_pwszURI;
  28. //
  29. // Cached translated URI
  30. //
  31. LPCWSTR m_pwszPath;
  32. //
  33. // File handle of target.
  34. //
  35. auto_ref_handle m_hf;
  36. //
  37. // Boolean flag indicating whether the file is being created
  38. // as a result of this PUT. Used to tell whether we need
  39. // to delete the file on failure as well as determine
  40. // whether to send back a 200 OK or a 201 Created response.
  41. //
  42. BOOL m_fCreatedFile;
  43. //
  44. // OVERLAPPED structure with file pointer info necessary
  45. // for async file I/O
  46. //
  47. OVERLAPPED m_ov;
  48. //
  49. // Minimum number of milliseconds between polls for WriteFile()
  50. // I/O completion. This number increases geometrically by a factor
  51. // (below) to minimize polling by worker threads.
  52. //
  53. DWORD m_dwMsecPollDelay;
  54. //
  55. // Initial poll delay (in milliseconds) and factor by which
  56. // that delay is increased each we poll and find that the
  57. // I/O has not completed. The factor is expressed as a
  58. // fraction: POLL_DELAY_NUMERATOR/POLL_DELAY_DENOMINATOR.
  59. // Note that the new value is computed using integer arithmetic
  60. // so choose values such that the delay will actually increase!
  61. //
  62. //$OPT Are these values optimal? Ideally, we want the
  63. //$OPT first poll to happen immediately after the I/O
  64. //$OPT completes.
  65. //
  66. enum
  67. {
  68. MSEC_POLL_DELAY_INITIAL = 10,
  69. POLL_DELAY_NUMERATOR = 2,
  70. POLL_DELAY_DENOMINATOR = 1
  71. };
  72. //
  73. // Number of bytes written in the last write operation.
  74. //
  75. DWORD m_dwcbWritten;
  76. //
  77. // Observer passed to AsyncWrite() to notify when the
  78. // write completes.
  79. //
  80. IAsyncWriteObserver * m_pobs;
  81. //
  82. // Status
  83. //
  84. SCODE m_sc;
  85. // MANIPULATORS
  86. //
  87. VOID SendResponse();
  88. VOID AsyncWrite( const BYTE * pbBuf,
  89. UINT cbToWrite,
  90. IAsyncWriteObserver& obsAsyncWrite );
  91. VOID PostIOCompletionPoll();
  92. // CDavWorkContext callback called to poll for I/O completion
  93. //
  94. DWORD DwDoWork();
  95. VOID WriteComplete();
  96. VOID PersistComplete( HRESULT hr );
  97. // NOT IMPLEMENTED
  98. //
  99. CPutRequest& operator=( const CPutRequest& );
  100. CPutRequest( const CPutRequest& );
  101. public:
  102. // CREATORS
  103. //
  104. CPutRequest( CMethUtil * pmu ) :
  105. m_pmu(pmu),
  106. m_pwszURI(pmu->LpwszRequestUrl()),
  107. m_pwszPath(pmu->LpwszPathTranslated()),
  108. m_fCreatedFile(FALSE),
  109. m_pobs(NULL),
  110. m_sc(S_OK)
  111. {
  112. m_ov.hEvent = NULL;
  113. m_ov.Offset = 0;
  114. m_ov.OffsetHigh = 0;
  115. }
  116. ~CPutRequest()
  117. {
  118. if ( m_ov.hEvent )
  119. CloseHandle( m_ov.hEvent );
  120. }
  121. // MANIPULATORS
  122. //
  123. void AddRef() { CMTRefCounted::AddRef(); }
  124. void Release() { CMTRefCounted::Release(); }
  125. VOID Execute();
  126. };
  127. // ------------------------------------------------------------------------
  128. //
  129. // CPutRequest::Execute()
  130. //
  131. // Process the request up to the point where we persist the body.
  132. //
  133. VOID
  134. CPutRequest::Execute()
  135. {
  136. LPCWSTR pwsz;
  137. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::Execute() called\n", GetCurrentThreadId(), this );
  138. //
  139. // First off, tell the pmu that we want to defer the response.
  140. // Even if we send it synchronously (i.e. due to an error in
  141. // this function), we still want to use the same mechanism that
  142. // we would use for async.
  143. //
  144. m_pmu->DeferResponse();
  145. // Do ISAPI application and IIS access bits checking
  146. //
  147. m_sc = m_pmu->ScIISCheck (m_pwszURI, MD_ACCESS_WRITE);
  148. if (FAILED(m_sc))
  149. {
  150. // Either the request has been forwarded, or some bad error occurred.
  151. // In either case, quit here and map the error!
  152. //
  153. DebugTrace( "Dav: ScIISCheck() failed (0x%08lX)\n", m_sc );
  154. SendResponse();
  155. return;
  156. }
  157. // From the HTTP/1.1 draft (update to RFC2068), Section 9.6:
  158. // The recipient of the entity MUST NOT ignore any Content-*
  159. // (e.g. Content-Range) headers that it does not understand
  160. // or implement and MUST return a 501 (Not Implemented) response
  161. // in such cases.
  162. // So, let's do the checking....
  163. //
  164. if (m_pmu->LpwszGetRequestHeader(gc_szContent_Range, FALSE))
  165. {
  166. m_sc = E_DAV_NO_PARTIAL_UPDATE; // 501 Not Implemented
  167. SendResponse();
  168. return;
  169. }
  170. // For PUT, content-length is required
  171. //
  172. if (NULL == m_pmu->LpwszGetRequestHeader (gc_szContent_Length, FALSE))
  173. {
  174. pwsz = m_pmu->LpwszGetRequestHeader (gc_szTransfer_Encoding, FALSE);
  175. if (!pwsz || _wcsicmp (pwsz, gc_wszChunked))
  176. {
  177. DavTrace ("Dav: PUT: missing content-length in request\n");
  178. m_sc = E_DAV_MISSING_LENGTH;
  179. SendResponse();
  180. return;
  181. }
  182. }
  183. // See if we are trying to trash the VROOT
  184. //
  185. if (m_pmu->FIsVRoot (m_pwszURI))
  186. {
  187. m_sc = E_DAV_PROTECTED_ENTITY;
  188. SendResponse();
  189. return;
  190. }
  191. // This method is gated by If-xxx headers
  192. //
  193. m_sc = ScCheckIfHeaders (m_pmu.get(), m_pwszPath, FALSE);
  194. if (m_sc != S_OK)
  195. {
  196. DebugTrace ("Dav: If-xxx failed their check\n");
  197. SendResponse();
  198. return;
  199. }
  200. // Check state headers.
  201. //
  202. m_sc = HrCheckStateHeaders (m_pmu.get(), m_pwszPath, FALSE);
  203. if (FAILED (m_sc))
  204. {
  205. DebugTrace ("DavFS: If-State checking failed.\n");
  206. SendResponse();
  207. return;
  208. }
  209. // If we have a locktoken, try to get the lock handle from the cache.
  210. // If this fails, fall through and do the normal processing.
  211. // DO NOT put LOCK handles into an auto-object!! The CACHE still owns it!!!
  212. //
  213. pwsz = m_pmu->LpwszGetRequestHeader (gc_szLockToken, TRUE);
  214. if (!pwsz || !FGetLockHandle (m_pmu.get(),
  215. m_pwszPath,
  216. GENERIC_WRITE,
  217. pwsz,
  218. &m_hf))
  219. {
  220. // Open the file manually.
  221. //
  222. if (!m_hf.FCreate(
  223. DavCreateFile (m_pwszPath, // filename
  224. GENERIC_WRITE, // dwAccess
  225. 0, //FILE_SHARE_READ | FILE_SHARE_WRITE, // DO conflict with OTHER write locks
  226. NULL, // lpSecurityAttributes
  227. OPEN_ALWAYS, // creation flags
  228. FILE_ATTRIBUTE_NORMAL | // attributes
  229. FILE_FLAG_OVERLAPPED |
  230. FILE_FLAG_SEQUENTIAL_SCAN,
  231. NULL))) // template
  232. {
  233. DWORD dwErr = GetLastError();
  234. // Return 409 Conflict in the case we were told that
  235. // path was not found, that will indicate that the parent
  236. // does not exist
  237. //
  238. if (ERROR_PATH_NOT_FOUND == dwErr)
  239. {
  240. m_sc = E_DAV_NONEXISTING_PARENT;
  241. }
  242. else
  243. {
  244. m_sc = HRESULT_FROM_WIN32(dwErr);
  245. }
  246. // Special work for 416 Locked responses -- fetch the
  247. // comment & set that as the response body.
  248. //
  249. if (FLockViolation (m_pmu.get(), dwErr, m_pwszPath, GENERIC_WRITE))
  250. {
  251. m_sc = E_DAV_LOCKED;
  252. }
  253. else
  254. {
  255. DWORD dwFileAttr;
  256. //$Raid
  257. // Special processing to find out if the resource is an
  258. // existing directory
  259. //
  260. if (static_cast<DWORD>(-1) != (dwFileAttr = GetFileAttributesW (m_pwszPath)))
  261. {
  262. if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY)
  263. m_sc = E_DAV_COLLECTION_EXISTS;
  264. }
  265. }
  266. DebugTrace ("Dav: failed to open the file for writing\n");
  267. SendResponse();
  268. return;
  269. }
  270. // Change the default error code to indicate the
  271. // creation of the file or the existance of the file.
  272. //
  273. if (GetLastError() != ERROR_ALREADY_EXISTS)
  274. {
  275. // Emit the location
  276. //
  277. m_pmu->EmitLocation (gc_szLocation, m_pwszURI, FALSE);
  278. m_fCreatedFile = TRUE;
  279. }
  280. // Make sure the content-location reflects the corrected URI
  281. //
  282. else if (FTrailingSlash (m_pwszURI))
  283. m_pmu->EmitLocation (gc_szContent_Location, m_pwszURI, FALSE);
  284. }
  285. //
  286. // Add a ref for the async persist and sloughf the data across.
  287. // Note that we use an auto_ref_ptr rather than AddRef() directly
  288. // because the persist call throws on failure and we need to clean
  289. // up the reference if it does.
  290. //
  291. {
  292. auto_ref_ptr<CPutRequest> pRef(this);
  293. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::Execute() calling AsyncPersistRequestBody()\n", GetCurrentThreadId(), this );
  294. m_pmu->AsyncPersistRequestBody( *this, *this );
  295. pRef.relinquish();
  296. }
  297. }
  298. // ------------------------------------------------------------------------
  299. //
  300. // CPutRequest::AsyncWrite()
  301. //
  302. // Called indirectly from AsyncPersistRequestBody() periodically to
  303. // write bytes to the file.
  304. //
  305. void
  306. CPutRequest::AsyncWrite( const BYTE * pbBuf,
  307. UINT cbToWrite,
  308. IAsyncWriteObserver& obs )
  309. {
  310. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::AsyncWrite() writing %d bytes\n", GetCurrentThreadId(), this, cbToWrite );
  311. //
  312. // Stash the async write observer passed to us so that
  313. // we can call it when the write completes
  314. //
  315. m_pobs = &obs;
  316. //
  317. // Start writing. I/O may complete before WriteFile() returns
  318. // in which case we continue to execute synchronously. If I/O
  319. // is pending when WriteFile() returns, we complete the I/O
  320. // asynchronously.
  321. //
  322. if ( WriteFile( m_hf.get(),
  323. pbBuf,
  324. cbToWrite,
  325. &m_dwcbWritten,
  326. &m_ov ) )
  327. {
  328. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::AsyncWrite(): WriteFile() succeeded\n", GetCurrentThreadId(), this );
  329. //
  330. // WriteFile() executed synchronously, so call
  331. // the completion routine now and keep processing
  332. // on the current thread.
  333. //
  334. WriteComplete();
  335. }
  336. else if ( ERROR_IO_PENDING == GetLastError() )
  337. {
  338. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::AsyncWrite(): WriteFile() executing asynchronously...\n", GetCurrentThreadId(), this );
  339. //
  340. // Set the polling delay to its initial value. The polling delay
  341. // is the amount of time before we'll check for I/O completion.
  342. // As described in the CPutRequest class definition, this delay
  343. // grows geometrically each time that the I/O is still pending
  344. // when polled. The value is only a hint -- polling may actually
  345. // execute before or after, depending on server load.
  346. //
  347. m_dwMsecPollDelay = MSEC_POLL_DELAY_INITIAL;
  348. //
  349. // WriteFile() is executing asynchronously, so make sure we
  350. // find out when it completes.
  351. //
  352. PostIOCompletionPoll();
  353. }
  354. else
  355. {
  356. DebugTrace( "CPutRequest::AsyncWrite() - WriteFile() failed (%d)\n", GetLastError() );
  357. m_sc = HRESULT_FROM_WIN32(GetLastError());
  358. WriteComplete();
  359. }
  360. }
  361. // ------------------------------------------------------------------------
  362. //
  363. // CPutRequest::PostIOCompletionPoll()
  364. //
  365. // Post a work context to poll for WriteFile() I/O completion.
  366. //
  367. VOID
  368. CPutRequest::PostIOCompletionPoll()
  369. {
  370. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::PostIOCompletionPoll() called\n", GetCurrentThreadId(), this );
  371. //
  372. // Post ourselves as a work context that will periodically
  373. // poll for async I/O completion. If successful our DwDoWork()
  374. // (inherited from CDAVWorkContext) will eventually be called
  375. // at some time > m_dwMsecPollDelay to poll for completion.
  376. //
  377. {
  378. auto_ref_ptr<CPutRequest> pRef(this);
  379. if ( CPoolManager::PostDelayedWork(this, m_dwMsecPollDelay) )
  380. {
  381. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::PostIOCompletionPoll(): PostDelayedWork() succeeded\n", GetCurrentThreadId(), this );
  382. pRef.relinquish();
  383. return;
  384. }
  385. }
  386. //
  387. // If we were unable to post the work context for any reason
  388. // we must wait for I/O completion and then call the completion
  389. // routine manually.
  390. //
  391. DebugTrace( "CPutRequest::PostIOCompletionPoll() - CPoolManager::PostDelayedWork() failed (%d). Waiting for completion....\n", GetLastError() );
  392. if ( GetOverlappedResult( m_hf.get(), &m_ov, &m_dwcbWritten, TRUE ) )
  393. {
  394. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::PostIOCompletionPoll(): GetOverlappedResult() succeeded\n", GetCurrentThreadId(), this );
  395. WriteComplete();
  396. return;
  397. }
  398. DebugTrace( "CPutRequest::PostIOCompletionPoll() - GetOverlappedResult() failed (%d).\n", GetLastError() );
  399. m_sc = HRESULT_FROM_WIN32(GetLastError());
  400. SendResponse();
  401. }
  402. // ------------------------------------------------------------------------
  403. //
  404. // CPutRequest::DwDoWork()
  405. //
  406. // Work completion callback routine. Called when the work context posted
  407. // above executes.
  408. //
  409. DWORD
  410. CPutRequest::DwDoWork()
  411. {
  412. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::DwDoWork() called\n", GetCurrentThreadId(), this );
  413. //
  414. // Take ownership of the reference added for posting.
  415. //
  416. auto_ref_ptr<CPutRequest> pRef;
  417. pRef.take_ownership(this);
  418. //
  419. // Quickly check whether the I/O has completed. If it has,
  420. // then call the completion routine. If not, then repost
  421. // the polling context with a geometrically longer delay.
  422. //
  423. if ( HasOverlappedIoCompleted(&m_ov) )
  424. {
  425. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::DwDoWork(): Overlapped I/O complete\n", GetCurrentThreadId(), this );
  426. if ( !GetOverlappedResult( m_hf.get(),
  427. &m_ov,
  428. &m_dwcbWritten,
  429. FALSE ) )
  430. {
  431. DebugTrace( "CPutRequest::DwDoWork() - Error in overlapped I/O (%d)\n", GetLastError() );
  432. m_sc = HRESULT_FROM_WIN32(GetLastError());
  433. }
  434. WriteComplete();
  435. }
  436. else
  437. {
  438. m_dwMsecPollDelay = (m_dwMsecPollDelay * POLL_DELAY_NUMERATOR) / POLL_DELAY_DENOMINATOR;
  439. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::DwDoWork(): I/O still pending. Increasing delay to %lu msec.\n", GetCurrentThreadId(), this, m_dwMsecPollDelay );
  440. PostIOCompletionPoll();
  441. }
  442. return 0;
  443. }
  444. // ------------------------------------------------------------------------
  445. //
  446. // CPutRequest::WriteComplete()
  447. //
  448. // Called when WriteFile() I/O completes -- either synchronously or
  449. // asynchronously, with or without an error.
  450. //
  451. void
  452. CPutRequest::WriteComplete()
  453. {
  454. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::WriteComplete() called. %d bytes written\n", GetCurrentThreadId(), this, m_dwcbWritten );
  455. //
  456. // If there was an error, then gripe about it.
  457. //
  458. if ( FAILED(m_sc) )
  459. DebugTrace( "CPutRequest::WriteComplete() - Write() error (as an HRESULT) 0x%08lX\n", m_sc );
  460. //
  461. // Update the current file position
  462. //
  463. m_ov.Offset += m_dwcbWritten;
  464. //
  465. // Resume processing by notifying the observer
  466. // we registered in AsyncWrite();
  467. //
  468. Assert( m_pobs );
  469. m_pobs->WriteComplete( m_dwcbWritten, m_sc );
  470. }
  471. // ------------------------------------------------------------------------
  472. //
  473. // CPutRequest::PersistComplete()
  474. //
  475. // AsyncPersistRequestBody() callback called when persisting completes.
  476. //
  477. VOID
  478. CPutRequest::PersistComplete( HRESULT hr )
  479. {
  480. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::PersistComplete() called\n", GetCurrentThreadId(), this );
  481. //
  482. // Take ownership of the reference added for the async persist.
  483. //
  484. auto_ref_ptr<CPutRequest> pRef;
  485. pRef.take_ownership(this);
  486. //
  487. // If the copy operation failed, gripe and send back
  488. // an appropriate response.
  489. //
  490. m_sc = hr;
  491. if ( FAILED(m_sc ) )
  492. {
  493. DebugTrace( "CPutRequest::PersistComplete() - Error persiting request body (0x%08lX)\n", m_sc );
  494. SendResponse();
  495. return;
  496. }
  497. //
  498. // Set EOF
  499. //
  500. SetFilePointer (m_hf.get(),
  501. m_ov.Offset,
  502. NULL,
  503. FILE_BEGIN);
  504. SetEndOfFile (m_hf.get());
  505. // Set the Content-xxx properties
  506. //
  507. m_sc = ScSetContentProperties (m_pmu.get(), m_pwszPath, m_hf.get());
  508. if ( FAILED(m_sc) )
  509. {
  510. DebugTrace( "CPutRequest::PersistComplete() - ScSetContentProperties() failed (0x%08lX)\n", m_sc );
  511. SendResponse();
  512. return;
  513. }
  514. // Passback an allow header
  515. //
  516. m_pmu->SetAllowHeader (RT_DOCUMENT);
  517. // Send the response
  518. //
  519. SendResponse();
  520. }
  521. // ------------------------------------------------------------------------
  522. //
  523. // CPutRequest::SendResponse()
  524. //
  525. // Set the response code and send the response.
  526. //
  527. VOID
  528. CPutRequest::SendResponse()
  529. {
  530. PutTrace( "DAV: TID %3d: 0x%08lX: CPutRequest::SendResponse() called\n", GetCurrentThreadId(), this );
  531. // Clear out any old handle here. We can't send any response
  532. // back while we are still holding a handle, otherwise, there
  533. // exists the chance that a client request comes immediately to
  534. // access this resource and receive 423 locked.
  535. //
  536. m_hf.clear();
  537. //
  538. // Set the response code and go
  539. //
  540. if ( SUCCEEDED(m_sc) )
  541. {
  542. if ( m_fCreatedFile )
  543. m_sc = W_DAV_CREATED;
  544. }
  545. else
  546. {
  547. if ( m_fCreatedFile )
  548. {
  549. // WARNING: the safe_revert class should only be
  550. // used in very selective situations. It is not
  551. // a "quick way to get around" impersonation.
  552. //
  553. safe_revert sr(m_pmu->HitUser());
  554. DavDeleteFile (m_pwszPath);
  555. DebugTrace ("Dav: deleting partial put (%ld)\n", GetLastError());
  556. }
  557. }
  558. m_pmu->SetResponseCode (HscFromHresult(m_sc), NULL, 0, CSEFromHresult(m_sc));
  559. m_pmu->SendCompleteResponse();
  560. }
  561. /*
  562. * DAVPut()
  563. *
  564. * Purpose:
  565. *
  566. * Win32 file system implementation of the DAV PUT method. The
  567. * PUT method creates a file in the DAV name space and populates
  568. * the file with the data found in the passed in request. The
  569. * response created indicates the success of the call.
  570. *
  571. * Parameters:
  572. *
  573. * pmu [in] pointer to the method utility object
  574. */
  575. void
  576. DAVPut (LPMETHUTIL pmu)
  577. {
  578. auto_ref_ptr<CPutRequest> pRequest(new CPutRequest(pmu));
  579. PutTrace( "DAV: CPutRequest: TID %3d: 0x%08lX Calling CPutRequest::Execute() \n", GetCurrentThreadId(), pRequest );
  580. pRequest->Execute();
  581. }