Source code of Windows XP (NT5)
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.

782 lines
19 KiB

  1. /*===================================================================
  2. Microsoft IIS 5.0 (ASP)
  3. Microsoft Confidential.
  4. Copyright 1998 Microsoft Corporation. All Rights Reserved.
  5. Component: 449 negotiations w/IE
  6. File: ie449.cpp
  7. Owner: DmitryR
  8. This file contains the implementation of the 449 negotiations w/IE
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "ie449.h"
  13. #include "memchk.h"
  14. /*===================================================================
  15. Globals
  16. ===================================================================*/
  17. C449FileMgr *m_p449FileMgr = NULL;
  18. /*===================================================================
  19. Internal funcitons
  20. ===================================================================*/
  21. inline BOOL FindCookie
  22. (
  23. char *szCookiesBuf,
  24. char *szCookie,
  25. DWORD cbCookie
  26. )
  27. {
  28. char *pch = szCookiesBuf;
  29. if (pch == NULL || *pch == '\0')
  30. return FALSE;
  31. while (1)
  32. {
  33. if (strnicmp(pch, szCookie, cbCookie) == 0)
  34. {
  35. if (pch[cbCookie] == '=') // next char must be '='
  36. return TRUE;
  37. }
  38. // next cookie
  39. pch = strchr(pch, ';');
  40. if (pch == NULL)
  41. break;
  42. while (*(++pch) == ' ') // skip ; and any spaces
  43. ;
  44. }
  45. return FALSE;
  46. }
  47. /*===================================================================
  48. The API
  49. ===================================================================*/
  50. /*===================================================================
  51. Init449
  52. ===================================================================*/
  53. HRESULT Init449()
  54. {
  55. // init hash table
  56. m_p449FileMgr = new C449FileMgr;
  57. if (m_p449FileMgr == NULL)
  58. return E_OUTOFMEMORY;
  59. HRESULT hr = m_p449FileMgr->Init();
  60. if (FAILED(hr))
  61. {
  62. delete m_p449FileMgr;
  63. m_p449FileMgr = NULL;
  64. return hr;
  65. }
  66. return S_OK;
  67. }
  68. /*===================================================================
  69. UnInit449
  70. ===================================================================*/
  71. HRESULT UnInit449()
  72. {
  73. if (m_p449FileMgr != NULL)
  74. {
  75. delete m_p449FileMgr;
  76. m_p449FileMgr = NULL;
  77. }
  78. return S_OK;
  79. }
  80. /*===================================================================
  81. Create449Cookie
  82. Get an existing 449 cookie from cache or create a new one
  83. Parameters
  84. szName cookie name
  85. szFile script file
  86. pp449 [out] the cookie
  87. Returns
  88. HRESULT
  89. ===================================================================*/
  90. HRESULT Create449Cookie
  91. (
  92. char *szName,
  93. TCHAR *szFile,
  94. C449Cookie **pp449
  95. )
  96. {
  97. HRESULT hr = S_OK;
  98. // Get the file first
  99. C449File *pFile = NULL;
  100. hr = m_p449FileMgr->GetFile(szFile, &pFile);
  101. if (FAILED(hr))
  102. return hr;
  103. // Create the cookie
  104. hr = C449Cookie::Create449Cookie(szName, pFile, pp449);
  105. if (FAILED(hr))
  106. pFile->Release(); // GetFile gave it addref'd
  107. return hr;
  108. }
  109. /*===================================================================
  110. Do449Processing
  111. Check
  112. if the browser is IE5+
  113. there's no echo-reply: header
  114. all the cookies are present
  115. Construct and send 449 response if needed
  116. When the response is sent, HitObj is marked as 'done with session'
  117. Parameters
  118. pHitObj the request
  119. rgpCookies array of cookie requirements
  120. cCookies number of cookie requirements
  121. Returns
  122. HRESULT
  123. ===================================================================*/
  124. HRESULT Do449Processing
  125. (
  126. CHitObj *pHitObj,
  127. C449Cookie **rgpCookies,
  128. DWORD cCookies
  129. )
  130. {
  131. HRESULT hr = S_OK;
  132. if (cCookies == 0)
  133. return hr;
  134. //////////////////////////////////////////
  135. // check the browser
  136. BOOL fBrowser = FALSE;
  137. char *szBrowser = pHitObj->PIReq()->QueryPszUserAgent();
  138. if (szBrowser == NULL || szBrowser[0] == '\0')
  139. return S_OK; // bad browser
  140. char *szMSIE = strstr(szBrowser, "MSIE ");
  141. if (szMSIE)
  142. {
  143. char chVersion = szMSIE[5];
  144. if (chVersion >= '5' && chVersion <= '9')
  145. fBrowser = TRUE;
  146. }
  147. #ifdef TINYGET449
  148. if (strcmp(szBrowser, "WBCLI") == 0)
  149. fBrowser = TRUE;
  150. #endif
  151. if (!fBrowser) // bad browser
  152. return S_OK;
  153. //////////////////////////////////////////
  154. // check the cookies
  155. char *szCookie = pHitObj->PIReq()->QueryPszCookie();
  156. // collect the arrays of pointers and sizes for not found cookies.
  157. // arrays size to at most number of cookies in the template.
  158. DWORD cNotFound = 0;
  159. DWORD cbNotFound = 0;
  160. STACK_BUFFER( tempCookiePtrs, 128 );
  161. STACK_BUFFER( tempCookieCBs, 128 );
  162. if (!tempCookiePtrs.Resize(cCookies * sizeof(void *))
  163. || !tempCookieCBs.Resize(cCookies * sizeof(DWORD))) {
  164. return E_OUTOFMEMORY;
  165. }
  166. void **rgpvNotFound = (void **)tempCookiePtrs.QueryPtr();
  167. DWORD *rgcbNotFound = (DWORD *)tempCookieCBs.QueryPtr();
  168. for (DWORD i = 0; SUCCEEDED(hr) && (i < cCookies); i++)
  169. {
  170. if (!FindCookie(szCookie, rgpCookies[i]->SzCookie(), rgpCookies[i]->CbCookie()))
  171. {
  172. // cookie not found -- append to the list
  173. hr = rgpCookies[i]->LoadFile();
  174. if (SUCCEEDED(hr)) // ignore bad files
  175. {
  176. rgpvNotFound[cNotFound] = rgpCookies[i]->SzBuffer();
  177. rgcbNotFound[cNotFound] = rgpCookies[i]->CbBuffer();
  178. cbNotFound += rgpCookies[i]->CbBuffer();
  179. cNotFound++;
  180. }
  181. }
  182. }
  183. if (!SUCCEEDED(hr))
  184. return hr;
  185. if (cNotFound == 0)
  186. return S_OK; // everything's found
  187. //////////////////////////////////////////
  188. // check echo-reply header
  189. char szEcho[80];
  190. DWORD dwEchoLen = sizeof(szEcho);
  191. if (pHitObj->PIReq()->GetServerVariableA("HTTP_MS_ECHO_REPLY", szEcho, &dwEchoLen)
  192. || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  193. {
  194. return S_OK; // already in response cycle
  195. }
  196. //////////////////////////////////////////
  197. // send the 449 response
  198. CResponse::SyncWriteBlocks
  199. (
  200. pHitObj->PIReq(), // WAM_EXEC_INFO
  201. cNotFound, // number of blocks
  202. cbNotFound, // total number of bytes in blocks
  203. rgpvNotFound, // array of block pointers
  204. rgcbNotFound, // array of block sizes
  205. NULL, // text/html
  206. "449 Retry with", // status
  207. "ms-echo-request: execute opaque=\"0\" location=\"BODY\"\r\n" // extra header
  208. );
  209. //////////////////////////////////////////
  210. // tell HitObj no to write anything else
  211. if (pHitObj->FExecuting()) // on MTS worker thread?
  212. {
  213. DWORD dwRequestStatus = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
  214. pHitObj->PIReq()->ServerSupportFunction
  215. (
  216. HSE_REQ_DONE_WITH_SESSION,
  217. &dwRequestStatus,
  218. 0,
  219. NULL
  220. );
  221. }
  222. pHitObj->SetDoneWithSession();
  223. return S_OK;
  224. }
  225. /*===================================================================
  226. Do449ChangeNotification
  227. Change notification processing
  228. Parameters
  229. szFile file changed or NULL for all
  230. Returns
  231. HRESULT
  232. ===================================================================*/
  233. HRESULT Do449ChangeNotification
  234. (
  235. TCHAR *szFile
  236. )
  237. {
  238. if (szFile)
  239. return m_p449FileMgr->Flush(szFile);
  240. else
  241. return m_p449FileMgr->FlushAll();
  242. }
  243. /*===================================================================
  244. Class C449File
  245. ===================================================================*/
  246. /*===================================================================
  247. C449File::C449File
  248. Constructor
  249. ===================================================================*/
  250. C449File::C449File()
  251. {
  252. m_cRefs = 0;
  253. m_fNeedLoad = 0;
  254. m_szFile = NULL;
  255. m_szBuffer = NULL;
  256. m_cbBuffer = 0;
  257. m_pDME = NULL;
  258. }
  259. /*===================================================================
  260. C449File::~C449File
  261. Destructor
  262. ===================================================================*/
  263. C449File::~C449File()
  264. {
  265. Assert(m_cRefs == 0);
  266. if (m_szFile)
  267. free(m_szFile);
  268. if (m_szBuffer)
  269. free(m_szBuffer);
  270. if (m_pDME)
  271. m_pDME->Release();
  272. }
  273. /*===================================================================
  274. C449File::Init
  275. Init strings,
  276. Load file for the first time,
  277. Start change notifications
  278. ===================================================================*/
  279. HRESULT C449File::Init
  280. (
  281. TCHAR *szFile
  282. )
  283. {
  284. // remember the name
  285. m_szFile = StringDup(szFile);
  286. if (m_szFile == NULL)
  287. return E_OUTOFMEMORY;
  288. // init link element
  289. CLinkElem::Init(m_szFile, _tcslen(m_szFile)*sizeof(TCHAR));
  290. // load
  291. m_fNeedLoad = 1;
  292. HRESULT hr = Load();
  293. if (FAILED(hr))
  294. return hr;
  295. // start directory notifications
  296. TCHAR *pch = _tcsrchr(m_szFile, _T('\\')); // last backslash
  297. if (pch == NULL)
  298. return E_FAIL; // bogus filename?
  299. CASPDirMonitorEntry *pDME = NULL;
  300. *pch = _T('\0');
  301. RegisterASPDirMonitorEntry(m_szFile, &pDME);
  302. *pch = _T('\\');
  303. m_pDME = pDME;
  304. // done
  305. return S_OK;
  306. }
  307. /*===================================================================
  308. C449File::Load
  309. Load the file if needed
  310. ===================================================================*/
  311. HRESULT C449File::Load()
  312. {
  313. HRESULT hr = S_OK;
  314. HANDLE hFile = INVALID_HANDLE_VALUE;
  315. HANDLE hMap = NULL;
  316. BYTE *pbBytes = NULL;
  317. DWORD dwSize = 0;
  318. // check if this thread needs to load the file
  319. if (InterlockedExchange(&m_fNeedLoad, 0) == 0)
  320. return S_OK;
  321. // cleanup the existing data if any
  322. if (m_szBuffer)
  323. free(m_szBuffer);
  324. m_szBuffer = NULL;
  325. m_cbBuffer = 0;
  326. // open the file
  327. if (SUCCEEDED(hr))
  328. {
  329. hFile = CreateFile(
  330. m_szFile,
  331. GENERIC_READ, // access (read-write) mode
  332. FILE_SHARE_READ, // share mode
  333. NULL, // pointer to security descriptor
  334. OPEN_EXISTING, // how to create
  335. FILE_ATTRIBUTE_NORMAL, // file attributes
  336. NULL // handle to file with attributes to copy
  337. );
  338. if (hFile == INVALID_HANDLE_VALUE)
  339. hr = E_FAIL;
  340. }
  341. // get file size
  342. if (SUCCEEDED(hr))
  343. {
  344. dwSize = GetFileSize(hFile, NULL);
  345. if (dwSize == 0 || dwSize == 0xFFFFFFFF)
  346. hr = E_FAIL;
  347. }
  348. // create mapping
  349. if (SUCCEEDED(hr))
  350. {
  351. hMap = CreateFileMapping(
  352. hFile, // handle to file to map
  353. NULL, // optional security attributes
  354. PAGE_READONLY, // protection for mapping object
  355. 0, // high-order 32 bits of object size
  356. 0, // low-order 32 bits of object size
  357. NULL // name of file-mapping object
  358. );
  359. if (hMap == NULL)
  360. hr = E_FAIL;
  361. }
  362. // map the file
  363. if (SUCCEEDED(hr))
  364. {
  365. pbBytes = (BYTE *)MapViewOfFile(
  366. hMap, // file-mapping object to map into address space
  367. FILE_MAP_READ, // access mode
  368. 0, // high-order 32 bits of file offset
  369. 0, // low-order 32 bits of file offset
  370. 0 // number of bytes to map
  371. );
  372. if (pbBytes == NULL)
  373. hr = E_FAIL;
  374. }
  375. // remember the bytes
  376. if (SUCCEEDED(hr))
  377. {
  378. m_szBuffer = (char *)malloc(dwSize);
  379. if (m_szBuffer != NULL)
  380. {
  381. memcpy(m_szBuffer, pbBytes, dwSize);
  382. m_cbBuffer = dwSize;
  383. }
  384. else
  385. {
  386. hr = E_OUTOFMEMORY;
  387. }
  388. }
  389. // cleanup
  390. if (pbBytes != NULL)
  391. UnmapViewOfFile(pbBytes);
  392. if (hMap != NULL)
  393. CloseHandle(hMap);
  394. if (hFile != INVALID_HANDLE_VALUE)
  395. CloseHandle(hFile);
  396. if (!SUCCEEDED(hr))
  397. SetNeedLoad();
  398. return hr;
  399. }
  400. /*===================================================================
  401. C449File::Create449File
  402. static constructor
  403. ===================================================================*/
  404. HRESULT C449File::Create449File
  405. (
  406. TCHAR *szFile,
  407. C449File **ppFile
  408. )
  409. {
  410. HRESULT hr = S_OK;
  411. C449File *pFile = new C449File;
  412. if (pFile == NULL)
  413. hr = E_OUTOFMEMORY;
  414. if (SUCCEEDED(hr))
  415. {
  416. hr = pFile->Init(szFile);
  417. }
  418. if (SUCCEEDED(hr))
  419. {
  420. pFile->AddRef();
  421. *ppFile = pFile;
  422. }
  423. else if (pFile)
  424. {
  425. delete pFile;
  426. }
  427. return hr;
  428. }
  429. /*===================================================================
  430. C449File::QueryInterface
  431. C449File::AddRef
  432. C449File::Release
  433. IUnknown members for C449File object.
  434. ===================================================================*/
  435. STDMETHODIMP C449File::QueryInterface(REFIID riid, VOID **ppv)
  436. {
  437. // should never be called
  438. Assert(FALSE);
  439. *ppv = NULL;
  440. return E_NOINTERFACE;
  441. }
  442. STDMETHODIMP_(ULONG) C449File::AddRef()
  443. {
  444. return InterlockedIncrement(&m_cRefs);
  445. }
  446. STDMETHODIMP_(ULONG) C449File::Release()
  447. {
  448. LONG cRefs = InterlockedDecrement(&m_cRefs);
  449. if (cRefs)
  450. return cRefs;
  451. delete this;
  452. return 0;
  453. }
  454. /*===================================================================
  455. Class C449FileMgr
  456. ===================================================================*/
  457. /*===================================================================
  458. C449FileMgr::C449FileMgr
  459. Constructor
  460. ===================================================================*/
  461. C449FileMgr::C449FileMgr()
  462. {
  463. INITIALIZE_CRITICAL_SECTION(&m_csLock);
  464. }
  465. /*===================================================================
  466. C449FileMgr::~C449FileMgr
  467. Destructor
  468. ===================================================================*/
  469. C449FileMgr::~C449FileMgr()
  470. {
  471. FlushAll();
  472. m_ht449Files.UnInit();
  473. DeleteCriticalSection(&m_csLock);
  474. }
  475. /*===================================================================
  476. C449FileMgr::Init
  477. Initialization
  478. ===================================================================*/
  479. HRESULT C449FileMgr::Init()
  480. {
  481. return m_ht449Files.Init(199);
  482. }
  483. /*===================================================================
  484. C449FileMgr::GetFile
  485. Find file in the hash table, or create a new one
  486. ===================================================================*/
  487. HRESULT C449FileMgr::GetFile
  488. (
  489. TCHAR *szFile,
  490. C449File **ppFile
  491. )
  492. {
  493. C449File *pFile = NULL;
  494. CLinkElem *pElem;
  495. Lock();
  496. pElem = m_ht449Files.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR));
  497. if (pElem)
  498. {
  499. // found
  500. pFile = static_cast<C449File *>(pElem);
  501. if (!SUCCEEDED(pFile->Load()))
  502. pFile = NULL;
  503. else
  504. pFile->AddRef(); // 1 ref to hand out
  505. }
  506. else if (SUCCEEDED(C449File::Create449File(szFile, &pFile)))
  507. {
  508. if (m_ht449Files.AddElem(pFile))
  509. pFile->AddRef(); // 1 for hash table + 1 to hand out
  510. }
  511. UnLock();
  512. *ppFile = pFile;
  513. return (pFile != NULL) ? S_OK : E_FAIL;
  514. }
  515. /*===================================================================
  516. C449FileMgr::Flush
  517. Change notification for a single file
  518. ===================================================================*/
  519. HRESULT C449FileMgr::Flush
  520. (
  521. TCHAR *szFile
  522. )
  523. {
  524. Lock();
  525. CLinkElem *pElem = m_ht449Files.FindElem(szFile, _tcslen(szFile)*sizeof(TCHAR));
  526. if (pElem)
  527. {
  528. C449File *pFile = static_cast<C449File *>(pElem);
  529. pFile->SetNeedLoad(); // next time reload
  530. }
  531. UnLock();
  532. return S_OK;
  533. }
  534. /*===================================================================
  535. C449FileMgr::FlushAll
  536. Remove all files
  537. FlushAll is always together with template flush
  538. ===================================================================*/
  539. HRESULT C449FileMgr::FlushAll()
  540. {
  541. // Unlink from hash table first
  542. Lock();
  543. CLinkElem *pElem = m_ht449Files.Head();
  544. m_ht449Files.ReInit();
  545. UnLock();
  546. // Walk the list to remove all
  547. while (pElem)
  548. {
  549. C449File *pFile = static_cast<C449File *>(pElem);
  550. pElem = pElem->m_pNext;
  551. pFile->Release();
  552. }
  553. return S_OK;
  554. }
  555. /*===================================================================
  556. Class C449Cookie
  557. ===================================================================*/
  558. /*===================================================================
  559. C449Cookie::C449Cookie
  560. Constructor
  561. ===================================================================*/
  562. C449Cookie::C449Cookie()
  563. {
  564. m_cRefs = 0;
  565. m_szName = NULL;
  566. m_cbName = 0;
  567. m_pFile = NULL;
  568. }
  569. /*===================================================================
  570. C449Cookie::~C449Cookie
  571. Destructor
  572. ===================================================================*/
  573. C449Cookie::~C449Cookie()
  574. {
  575. Assert(m_cRefs == 0);
  576. if (m_szName)
  577. free(m_szName);
  578. if (m_pFile)
  579. m_pFile->Release();
  580. }
  581. /*===================================================================
  582. C449Cookie::Init
  583. Initialize
  584. ===================================================================*/
  585. HRESULT C449Cookie::Init
  586. (
  587. char *szName,
  588. C449File *pFile
  589. )
  590. {
  591. m_szName = StringDupA(szName);
  592. if (m_szName == NULL)
  593. return E_OUTOFMEMORY;
  594. m_cbName = strlen(m_szName);
  595. m_pFile = pFile;
  596. return S_OK;
  597. }
  598. /*===================================================================
  599. C449Cookie::Create449Cookie
  600. static constructor
  601. ===================================================================*/
  602. HRESULT C449Cookie::Create449Cookie
  603. (
  604. char *szName,
  605. C449File *pFile,
  606. C449Cookie **pp449Cookie
  607. )
  608. {
  609. HRESULT hr = S_OK;
  610. C449Cookie *pCookie = new C449Cookie;
  611. if (pCookie == NULL)
  612. hr = E_OUTOFMEMORY;
  613. if (SUCCEEDED(hr))
  614. {
  615. hr = pCookie->Init(szName, pFile);
  616. }
  617. if (SUCCEEDED(hr))
  618. {
  619. pCookie->AddRef();
  620. *pp449Cookie = pCookie;
  621. }
  622. else if (pCookie)
  623. {
  624. delete pCookie;
  625. }
  626. return hr;
  627. }
  628. /*===================================================================
  629. C449Cookie::QueryInterface
  630. C449Cookie::AddRef
  631. C449Cookie::Release
  632. IUnknown members for C449Cookie object.
  633. ===================================================================*/
  634. STDMETHODIMP C449Cookie::QueryInterface(REFIID riid, VOID **ppv)
  635. {
  636. // should never be called
  637. Assert(FALSE);
  638. *ppv = NULL;
  639. return E_NOINTERFACE;
  640. }
  641. STDMETHODIMP_(ULONG) C449Cookie::AddRef()
  642. {
  643. return InterlockedIncrement(&m_cRefs);
  644. }
  645. STDMETHODIMP_(ULONG) C449Cookie::Release()
  646. {
  647. LONG cRefs = InterlockedDecrement(&m_cRefs);
  648. if (cRefs)
  649. return cRefs;
  650. delete this;
  651. return 0;
  652. }