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.

943 lines
21 KiB

  1. /*
  2. * D A V C O M . C P P
  3. *
  4. * Common routines used by both DAVFS and DAVOWS.
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. #include "_davprs.h"
  9. #include <iiscnfg.h>
  10. #include "instdata.h"
  11. #include <mapicode.h>
  12. #include <mimeole.h>
  13. #include <dav.rh>
  14. #include <ex\rgiter.h>
  15. // Map last error to HTTP response code --------------------------------------
  16. //
  17. /*
  18. * HscFromLastError()
  19. *
  20. * Purpose:
  21. *
  22. * Maps the value returned from GetLastError() to
  23. * an HTTP 1.1 response status code.
  24. *
  25. * Parameters:
  26. *
  27. * err [in] system error code
  28. *
  29. * Returns:
  30. *
  31. * Mapped system error code
  32. */
  33. UINT
  34. HscFromLastError (DWORD dwErr)
  35. {
  36. UINT hsc = HSC_INTERNAL_SERVER_ERROR;
  37. switch (dwErr)
  38. {
  39. // Successes ---------------------------------------------------------
  40. //
  41. case NO_ERROR:
  42. return HSC_OK;
  43. // Parial Success
  44. //
  45. case ERROR_PARTIAL_COPY:
  46. hsc = HSC_MULTI_STATUS;
  47. break;
  48. // Errors ------------------------------------------------------------
  49. //
  50. // Not Implemented
  51. //
  52. case ERROR_NOT_SUPPORTED:
  53. case ERROR_INVALID_FUNCTION:
  54. hsc = HSC_NOT_IMPLEMENTED;
  55. break;
  56. // Not Found
  57. //
  58. case ERROR_FILE_NOT_FOUND:
  59. case ERROR_PATH_NOT_FOUND:
  60. case ERROR_INVALID_NAME:
  61. hsc = HSC_NOT_FOUND;
  62. break;
  63. // Unathorized Access
  64. //
  65. case ERROR_ACCESS_DENIED:
  66. hsc = HSC_UNAUTHORIZED;
  67. break;
  68. // Forbidden access
  69. //
  70. case ERROR_DRIVE_LOCKED:
  71. case ERROR_INVALID_ACCESS:
  72. case ERROR_INVALID_PASSWORD:
  73. case ERROR_LOCK_VIOLATION:
  74. case ERROR_WRITE_PROTECT:
  75. hsc = HSC_FORBIDDEN;
  76. break;
  77. // LOCKING -- this is the error when a resource is
  78. // already locked.
  79. //
  80. case ERROR_SHARING_VIOLATION:
  81. hsc = HSC_LOCKED;
  82. #ifdef DBG
  83. {
  84. static LONG s_lAssert = -1;
  85. if (s_lAssert == -1)
  86. {
  87. LONG lAss = GetPrivateProfileIntA ("general",
  88. "Assert_423s",
  89. 0,
  90. gc_szDbgIni);
  91. InterlockedCompareExchange (&s_lAssert, lAss, -1);
  92. }
  93. if (s_lAssert != 0)
  94. TrapSz ("GetLastError() maps to 423");
  95. }
  96. #endif // DBG
  97. break;
  98. // Bad Requests
  99. //
  100. case ERROR_BAD_COMMAND:
  101. case ERROR_BAD_FORMAT:
  102. case ERROR_INVALID_DRIVE:
  103. case ERROR_INVALID_PARAMETER:
  104. case ERROR_NO_UNICODE_TRANSLATION:
  105. hsc = HSC_BAD_REQUEST;
  106. break;
  107. // Errors generated when the client drops the connection
  108. // on us or when we timeout waiting for the client to send
  109. // us additional data. These errors should map to a response
  110. // status code of 400 Bad Request even though we can't actually
  111. // send back the response. IIS logs the response status code
  112. // and we want to indicate that the error is the client's,
  113. // not ours. K2 logs a 400, so this is for compatibility.
  114. //
  115. case WSAECONNRESET:
  116. case ERROR_NETNAME_DELETED:
  117. case ERROR_SEM_TIMEOUT:
  118. hsc = HSC_BAD_REQUEST;
  119. break;
  120. // Method Failure
  121. //
  122. case ERROR_DIR_NOT_EMPTY:
  123. hsc = HSC_METHOD_FAILURE;
  124. break;
  125. // Conflict
  126. //
  127. case ERROR_FILE_EXISTS:
  128. case ERROR_ALREADY_EXISTS:
  129. hsc = HSC_CONFLICT;
  130. break;
  131. // Unavailable Services (SMB access)
  132. //
  133. case ERROR_NETWORK_UNREACHABLE:
  134. case ERROR_UNEXP_NET_ERR:
  135. hsc = HSC_SERVICE_UNAVAILABLE;
  136. break;
  137. // Returned by metabase when the server is too busy.
  138. // Do NOT map this to HSC_SERVICE_UNAVAILABLE. The
  139. // "too busy" scenario has an IIS custom suberror
  140. // which assumes a 500 (not 503) status code.
  141. //
  142. case ERROR_PATH_BUSY:
  143. hsc = HSC_INTERNAL_SERVER_ERROR;
  144. break;
  145. // This error code (ERROR_OUTOFMEMORY) has been added for DAVEX.
  146. // The exchange store returns this error when we try to retrieve
  147. // the message body property. When we fetch properties on a
  148. // message, the store does not return the message body property
  149. // if the message body is greater than a certain length. The
  150. // general idea is that we don't wan't huge message bodies
  151. // returned along with the other properties. We'd much rather fetch
  152. // the message body separately.
  153. //
  154. case ERROR_OUTOFMEMORY:
  155. hsc = HSC_INSUFFICIENT_SPACE;
  156. break;
  157. default:
  158. hsc = HSC_INTERNAL_SERVER_ERROR;
  159. #ifdef DBG
  160. {
  161. static LONG s_lAssert = -1;
  162. if (s_lAssert == -1)
  163. {
  164. LONG lAss = GetPrivateProfileIntA ("general",
  165. "Assert_500s",
  166. 0,
  167. gc_szDbgIni);
  168. InterlockedCompareExchange (&s_lAssert, lAss, -1);
  169. }
  170. if (s_lAssert != 0)
  171. TrapSz ("GetLastError() maps to 500");
  172. }
  173. #endif // DBG
  174. break;
  175. }
  176. DebugTrace ("DAV: sys error (%ld) mapped to hsc (%ld)\n", dwErr, hsc);
  177. return hsc;
  178. }
  179. /*
  180. * CSEFromHresult()
  181. *
  182. * Purpose:
  183. *
  184. * Maps an hresult to an IIS custom error suberror
  185. *
  186. * Parameters:
  187. *
  188. * hr [in] HRESULT error code
  189. *
  190. * Returns:
  191. *
  192. * Mapped suberror
  193. */
  194. UINT
  195. CSEFromHresult (HRESULT hr)
  196. {
  197. UINT cse = CSE_NONE;
  198. switch (hr)
  199. {
  200. // Read Access Forbidden
  201. //
  202. case E_DAV_NO_IIS_READ_ACCESS:
  203. Assert( HscFromHresult(hr) == HSC_FORBIDDEN );
  204. cse = CSE_403_READ;
  205. break;
  206. // Write Access Forbidden
  207. //
  208. case E_DAV_NO_IIS_WRITE_ACCESS:
  209. Assert( HscFromHresult(hr) == HSC_FORBIDDEN );
  210. cse = CSE_403_WRITE;
  211. break;
  212. // Execute Access Forbidden
  213. //
  214. case E_DAV_NO_IIS_EXECUTE_ACCESS:
  215. Assert( HscFromHresult(hr) == HSC_FORBIDDEN );
  216. cse = CSE_403_EXECUTE;
  217. break;
  218. // Access denied due to ACL
  219. //
  220. case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
  221. Assert( HscFromHresult(hr) == HSC_UNAUTHORIZED );
  222. cse = CSE_401_ACL;
  223. break;
  224. // Server too busy
  225. //
  226. case HRESULT_FROM_WIN32(ERROR_PATH_BUSY):
  227. Assert( HscFromHresult(hr) == HSC_INTERNAL_SERVER_ERROR );
  228. cse = CSE_500_TOO_BUSY;
  229. break;
  230. }
  231. return cse;
  232. }
  233. /*
  234. * HscFromHresult()
  235. *
  236. * Purpose:
  237. *
  238. * Maps an hresult to an HTTP 1.1 response status code.
  239. *
  240. * Parameters:
  241. *
  242. * hr [in] HRESULT error code
  243. *
  244. * Returns:
  245. *
  246. * Mapped error code
  247. */
  248. UINT
  249. HscFromHresult (HRESULT hr)
  250. {
  251. UINT hsc = HSC_INTERNAL_SERVER_ERROR;
  252. // If the facility of the hr is WIN32,
  253. // parse out the error bits and send it to HscFromLastError.
  254. //
  255. if (FACILITY_WIN32 == HRESULT_FACILITY(hr))
  256. return HscFromLastError (HRESULT_CODE(hr));
  257. switch (hr)
  258. {
  259. // Successes ---------------------------------------------------------
  260. //
  261. case S_OK:
  262. case S_FALSE:
  263. case W_DAV_SCRIPTMAP_MATCH_FOUND:
  264. return HSC_OK;
  265. // No Content
  266. //
  267. case W_DAV_NO_CONTENT:
  268. hsc = HSC_NO_CONTENT;
  269. break;
  270. // Created
  271. //
  272. case W_DAV_CREATED:
  273. hsc = HSC_CREATED;
  274. break;
  275. // Partial content
  276. //
  277. case W_DAV_PARTIAL_CONTENT:
  278. hsc = HSC_PARTIAL_CONTENT;
  279. break;
  280. // Multi-status
  281. //
  282. case W_DAV_PARTIAL_SUCCESS:
  283. hsc = HSC_MULTI_STATUS;
  284. break;
  285. // Moved temporarily
  286. //
  287. case W_DAV_MOVED_TEMPORARILY:
  288. hsc = HSC_MOVED_TEMPORARILY;
  289. break;
  290. // Errors ------------------------------------------------------------
  291. //
  292. // Not modified
  293. //
  294. case E_DAV_ENTITY_NOT_MODIFIED:
  295. hsc = HSC_NOT_MODIFIED;
  296. break;
  297. // Pre-condition failed
  298. //
  299. case E_DAV_IF_HEADER_FAILURE:
  300. case E_DAV_NOTALLOWED_WITHIN_TRANSACTION:
  301. case E_DAV_OVERWRITE_REQUIRED:
  302. case E_DAV_CANT_SATISFY_LOCK_REQUEST:
  303. case E_DAV_NOTIF_SUBID_ERROR:
  304. hsc = HSC_PRECONDITION_FAILED;
  305. break;
  306. // Not Implemented
  307. //
  308. case E_NOTIMPL:
  309. case E_DAV_NO_PARTIAL_UPDATE:
  310. case STG_E_UNIMPLEMENTEDFUNCTION:
  311. case STG_E_INVALIDFUNCTION:
  312. case E_DAV_STORE_CHECK_FOLDER_NAME:
  313. case E_DAV_MKCOL_NOT_ALLOWED_ON_NULL_RESOURCE:
  314. case E_DAV_STORE_SEARCH_UNSUPPORTED:
  315. hsc = HSC_NOT_IMPLEMENTED;
  316. break;
  317. // Not Found
  318. //
  319. case E_DAV_ALT_FILESTREAM:
  320. case E_DAV_SHORT_FILENAME:
  321. case MK_E_NOOBJECT:
  322. case STG_E_FILENOTFOUND:
  323. case STG_E_INVALIDNAME:
  324. case STG_E_PATHNOTFOUND:
  325. case E_DAV_HIDDEN_OBJECT:
  326. case E_DAV_STORE_BAD_PATH:
  327. case E_DAV_STORE_NOT_FOUND:
  328. hsc = HSC_NOT_FOUND;
  329. break;
  330. // Unathorized Access
  331. //
  332. case E_DAV_ENTITY_TYPE_CONFLICT:
  333. case E_ACCESSDENIED:
  334. case STG_E_ACCESSDENIED:
  335. hsc = HSC_UNAUTHORIZED;
  336. break;
  337. case E_DAV_SMB_PROPERTY_ERROR:
  338. case E_DAV_NO_IIS_ACCESS_RIGHTS:
  339. case E_DAV_NO_IIS_READ_ACCESS:
  340. case E_DAV_NO_IIS_WRITE_ACCESS:
  341. case E_DAV_NO_IIS_EXECUTE_ACCESS:
  342. case E_DAV_NO_ACL_ACCESS:
  343. case E_DAV_PROTECTED_ENTITY:
  344. case E_DAV_CONFLICTING_PATHS:
  345. case E_DAV_FORBIDDEN:
  346. case STG_E_DISKISWRITEPROTECTED:
  347. case STG_E_LOCKVIOLATION:
  348. case E_DAV_STORE_MAIL_SUBMISSION:
  349. case E_DAV_STORE_REVISION_ID_FAILURE:
  350. case E_DAV_MAIL_SUBMISSION_FORBIDDEN:
  351. case E_DAV_MKCOL_REVISION_ID_FORBIDDEN:
  352. case E_ABORT:
  353. hsc = HSC_FORBIDDEN;
  354. break;
  355. case E_DAV_SEARCH_COULD_NOT_RESTRICT:
  356. case E_DAV_UNSUPPORTED_SQL:
  357. case MIME_E_NO_DATA: // empty 822 message, returned from IMail. It is nothing wrong with
  358. // request that attempts to create empty message. Semantics are wrong.
  359. hsc = HSC_UNPROCESSABLE;
  360. break;
  361. // LOCKING errors when a resource is already locked.
  362. //
  363. case E_DAV_LOCKED:
  364. case STG_E_SHAREVIOLATION:
  365. hsc = HSC_LOCKED;
  366. #ifdef DBG
  367. {
  368. static LONG s_lAssert = -1;
  369. if (s_lAssert == -1)
  370. {
  371. LONG lAss = GetPrivateProfileIntA ("general",
  372. "Assert_423s",
  373. 0,
  374. gc_szDbgIni);
  375. InterlockedCompareExchange (&s_lAssert, lAss, -1);
  376. }
  377. if (s_lAssert != 0)
  378. TrapSz ("HRESULT maps to 423");
  379. }
  380. #endif // DBG
  381. break;
  382. // Bad Requests
  383. //
  384. case E_DAV_EMPTY_FIND_REQUEST:
  385. case E_DAV_EMPTY_PATCH_REQUEST:
  386. case E_DAV_INCOMPLETE_SQL_STATEMENT:
  387. case E_DAV_INVALID_HEADER:
  388. case E_DAV_LOCK_NOT_FOUND:
  389. case E_DAV_MALFORMED_PATH:
  390. case E_DAV_METHOD_FAILURE_STAR_URL:
  391. case E_DAV_MISSING_CONTENT_TYPE:
  392. case E_DAV_NAMED_PROPERTY_ERROR:
  393. case E_DAV_NO_DESTINATION:
  394. case E_DAV_NO_QUERY:
  395. case E_DAV_PATCH_TYPE_MISMATCH:
  396. case E_DAV_READ_REQUEST_TIMEOUT:
  397. case E_DAV_SEARCH_SCOPE_ERROR:
  398. case E_DAV_UNEXPECTED_TYPE:
  399. case E_DAV_XML_PARSE_ERROR:
  400. case E_DAV_XML_BAD_DATA:
  401. case E_INVALIDARG:
  402. case MK_E_NOSTORAGE:
  403. case MK_E_SYNTAX:
  404. case STG_E_INVALIDPARAMETER:
  405. hsc = HSC_BAD_REQUEST;
  406. break;
  407. // Length required
  408. //
  409. case E_DAV_MISSING_LENGTH:
  410. hsc = HSC_LENGTH_REQUIRED;
  411. break;
  412. // Unknown content-types
  413. //
  414. case E_DAV_UNKNOWN_CONTENT:
  415. hsc = HSC_UNSUPPORTED_MEDIA_TYPE;
  416. break;
  417. // Content errors
  418. //
  419. case E_DAV_BASE64_ENCODING_ERROR:
  420. case E_DAV_RESPONSE_TYPE_UNACCEPTED:
  421. hsc = HSC_NOT_ACCEPTABLE;
  422. break;
  423. // Bad Gateway
  424. //
  425. case E_DAV_BAD_DESTINATION:
  426. case W_DAV_SPANS_VIRTUAL_ROOTS:
  427. case E_DAV_STAR_SCRIPTMAPING_MISMATCH:
  428. hsc = HSC_BAD_GATEWAY;
  429. break;
  430. // Methods not allowed
  431. //
  432. case E_DAV_COLLECTION_EXISTS:
  433. case E_DAV_VOLUME_NOT_NTFS:
  434. case E_NOINTERFACE:
  435. case E_DAV_STORE_ALREADY_EXISTS:
  436. case E_DAV_MKCOL_OBJECT_ALREADY_EXISTS:
  437. hsc = HSC_METHOD_NOT_ALLOWED;
  438. break;
  439. // Conflict
  440. //
  441. case E_DAV_NONEXISTING_PARENT:
  442. case STG_E_FILEALREADYEXISTS:
  443. case E_DAV_CONFLICT:
  444. case E_DAV_NATIVE_CONTENT_NOT_MAPI:
  445. hsc = HSC_CONFLICT;
  446. break;
  447. // Unsatisfiable byte range requests
  448. //
  449. case E_DAV_RANGE_NOT_SATISFIABLE:
  450. hsc = HSC_RANGE_NOT_SATISFIABLE;
  451. break;
  452. // 424 Method Failure
  453. //
  454. case E_DAV_STORE_COMMIT_GOP:
  455. hsc = HSC_METHOD_FAILURE;
  456. break;
  457. case E_DAV_IPC_CONNECT_FAILED:
  458. case E_DAV_EXPROX_CONNECT_FAILED:
  459. case E_DAV_MDB_DOWN:
  460. case E_DAV_STORE_MDB_UNAVAILABLE:
  461. hsc = HSC_SERVICE_UNAVAILABLE;
  462. break;
  463. case E_DAV_RSRC_INSUFFICIENT_BUFFER:
  464. hsc = HSC_INSUFFICIENT_SPACE;
  465. break;
  466. default:
  467. case E_DAV_METHOD_FORWARDED:
  468. case E_DAV_GET_DB_HELPER_FAILURE:
  469. case E_DAV_NOTIF_POLL_FAILURE:
  470. hsc = HSC_INTERNAL_SERVER_ERROR;
  471. #ifdef DBG
  472. {
  473. static LONG s_lAssert = -1;
  474. if (s_lAssert == -1)
  475. {
  476. LONG lAss = GetPrivateProfileIntA ("general",
  477. "Assert_500s",
  478. 0,
  479. gc_szDbgIni);
  480. InterlockedCompareExchange (&s_lAssert, lAss, -1);
  481. }
  482. if (s_lAssert != 0)
  483. TrapSz ("HRESULT maps to 500");
  484. }
  485. #endif // DBG
  486. break;
  487. }
  488. DebugTrace ("DAV: HRESULT error (0x%08x) mapped to hsc (%ld)\n", hr, hsc);
  489. return hsc;
  490. }
  491. BOOL
  492. FWchFromHex (LPCWSTR pwsz, WCHAR * pwch)
  493. {
  494. INT iwch;
  495. WCHAR wch;
  496. WCHAR wchX = 0;
  497. Assert (pwch);
  498. for (iwch = 0; iwch < 2; iwch++)
  499. {
  500. // Shift whats there up a diget
  501. //
  502. wchX = (WCHAR)(wchX << 4);
  503. // Parse the next char
  504. //
  505. wch = pwsz[iwch];
  506. // Make sure we don't exceed the sequence.
  507. //
  508. if (!wch)
  509. return FALSE;
  510. #pragma warning(disable:4244)
  511. if ((wch >= L'0') && (wch <= L'9'))
  512. wchX += (WCHAR)(wch - L'0');
  513. else if ((wch >= L'A') && (wch <= L'F'))
  514. wchX += (WCHAR)(wch - L'A' + 10);
  515. else if ((wch >= L'a') && (wch <= L'f'))
  516. wchX += (WCHAR)(wch - L'a' + 10);
  517. else
  518. return FALSE; // bad sequence
  519. #pragma warning(default:4244)
  520. }
  521. *pwch = wchX;
  522. return TRUE;
  523. }
  524. // Byte Range Checking and Header Emission -----------------------------------------------------------
  525. //
  526. /*
  527. * ScProcessByteRanges()
  528. *
  529. * Purpose:
  530. *
  531. * Helper function used to process byte ranges and emit the header
  532. * information for GET responses.
  533. *
  534. * Parameters:
  535. *
  536. * pmu [in] pointer to the method util obj
  537. * pwszPath [in] path of request entity
  538. * dwSizeLow [in] size of get request entity (low byte)
  539. * dwSizeHigh [in] size of get request entity (high byte)
  540. * pByteRange [out] given a pointer to a RangeIter obj, the
  541. * function fills in byte range information
  542. * if the request contains a Range header
  543. * pszEtagOverride [in, opt.] pointer to an Etag, overrides the Etag
  544. * generated from the last modification
  545. * time
  546. * pftOverride [in, opt.] pointer to a FILETIME structure, overrides
  547. * call to FGetLastModTime
  548. *
  549. * Returns: SCODE
  550. *
  551. * S_OK indicates success(ordinary response).
  552. * W_DAV_PARTIAL_CONTENT (206) indicates success(byte range response).
  553. * E_DAV_RANGE_NOT_SATISFIABLE (416) indicates all of requested
  554. * byte ranges were beyond the size of the entity.
  555. */
  556. SCODE
  557. ScProcessByteRanges (IMethUtil * pmu,
  558. LPCWSTR pwszPath,
  559. DWORD dwSizeLow,
  560. DWORD dwSizeHigh,
  561. CRangeParser * pByteRange)
  562. {
  563. FILETIME ft;
  564. WCHAR pwszEtag[CCH_ETAG];
  565. // Check the validity of the inputs
  566. //
  567. Assert (pmu);
  568. Assert (pwszPath);
  569. Assert (pByteRange);
  570. SideAssert(FGetLastModTime (pmu, pwszPath, &ft));
  571. SideAssert(FETagFromFiletime (&ft, pwszEtag, pmu->GetEcb()));
  572. return ScProcessByteRangesFromEtagAndTime (pmu,
  573. dwSizeLow,
  574. dwSizeHigh,
  575. pByteRange,
  576. pwszEtag,
  577. &ft);
  578. }
  579. SCODE
  580. ScProcessByteRangesFromEtagAndTime (IMethUtil * pmu,
  581. DWORD dwSizeLow,
  582. DWORD dwSizeHigh,
  583. CRangeParser *pByteRange,
  584. LPCWSTR pwszEtag,
  585. FILETIME * pft)
  586. {
  587. SCODE sc = S_OK;
  588. LPCWSTR pwszRangeHeader;
  589. WCHAR rgwchBuf[128] = L"";
  590. // Check the validity of the inputs
  591. //
  592. Assert (pmu);
  593. Assert (pByteRange);
  594. Assert (pwszEtag);
  595. Assert (pft);
  596. // Check to see if we have a Range header and the If-Range condition( if
  597. // there is one) is satisfied. Do not apply URL conversion rules while
  598. // fetching the header.
  599. //
  600. pwszRangeHeader = pmu->LpwszGetRequestHeader (gc_szRange, FALSE);
  601. if ( pwszRangeHeader && !FAILED (ScCheckIfRangeHeaderFromEtag (pmu,
  602. pft,
  603. pwszEtag)) )
  604. {
  605. // Limit the maximum size of range headers we will process
  606. //
  607. if ( MAX_PATH < wcslen(pwszRangeHeader) )
  608. {
  609. sc = E_DAV_RANGE_NOT_SATISFIABLE;
  610. goto ret;
  611. }
  612. // We have no means of handling byte ranges for files larger than 4GB,
  613. // due to limitations of _HSE_TF_INFO that takes DWORD values for sizes
  614. // and offsets. So if we are geting byterange request on that large file
  615. // just fail out - with some error that maps to 405 Method Not Allowed
  616. //
  617. if (dwSizeHigh)
  618. {
  619. sc = E_NOINTERFACE;
  620. goto ret;
  621. }
  622. // OK, we have a byte range. Parse the byte ranges from the header.
  623. // The function takes the size of the request entity to make
  624. // sure the byte ranges are consistent with the entity size (no byte
  625. // ranges beyond the size).
  626. //
  627. sc = pByteRange->ScParseByteRangeHdr(pwszRangeHeader, dwSizeLow);
  628. switch (sc)
  629. {
  630. case W_DAV_PARTIAL_CONTENT:
  631. // We have a byte range (206 partial content). Send back
  632. // this return code.
  633. //
  634. break;
  635. case E_DAV_RANGE_NOT_SATISFIABLE:
  636. // We don't have any satisfiable ranges (all our ranges had a
  637. // start byte greater than the size of the file or they
  638. // requested a zero-sized range). Our behaviour here depends on
  639. // the presence of the If-Range header.
  640. // If we have an If-Range header, return the default response
  641. // S_OK (the entire file). If we don't have one,
  642. // we need to return a 416 (Requested Range Not Satisfiable).
  643. // Would look like it is more performant to ask for the skinny
  644. // version here, but at this moment wide header value is already
  645. // cached so it makes no difference. And do not apply URL conversion
  646. // rules to the header.
  647. //
  648. if (!pmu->LpwszGetRequestHeader(gc_szIf_Range, FALSE))
  649. {
  650. // NO If-Range header found.
  651. // Set the Content-Range header to say "bytes *"
  652. // (meaning the whole file was sent).
  653. //
  654. wsprintfW(rgwchBuf, L"%ls */%d", gc_wszBytes, dwSizeLow);
  655. pmu->SetResponseHeader(gc_szContent_Range, rgwchBuf);
  656. // Send back this return code (E_DAV_RANGE_NOT_SATISFIABLE).
  657. //
  658. }
  659. else
  660. {
  661. // We DO have an If-Range header.
  662. // Return 200 OK, and send the whole file.
  663. //
  664. sc = S_OK;
  665. }
  666. break;
  667. case E_INVALIDARG:
  668. // If the parsing function returned S_FALSE we have a syntax
  669. // error, so we ignore the Range header and send the entire
  670. // file/stream.
  671. // Reset our return code to S_OK.
  672. //
  673. sc = S_OK;
  674. break;
  675. default:
  676. // Unrecognizable error. We should never see anything but
  677. // the three values in the case statement. Assert (TrapSz),
  678. // and return this sc.
  679. //
  680. break;
  681. }
  682. }
  683. // Either we didn't have a Range header or the If-Range condition
  684. // was false. Its an ordinary GET and we need to send the entire
  685. // file. Our response (S_OK) is already set by default.
  686. //
  687. ret:
  688. return sc;
  689. }
  690. // Generating a boundary for multipartpart mime like responses------------------
  691. //
  692. /*
  693. * GenerateBoundary()
  694. *
  695. * Purpose:
  696. *
  697. * Helper function used to generate a separator boundary for multipart
  698. * mime like responses
  699. *
  700. * Parameters:
  701. *
  702. * rgwchBoundary [out] boundary for multipart responses
  703. * cch [in] size of the rgwchBoundary parameter
  704. */
  705. void
  706. GenerateBoundary(LPWSTR rgwchBoundary, UINT cch)
  707. {
  708. UINT cchMin;
  709. UINT iIter;
  710. // Assert that we've been given a buffer of at least size 2 (a minimum
  711. // null terminated boundary of one byte).
  712. //
  713. Assert (cch > 1);
  714. Assert (rgwchBoundary);
  715. // The boundary size is the smaller of the size passed in to us or the default
  716. //
  717. cchMin = min(gc_ulDefaultBoundarySz, cch - 1);
  718. // We are going to randomly use characters from the boundary alphabet.
  719. // The rand() function is seeded by the current time
  720. //
  721. srand(GetTickCount());
  722. // Now to generate the actual boundary
  723. //
  724. for (iIter = 0; iIter < cchMin; iIter++)
  725. {
  726. rgwchBoundary[iIter] = gc_wszBoundaryAlphabet[ rand() % gc_ulAlphabetSz ];
  727. }
  728. rgwchBoundary[cchMin] = L'\0';
  729. }
  730. // Non-Async IO on Top of Overlapped Files -----------------------------------
  731. //
  732. BOOL
  733. ReadFromOverlapped (HANDLE hf,
  734. LPVOID pvBuf,
  735. ULONG cbToRead,
  736. ULONG * pcbRead,
  737. OVERLAPPED * povl)
  738. {
  739. Assert (povl);
  740. // Start reading
  741. //
  742. if ( !ReadFile( hf, pvBuf, cbToRead, pcbRead, povl ) )
  743. {
  744. if ( GetLastError() == ERROR_IO_PENDING )
  745. {
  746. if ( !GetOverlappedResult( hf, povl, pcbRead, TRUE ) )
  747. {
  748. if ( GetLastError() != ERROR_HANDLE_EOF )
  749. {
  750. DebugTrace( "ReadFromOverlapped(): "
  751. "GetOverlappedResult() failed (%d)\n",
  752. GetLastError() );
  753. return FALSE;
  754. }
  755. }
  756. }
  757. else if ( GetLastError() != ERROR_HANDLE_EOF )
  758. {
  759. DebugTrace( "ReadFromOverlapped(): "
  760. "ReadFile() failed (%d)\n",
  761. GetLastError() );
  762. return FALSE;
  763. }
  764. }
  765. return TRUE;
  766. }
  767. BOOL
  768. WriteToOverlapped (HANDLE hf,
  769. const void * pvBuf,
  770. ULONG cbToWrite,
  771. ULONG * pcbWritten,
  772. OVERLAPPED * povl)
  773. {
  774. Assert (povl);
  775. // Start writting
  776. //
  777. if ( !WriteFile( hf, pvBuf, cbToWrite, pcbWritten, povl ) )
  778. {
  779. if ( GetLastError() == ERROR_IO_PENDING )
  780. {
  781. if ( !GetOverlappedResult( hf, povl, pcbWritten, TRUE ) )
  782. {
  783. if ( GetLastError() != ERROR_HANDLE_EOF )
  784. {
  785. DebugTrace( "WriteToOverlapped(): "
  786. "GetOverlappedResult() failed (%d)\n",
  787. GetLastError() );
  788. return FALSE;
  789. }
  790. }
  791. }
  792. else if ( GetLastError() != ERROR_HANDLE_EOF )
  793. {
  794. DebugTrace( "WriteToOverlapped(): "
  795. "WriteFile() failed (%d)\n",
  796. GetLastError() );
  797. return FALSE;
  798. }
  799. }
  800. return TRUE;
  801. }