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.

481 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. prefetch.cxx
  5. Abstract:
  6. Functions and methods to support http random read access.
  7. Contents:
  8. AttemptReadFromFile
  9. SetStreamPointer
  10. SetLengthFromCache
  11. ReadLoop_Fsm
  12. WriteResponseBufferToCache
  13. WriteQueryBufferToCache
  14. Author:
  15. Rajeev Dujari (rajeevd) March 1996
  16. Revision History:
  17. Ahsan Kabir (akabir) November 1997
  18. --*/
  19. #include <wininetp.h>
  20. #define READLOOP_BUFSIZE 2048
  21. BOOL
  22. HTTP_REQUEST_HANDLE_OBJECT::AttemptReadFromFile(
  23. LPVOID lpBuf,
  24. DWORD cbToRead,
  25. DWORD* pcbRead
  26. )
  27. {
  28. DEBUG_ENTER((DBG_CACHE,
  29. Bool,
  30. "INTERNET_CONNECT_HANDLE_OBJECT::AttemptReadFromFile",
  31. "%#x, %d, %#x",
  32. lpBuf,
  33. cbToRead,
  34. pcbRead
  35. ));
  36. BOOL fSuccess;
  37. DWORD dwBytesToCopy = 0;
  38. if (!cbToRead)
  39. {
  40. *pcbRead = 0;
  41. DEBUG_LEAVE(TRUE);
  42. return TRUE;
  43. }
  44. if (IsCacheReadInProgress())
  45. {
  46. INET_ASSERT(_VirtualCacheFileSize == _RealCacheFileSize);
  47. // Entire read should be satisfied from cache.
  48. *pcbRead = cbToRead;
  49. if (ReadUrlCacheEntryStream
  50. (_hCacheStream, _dwCurrentStreamPosition, lpBuf, pcbRead, 0))
  51. {
  52. AdvanceReadPosition (*pcbRead);
  53. DEBUG_LEAVE(TRUE);
  54. return TRUE;
  55. }
  56. else
  57. {
  58. *pcbRead = 0;
  59. DEBUG_LEAVE(FALSE);
  60. return FALSE;
  61. }
  62. }
  63. else if (IsCacheWriteInProgress())
  64. {
  65. // See if the read is completely within the file.
  66. if (!IsEndOfFile() && _dwCurrentStreamPosition + cbToRead > _VirtualCacheFileSize)
  67. {
  68. DEBUG_PRINT(HTTP, ERROR, ("AttemptRead Failed streampos=%d cbToRead=%d, _VitrualCacheFileSize=%d\n",
  69. _dwCurrentStreamPosition, cbToRead, _VirtualCacheFileSize));
  70. DEBUG_LEAVE(FALSE);
  71. return FALSE;
  72. }
  73. HANDLE hfRead;
  74. hfRead = GetDownloadFileReadHandle();
  75. if (hfRead == INVALID_HANDLE_VALUE)
  76. {
  77. DEBUG_LEAVE(FALSE);
  78. return FALSE;
  79. }
  80. // Read the data from the file.
  81. SetFilePointer (hfRead, _dwCurrentStreamPosition, NULL, FILE_BEGIN);
  82. fSuccess = ReadFile (hfRead, lpBuf, cbToRead, pcbRead, NULL);
  83. if (!fSuccess)
  84. {
  85. DEBUG_LEAVE(FALSE);
  86. return FALSE;
  87. }
  88. AdvanceReadPosition (*pcbRead);
  89. DEBUG_LEAVE(TRUE);
  90. return TRUE;
  91. }
  92. else
  93. {
  94. DEBUG_LEAVE(FALSE);
  95. return FALSE;
  96. }
  97. }
  98. // Called from InternetSetFilePointer
  99. DWORD
  100. HTTP_REQUEST_HANDLE_OBJECT::SetStreamPointer(
  101. LONG lDistanceToMove,
  102. DWORD dwMoveMethod
  103. )
  104. {
  105. DWORD dwErr = ERROR_SUCCESS;
  106. // Fail if data is not from cache or going to cache.
  107. if (!IsCacheReadInProgress() && !IsCacheWriteInProgress())
  108. {
  109. dwErr = ERROR_INTERNET_INVALID_OPERATION;
  110. goto done;
  111. }
  112. // BUGBUG: we don't handle chunked transfer, new with http 1.1
  113. if (IsChunkEncoding())
  114. {
  115. dwErr = ERROR_INTERNET_INVALID_OPERATION;
  116. goto done;
  117. }
  118. switch (dwMoveMethod)
  119. {
  120. case FILE_BEGIN:
  121. _dwCurrentStreamPosition = (DWORD) lDistanceToMove;
  122. break;
  123. case FILE_CURRENT:
  124. if (lDistanceToMove < 0
  125. && ((DWORD) -lDistanceToMove) > _dwCurrentStreamPosition)
  126. {
  127. dwErr = ERROR_NEGATIVE_SEEK;
  128. }
  129. else
  130. {
  131. _dwCurrentStreamPosition += lDistanceToMove;
  132. }
  133. break;
  134. case FILE_END:
  135. if (!IsContentLength())
  136. dwErr = ERROR_INTERNET_INVALID_OPERATION;
  137. else if (lDistanceToMove < 0 && ((DWORD) -lDistanceToMove) > _ContentLength)
  138. dwErr = ERROR_NEGATIVE_SEEK;
  139. else
  140. _dwCurrentStreamPosition = _ContentLength + lDistanceToMove;
  141. break;
  142. default:
  143. dwErr = ERROR_INVALID_PARAMETER;
  144. break;
  145. }
  146. done:
  147. if (dwErr == ERROR_SUCCESS)
  148. {
  149. if (IsKeepAlive() && IsContentLength())
  150. _BytesRemaining = _ContentLength - _dwCurrentStreamPosition;
  151. if (_VirtualCacheFileSize > _dwCurrentStreamPosition)
  152. SetAvailableDataLength (_VirtualCacheFileSize - _dwCurrentStreamPosition);
  153. else
  154. SetAvailableDataLength (0);
  155. return _dwCurrentStreamPosition;
  156. }
  157. else
  158. {
  159. SetLastError (dwErr);
  160. return (DWORD) -1L;
  161. }
  162. }
  163. DWORD
  164. CFsm_ReadLoop::RunSM(
  165. IN CFsm * Fsm
  166. )
  167. {
  168. DEBUG_ENTER((DBG_HTTP,
  169. Dword,
  170. "CFsm_ReadLoop::RunSM",
  171. "%#x",
  172. Fsm
  173. ));
  174. DWORD error;
  175. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  176. CFsm_ReadLoop * stateMachine = (CFsm_ReadLoop *)Fsm;
  177. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)Fsm->GetContext();
  178. switch (Fsm->GetState()) {
  179. case FSM_STATE_INIT:
  180. case FSM_STATE_CONTINUE:
  181. error = pRequest->ReadLoop_Fsm(stateMachine);
  182. break;
  183. default:
  184. error = ERROR_INTERNET_INTERNAL_ERROR;
  185. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  186. INET_ASSERT(FALSE);
  187. break;
  188. }
  189. DEBUG_LEAVE(error);
  190. return error;
  191. }
  192. DWORD
  193. HTTP_REQUEST_HANDLE_OBJECT::ReadLoop_Fsm(
  194. IN CFsm_ReadLoop * Fsm
  195. )
  196. {
  197. DEBUG_ENTER((DBG_HTTP,
  198. Dword,
  199. "HTTP_REQUEST_HANDLE_OBJECT::ReadLoop_Fsm",
  200. "%#x",
  201. Fsm
  202. ));
  203. CFsm_ReadLoop & fsm = *Fsm;
  204. DWORD dwErr = fsm.GetError();
  205. if (fsm.GetState() == FSM_STATE_CONTINUE)
  206. {
  207. goto receive_continue;
  208. }
  209. // Set the goal for reading from the socket.
  210. fsm.m_dwReadEnd = _dwCurrentStreamPosition +
  211. ((fsm.m_dwSocketFlags & SF_NO_WAIT)? 1 : fsm.m_cbReadIn);
  212. // If app is trying to read beyond eof, limit it.
  213. if (fsm.m_dwReadEnd > _ContentLength)
  214. {
  215. fsm.m_dwReadEnd = _ContentLength;
  216. fsm.m_cbReadIn = fsm.m_dwReadEnd - _dwCurrentStreamPosition;
  217. }
  218. // Flush any data in response buffer to download file.
  219. dwErr = WriteResponseBufferToCache();
  220. if (dwErr != ERROR_SUCCESS)
  221. goto done;
  222. // Flush any data in query buffer to download file.
  223. dwErr = WriteQueryBufferToCache();
  224. if (dwErr != ERROR_SUCCESS)
  225. goto done;
  226. // BUGBUG: what if HaveReadFileExData?
  227. // Allocate receive buffer. We could optimize this to use
  228. // the client buffer or query buffer when available to avoid
  229. // reading from the file data that was just written.
  230. fsm.m_cbBuf = READLOOP_BUFSIZE;
  231. if (!(fsm.m_pBuf = (PVOID) new BYTE [fsm.m_cbBuf]))
  232. {
  233. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  234. goto done;
  235. }
  236. HANDLE hfRead;
  237. hfRead = GetDownloadFileReadHandle();
  238. if (hfRead == INVALID_HANDLE_VALUE)
  239. {
  240. dwErr = GetLastError();
  241. DEBUG_PRINT(CACHE, ERROR, ("Cache: createfile failed error=%ld\n", dwErr));
  242. goto done;
  243. }
  244. while (1)
  245. {
  246. // Calculate amount of data available for next read.
  247. if (_VirtualCacheFileSize > _dwCurrentStreamPosition)
  248. SetAvailableDataLength (_VirtualCacheFileSize - _dwCurrentStreamPosition);
  249. else
  250. SetAvailableDataLength (0);
  251. // Check if pending request can be satisfied from file.
  252. if (_EndOfFile || _VirtualCacheFileSize >= fsm.m_dwReadEnd)
  253. {
  254. INET_ASSERT (AvailableDataLength());
  255. if (fsm.m_pRead)
  256. {
  257. // The client wants us to fill the buffer.
  258. if (fsm.m_dwSocketFlags & SF_NO_WAIT)
  259. {
  260. // If the app is greedy, give it all we've got.
  261. if (fsm.m_cbReadIn > AvailableDataLength())
  262. fsm.m_cbReadIn = AvailableDataLength();
  263. }
  264. else
  265. {
  266. INET_ASSERT (fsm.m_cbReadIn <= AvailableDataLength());
  267. }
  268. }
  269. // Read the data from the file.
  270. LONG lRet;
  271. lRet = SetFilePointer
  272. (hfRead, _dwCurrentStreamPosition, NULL, FILE_BEGIN);
  273. INET_ASSERT ((DWORD) lRet == _dwCurrentStreamPosition);
  274. if (lRet == -1)
  275. {
  276. dwErr = GetLastError();
  277. goto done;
  278. }
  279. BOOL fRet;
  280. fRet = ReadFile
  281. (hfRead, fsm.m_pRead, fsm.m_cbReadIn, fsm.m_pcbReadOut, NULL);
  282. if (!fRet)
  283. {
  284. dwErr = GetLastError();
  285. goto done;
  286. }
  287. AdvanceReadPosition (*fsm.m_pcbReadOut);
  288. INET_ASSERT (dwErr == ERROR_SUCCESS);
  289. goto done;
  290. }
  291. INET_ASSERT (!_EndOfFile);
  292. INET_ASSERT (_Socket);
  293. fsm.m_cbRead = fsm.m_cbBuf;
  294. if (IsKeepAlive() && fsm.m_cbRead > _BytesInSocket)
  295. fsm.m_cbRead = _BytesInSocket;
  296. fsm.m_cbRecv = 0;
  297. // Get some more data from the socket.
  298. dwErr = _Socket->Receive
  299. (
  300. &fsm.m_pBuf, // IN OUT LPVOID* lplpBuffer,
  301. &fsm.m_cbBuf, // IN OUT LPDWORD lpdwBufferLength,
  302. &fsm.m_cbRead, // IN OUT LPDWORD lpdwBufferRemaining,
  303. &fsm.m_cbRecv, // IN OUT LPDWORD lpdwBytesReceived,
  304. 0, // IN DWORD dwExtraSpace,
  305. fsm.m_dwSocketFlags, // IN DWORD dwFlags,
  306. &_EndOfFile // OUT LPBOOL lpbEof
  307. );
  308. if (dwErr == ERROR_IO_PENDING)
  309. {
  310. if (fsm.m_dwSocketFlags & SF_NO_WAIT)
  311. {
  312. // InternetReadFileEx can set IRF_NO_WAIT. If we must go async
  313. // in this case, morph the request into a QueryDataAvailable
  314. // and app will call again to get the data after notification.
  315. fsm.m_pRead = NULL;
  316. fsm.m_cbReadIn = 1;
  317. fsm.m_pcbReadOut = NULL;
  318. }
  319. goto done;
  320. }
  321. receive_continue:
  322. if (dwErr != ERROR_SUCCESS)
  323. {
  324. DEBUG_PRINT(HTTP,
  325. ERROR,
  326. ("error %d on socket %#x\n",
  327. dwErr,
  328. _Socket->GetSocket()));
  329. goto done;
  330. }
  331. // Append data to download file.
  332. dwErr = WriteCache ((PBYTE) fsm.m_pBuf, fsm.m_cbRecv);
  333. if (dwErr != ERROR_SUCCESS)
  334. goto done;
  335. // If content length is known, check for EOF.
  336. if (IsKeepAlive())
  337. {
  338. _BytesInSocket -= fsm.m_cbRecv;
  339. if (!_BytesInSocket)
  340. _EndOfFile = TRUE;
  341. }
  342. if (_EndOfFile)
  343. {
  344. // Set handle state.
  345. SetState(HttpRequestStateReopen);
  346. if (!IsKeepAlive())
  347. CloseConnection(FALSE);
  348. SetData(FALSE);
  349. }
  350. } // end while (1)
  351. done:
  352. if (dwErr != ERROR_IO_PENDING)
  353. {
  354. delete [] fsm.m_pBuf;
  355. fsm.SetDone();
  356. if (dwErr != ERROR_SUCCESS)
  357. {
  358. DEBUG_PRINT(HTTP, ERROR, ("Readloop: Error = %d\n", dwErr));
  359. SetState(HttpRequestStateError);
  360. LocalEndCacheWrite(FALSE);
  361. }
  362. }
  363. DEBUG_LEAVE(dwErr);
  364. return dwErr;
  365. }
  366. // Called from ReadLoop to write data in response buffer to download file.
  367. DWORD HTTP_REQUEST_HANDLE_OBJECT::WriteResponseBufferToCache (VOID)
  368. {
  369. DWORD cbData = _BytesReceived - _DataOffset;
  370. if (!cbData)
  371. return ERROR_SUCCESS;
  372. DWORD dwErr = WriteCache
  373. (((LPBYTE) _ResponseBuffer) + _DataOffset, cbData);
  374. _DataOffset += cbData;
  375. DEBUG_PRINT(HTTP, ERROR, ("WriteResponseBufferToCache: Error = %d", dwErr));
  376. return dwErr;
  377. }
  378. // Called from ReadLoop to write data in query buffer to download file.
  379. DWORD HTTP_REQUEST_HANDLE_OBJECT::WriteQueryBufferToCache (VOID)
  380. {
  381. if (!_QueryBytesAvailable)
  382. return ERROR_SUCCESS;
  383. DWORD dwErr = WriteCache
  384. (((LPBYTE) _QueryBuffer) + _QueryOffset, _QueryBytesAvailable);
  385. _QueryOffset += _QueryBytesAvailable;
  386. _QueryBytesAvailable = 0;
  387. DEBUG_PRINT(HTTP, ERROR, ("WriteQueryBufferToCache: Error = %d", dwErr));
  388. return dwErr;
  389. }