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.

1608 lines
54 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: CIsapiReqInfo implementation....
  6. File: IsapiReq.cpp
  7. Owner: AndyMorr
  8. ===================================================================*/
  9. #include "denpre.h"
  10. #pragma hdrstop
  11. #include "memchk.h"
  12. // undef these here so that we can call the WXI and ECB functions with
  13. // the same name and not be victims of the substituition.
  14. #undef MapUrlToPath
  15. #undef GetCustomError
  16. #undef GetAspMDData
  17. #undef GetAspMDAllData
  18. #undef GetServerVariable
  19. LONG g_nOutstandingAsyncWrites = 0;
  20. /*===================================================================
  21. CIsapiReqInfo::CIsapiReqInfo
  22. ===================================================================*/
  23. CIsapiReqInfo::CIsapiReqInfo(EXTENSION_CONTROL_BLOCK *pECB) {
  24. m_cRefs = 1;
  25. m_fApplnMDPathAInited = 0;
  26. m_fApplnMDPathWInited = 0;
  27. m_fAppPoolIdAInited = 0;
  28. m_fAppPoolIdWInited = 0;
  29. m_fPathInfoWInited = 0;
  30. m_fPathTranslatedWInited = 0;
  31. m_fCookieInited = 0;
  32. m_fUserAgentInited = 0;
  33. m_fInstanceIDInited = 0;
  34. m_fVersionInited = 0;
  35. m_fFKeepConnInited = 0;
  36. m_fPendSendCSInited = 0;
  37. m_fIOCompletionRegistered = 0;
  38. m_fHeadersWritten = 0;
  39. m_dwInstanceID = 0;
  40. m_dwVersionMajor = 1;
  41. m_dwVersionMinor = 0;
  42. m_cchQueryString = -1;
  43. m_cchApplnMDPathA = -1;
  44. m_cchPathTranslatedA = -1;
  45. m_cchPathInfoA = -1;
  46. m_cchApplnMDPathW = -1;
  47. m_cchPathTranslatedW = -1;
  48. m_cchPathInfoW = -1;
  49. m_cchAppPoolIdW = -1;
  50. m_cchAppPoolIdA = -1;
  51. m_fKeepConn = FALSE;
  52. m_pIAdminBase = NULL;
  53. m_pECB = pECB;
  54. m_dwRequestStatus = HSE_STATUS_SUCCESS;
  55. m_dwAsyncError = NOERROR;
  56. }
  57. /*===================================================================
  58. CIsapiReqInfo::~CIsapiReqInfo
  59. ===================================================================*/
  60. CIsapiReqInfo::~CIsapiReqInfo() {
  61. Assert(m_listPendingSends.FIsEmpty());
  62. if (m_pIAdminBase != NULL) {
  63. m_pIAdminBase->Release();
  64. m_pIAdminBase = NULL;
  65. }
  66. if (m_fPendSendCSInited)
  67. DeleteCriticalSection(&m_csPendingSendCS);
  68. if (m_pECB) {
  69. DWORD dwRequestStatus = HSE_STATUS_SUCCESS;
  70. if ((m_pECB->dwHttpStatusCode >= 500) && (m_pECB->dwHttpStatusCode < 600))
  71. dwRequestStatus = HSE_STATUS_ERROR;
  72. else if (m_dwRequestStatus == HSE_STATUS_PENDING)
  73. dwRequestStatus = m_dwAsyncError ? HSE_STATUS_ERROR : HSE_STATUS_SUCCESS;
  74. ServerSupportFunction(HSE_REQ_DONE_WITH_SESSION,
  75. &dwRequestStatus,
  76. NULL,
  77. NULL);
  78. }
  79. }
  80. /*===================================================================
  81. CIsapiReqInfo::QueryPszQueryString
  82. ===================================================================*/
  83. LPSTR CIsapiReqInfo::QueryPszQueryString()
  84. {
  85. return m_pECB->lpszQueryString;
  86. }
  87. /*===================================================================
  88. CIsapiReqInfo::QueryCchQueryString
  89. ===================================================================*/
  90. DWORD CIsapiReqInfo::QueryCchQueryString()
  91. {
  92. if (m_cchQueryString == -1) {
  93. m_cchQueryString = QueryPszQueryString() ? strlen(QueryPszQueryString()) : 0;
  94. }
  95. return m_cchQueryString;
  96. }
  97. /*===================================================================
  98. CIsapiReqInfo::QueryPszApplnMDPathA
  99. ===================================================================*/
  100. LPSTR CIsapiReqInfo::QueryPszApplnMDPathA()
  101. {
  102. if (m_fApplnMDPathAInited == FALSE) {
  103. *((LPSTR)m_ApplnMDPathA.QueryPtr()) = '\0';
  104. m_fApplnMDPathAInited = InternalGetServerVariable("APPL_MD_PATH", &m_ApplnMDPathA);
  105. }
  106. ASSERT(m_fApplnMDPathAInited);
  107. return (LPSTR)m_ApplnMDPathA.QueryPtr();
  108. }
  109. /*===================================================================
  110. CIsapiReqInfo::QueryCchApplnMDPathA
  111. ===================================================================*/
  112. DWORD CIsapiReqInfo::QueryCchApplnMDPathA()
  113. {
  114. if (m_cchApplnMDPathA == -1) {
  115. m_cchApplnMDPathA = QueryPszApplnMDPathA()
  116. ? strlen(QueryPszApplnMDPathA())
  117. : 0;
  118. }
  119. return(m_cchApplnMDPathA);
  120. }
  121. /*===================================================================
  122. CIsapiReqInfo::QueryPszApplnMDPathW
  123. ===================================================================*/
  124. LPWSTR CIsapiReqInfo::QueryPszApplnMDPathW()
  125. {
  126. if (m_fApplnMDPathWInited == FALSE) {
  127. *((LPWSTR)m_ApplnMDPathW.QueryPtr()) = L'\0';
  128. m_fApplnMDPathWInited = InternalGetServerVariable("UNICODE_APPL_MD_PATH", &m_ApplnMDPathW);
  129. }
  130. ASSERT(m_fApplnMDPathWInited);
  131. return (LPWSTR)m_ApplnMDPathW.QueryPtr();
  132. }
  133. /*===================================================================
  134. CIsapiReqInfo::QueryCchApplnMDPathW
  135. ===================================================================*/
  136. DWORD CIsapiReqInfo::QueryCchApplnMDPathW()
  137. {
  138. if (m_cchApplnMDPathW == -1) {
  139. m_cchApplnMDPathW = QueryPszApplnMDPathW()
  140. ? wcslen(QueryPszApplnMDPathW())
  141. : 0;
  142. }
  143. return(m_cchApplnMDPathW);
  144. }
  145. /*===================================================================
  146. CIsapiReqInfo::QueryPszAppPoolIdA
  147. ===================================================================*/
  148. LPSTR CIsapiReqInfo::QueryPszAppPoolIdA()
  149. {
  150. if (m_fAppPoolIdAInited == FALSE) {
  151. *((LPSTR)m_AppPoolIdA.QueryPtr()) = '\0';
  152. m_fAppPoolIdAInited = InternalGetServerVariable("APP_POOL_ID", &m_AppPoolIdA);
  153. }
  154. ASSERT(m_fAppPoolIdAInited);
  155. return (LPSTR)m_AppPoolIdA.QueryPtr();
  156. }
  157. /*===================================================================
  158. CIsapiReqInfo::QueryCchAppPoolIdA
  159. ===================================================================*/
  160. DWORD CIsapiReqInfo::QueryCchAppPoolIdA()
  161. {
  162. if (m_cchAppPoolIdA == -1) {
  163. m_cchAppPoolIdA = QueryPszAppPoolIdA()
  164. ? strlen(QueryPszAppPoolIdA())
  165. : 0;
  166. }
  167. return(m_cchAppPoolIdA);
  168. }
  169. /*===================================================================
  170. CIsapiReqInfo::QueryPszAppPoolIdW
  171. ===================================================================*/
  172. LPWSTR CIsapiReqInfo::QueryPszAppPoolIdW()
  173. {
  174. if (m_fAppPoolIdWInited == FALSE) {
  175. *((LPWSTR)m_AppPoolIdW.QueryPtr()) = L'\0';
  176. m_fAppPoolIdWInited = InternalGetServerVariable("UNICODE_APP_POOL_ID", &m_AppPoolIdW);
  177. }
  178. ASSERT(m_fAppPoolIdWInited);
  179. return (LPWSTR)m_AppPoolIdW.QueryPtr();
  180. }
  181. /*===================================================================
  182. CIsapiReqInfo::QueryCchAppPoolIdW
  183. ===================================================================*/
  184. DWORD CIsapiReqInfo::QueryCchAppPoolIdW()
  185. {
  186. if (m_cchAppPoolIdW == -1) {
  187. m_cchAppPoolIdW = QueryPszAppPoolIdW()
  188. ? wcslen(QueryPszAppPoolIdW())
  189. : 0;
  190. }
  191. return(m_cchAppPoolIdW);
  192. }
  193. /*===================================================================
  194. CIsapiReqInfo::QueryPszPathInfoA
  195. ===================================================================*/
  196. LPSTR CIsapiReqInfo::QueryPszPathInfoA()
  197. {
  198. return m_pECB->lpszPathInfo;
  199. }
  200. /*===================================================================
  201. CIsapiReqInfo::QueryCchPathInfoA
  202. ===================================================================*/
  203. DWORD CIsapiReqInfo::QueryCchPathInfoA()
  204. {
  205. if (m_cchPathInfoA == -1) {
  206. m_cchPathInfoA = QueryPszPathInfoA()
  207. ? strlen(QueryPszPathInfoA())
  208. : 0;
  209. }
  210. return m_cchPathInfoA;
  211. }
  212. /*===================================================================
  213. CIsapiReqInfo::QueryPszPathInfoW
  214. ===================================================================*/
  215. LPWSTR CIsapiReqInfo::QueryPszPathInfoW()
  216. {
  217. if (m_fPathInfoWInited == FALSE) {
  218. *((LPWSTR)m_PathInfoW.QueryPtr()) = L'\0';
  219. m_fPathInfoWInited = InternalGetServerVariable("UNICODE_PATH_INFO", &m_PathInfoW);
  220. }
  221. ASSERT(m_fPathInfoWInited);
  222. return (LPWSTR)m_PathInfoW.QueryPtr();
  223. }
  224. /*===================================================================
  225. CIsapiReqInfo::QueryCchPathInfoW
  226. ===================================================================*/
  227. DWORD CIsapiReqInfo::QueryCchPathInfoW()
  228. {
  229. if (m_cchPathInfoW == -1) {
  230. m_cchPathInfoW = QueryPszPathInfoW()
  231. ? wcslen(QueryPszPathInfoW())
  232. : 0;
  233. }
  234. return m_cchPathInfoW;
  235. }
  236. /*===================================================================
  237. CIsapiReqInfo::QueryPszPathTranslatedA
  238. ===================================================================*/
  239. LPSTR CIsapiReqInfo::QueryPszPathTranslatedA()
  240. {
  241. return m_pECB->lpszPathTranslated;
  242. }
  243. /*===================================================================
  244. CIsapiReqInfo::QueryCchPathTranslatedA
  245. ===================================================================*/
  246. DWORD CIsapiReqInfo::QueryCchPathTranslatedA()
  247. {
  248. if (m_cchPathTranslatedA == -1) {
  249. m_cchPathTranslatedA = QueryPszPathTranslatedA()
  250. ? strlen(QueryPszPathTranslatedA())
  251. : 0;
  252. }
  253. return m_cchPathTranslatedA;
  254. }
  255. /*===================================================================
  256. CIsapiReqInfo::QueryPszPathTranslatedW
  257. ===================================================================*/
  258. LPWSTR CIsapiReqInfo::QueryPszPathTranslatedW()
  259. {
  260. if (m_fPathTranslatedWInited == FALSE) {
  261. *((LPWSTR)m_PathTranslatedW.QueryPtr()) = L'\0';
  262. m_fPathTranslatedWInited = InternalGetServerVariable("UNICODE_PATH_TRANSLATED", &m_PathTranslatedW);
  263. }
  264. return (LPWSTR)m_PathTranslatedW.QueryPtr();
  265. }
  266. /*===================================================================
  267. CIsapiReqInfo::QueryCchPathTranslatedW
  268. ===================================================================*/
  269. DWORD CIsapiReqInfo::QueryCchPathTranslatedW()
  270. {
  271. if (m_cchPathTranslatedW == -1) {
  272. m_cchPathTranslatedW = QueryPszPathTranslatedW()
  273. ? wcslen(QueryPszPathTranslatedW())
  274. : 0;
  275. }
  276. return m_cchPathTranslatedW;
  277. }
  278. /*===================================================================
  279. CIsapiReqInfo::QueryPszCookie
  280. ===================================================================*/
  281. LPSTR CIsapiReqInfo::QueryPszCookie()
  282. {
  283. if (m_fCookieInited == FALSE) {
  284. *((LPSTR)m_Cookie.QueryPtr()) = '\0';
  285. InternalGetServerVariable("HTTP_COOKIE", &m_Cookie);
  286. m_fCookieInited = TRUE;
  287. }
  288. return (LPSTR)m_Cookie.QueryPtr();
  289. }
  290. /*===================================================================
  291. CIsapiReqInfo::SetDwHttpStatusCode
  292. ===================================================================*/
  293. VOID CIsapiReqInfo::SetDwHttpStatusCode(DWORD dwStatus)
  294. {
  295. m_pECB->dwHttpStatusCode = dwStatus;
  296. }
  297. /*===================================================================
  298. CIsapiReqInfo::QueryPbData
  299. ===================================================================*/
  300. LPBYTE CIsapiReqInfo::QueryPbData()
  301. {
  302. return m_pECB->lpbData;
  303. }
  304. /*===================================================================
  305. CIsapiReqInfo::QueryCbAvailable
  306. ===================================================================*/
  307. DWORD CIsapiReqInfo::QueryCbAvailable()
  308. {
  309. return m_pECB->cbAvailable;
  310. }
  311. /*===================================================================
  312. CIsapiReqInfo::QueryCbTotalBytes
  313. ===================================================================*/
  314. DWORD CIsapiReqInfo::QueryCbTotalBytes()
  315. {
  316. return m_pECB->cbTotalBytes;
  317. }
  318. /*===================================================================
  319. CIsapiReqInfo::QueryPszContentType
  320. ===================================================================*/
  321. LPSTR CIsapiReqInfo::QueryPszContentType()
  322. {
  323. return m_pECB->lpszContentType;
  324. }
  325. /*===================================================================
  326. CIsapiReqInfo::QueryPszMethod
  327. ===================================================================*/
  328. LPSTR CIsapiReqInfo::QueryPszMethod()
  329. {
  330. return m_pECB->lpszMethod;
  331. }
  332. /*===================================================================
  333. CIsapiReqInfo::QueryPszUserAgent
  334. ===================================================================*/
  335. LPSTR CIsapiReqInfo::QueryPszUserAgent()
  336. {
  337. if (m_fUserAgentInited == FALSE) {
  338. *((LPSTR)m_UserAgent.QueryPtr()) = '\0';
  339. InternalGetServerVariable("HTTP_USER_AGENT", &m_UserAgent);
  340. }
  341. return (LPSTR)m_UserAgent.QueryPtr();
  342. }
  343. /*===================================================================
  344. CIsapiReqInfo::QueryInstanceId
  345. ===================================================================*/
  346. DWORD CIsapiReqInfo::QueryInstanceId()
  347. {
  348. if (m_fInstanceIDInited == FALSE) {
  349. BUFFER instanceID;
  350. m_fInstanceIDInited = InternalGetServerVariable("INSTANCE_ID", &instanceID);
  351. if (m_fInstanceIDInited == TRUE) {
  352. m_dwInstanceID = atoi((char *)instanceID.QueryPtr());
  353. }
  354. else {
  355. m_dwInstanceID = 1;
  356. }
  357. }
  358. return m_dwInstanceID;
  359. }
  360. /*===================================================================
  361. CIsapiReqInfo::IsChild
  362. ===================================================================*/
  363. BOOL CIsapiReqInfo::IsChild()
  364. {
  365. // BUGBUG: This needs to be implemented
  366. return FALSE;
  367. }
  368. /*===================================================================
  369. CIsapiReqInfo::FInPool
  370. ===================================================================*/
  371. BOOL CIsapiReqInfo::FInPool()
  372. {
  373. DWORD dwAppFlag;
  374. if (ServerSupportFunction(HSE_REQ_IS_IN_PROCESS,
  375. &dwAppFlag,
  376. NULL,
  377. NULL) == FALSE) {
  378. // BUGBUG: Need to enable this Assert in future builds.
  379. //Assert(0);
  380. // if error, the best we can do is return TRUE here so
  381. // that ASP picks up its settings from the service level
  382. return TRUE;
  383. }
  384. return !(dwAppFlag == HSE_APP_FLAG_ISOLATED_OOP);
  385. }
  386. /*===================================================================
  387. CIsapiReqInfo::QueryHttpVersionMajor
  388. ===================================================================*/
  389. DWORD CIsapiReqInfo::QueryHttpVersionMajor()
  390. {
  391. InitVersionInfo();
  392. return m_dwVersionMajor;
  393. }
  394. /*===================================================================
  395. CIsapiReqInfo::QueryHttpVersionMinor
  396. ===================================================================*/
  397. DWORD CIsapiReqInfo::QueryHttpVersionMinor()
  398. {
  399. InitVersionInfo();
  400. return m_dwVersionMinor;
  401. }
  402. /*===================================================================
  403. CIsapiReqInfo::GetAspMDData
  404. ===================================================================*/
  405. HRESULT CIsapiReqInfo::GetAspMDDataA(CHAR * pszMDPath,
  406. DWORD dwMDIdentifier,
  407. DWORD dwMDAttributes,
  408. DWORD dwMDUserType,
  409. DWORD dwMDDataType,
  410. DWORD dwMDDataLen,
  411. DWORD dwMDDataTag,
  412. unsigned char * pbMDData,
  413. DWORD * pdwRequiredBufferSize)
  414. {
  415. return E_NOTIMPL;
  416. }
  417. /*===================================================================
  418. CIsapiReqInfo::GetAspMDData
  419. ===================================================================*/
  420. HRESULT CIsapiReqInfo::GetAspMDDataW(WCHAR * pszMDPath,
  421. DWORD dwMDIdentifier,
  422. DWORD dwMDAttributes,
  423. DWORD dwMDUserType,
  424. DWORD dwMDDataType,
  425. DWORD dwMDDataLen,
  426. DWORD dwMDDataTag,
  427. unsigned char * pbMDData,
  428. DWORD * pdwRequiredBufferSize)
  429. {
  430. IMSAdminBase *pMetabase;
  431. METADATA_HANDLE hKey = NULL;
  432. METADATA_RECORD MetadataRecord;
  433. DWORD dwTimeout = 30000;
  434. HRESULT hr = S_OK;
  435. HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
  436. AspDoRevertHack( &hCurrentUser );
  437. pMetabase = GetMetabaseIF(&hr);
  438. ASSERT(pMetabase);
  439. if (pMetabase)
  440. {
  441. hr = pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  442. pszMDPath,
  443. METADATA_PERMISSION_READ,
  444. dwTimeout,
  445. &hKey
  446. );
  447. ASSERT(SUCCEEDED(hr));
  448. if( SUCCEEDED(hr) )
  449. {
  450. MetadataRecord.dwMDIdentifier = dwMDIdentifier;
  451. MetadataRecord.dwMDAttributes = dwMDAttributes;
  452. MetadataRecord.dwMDUserType = dwMDUserType;
  453. MetadataRecord.dwMDDataType = dwMDDataType;
  454. MetadataRecord.dwMDDataLen = dwMDDataLen;
  455. MetadataRecord.pbMDData = pbMDData;
  456. MetadataRecord.dwMDDataTag = dwMDDataTag;
  457. hr = pMetabase->GetData( hKey,
  458. L"",
  459. &MetadataRecord,
  460. pdwRequiredBufferSize);
  461. ASSERT(SUCCEEDED(hr));
  462. pMetabase->CloseKey( hKey );
  463. }
  464. }
  465. else // pMetabase == NULL, but there was No HRESULT set then we will explicitly set it.
  466. {
  467. if (SUCCEEDED(hr))
  468. hr = E_FAIL;
  469. }
  470. AspUndoRevertHack( &hCurrentUser );
  471. return hr;
  472. }
  473. /*===================================================================
  474. CIsapiReqInfo::GetAspMDAllData
  475. ===================================================================*/
  476. HRESULT CIsapiReqInfo::GetAspMDAllDataA(LPSTR pszMDPath,
  477. DWORD dwMDUserType,
  478. DWORD dwDefaultBufferSize,
  479. LPVOID pvBuffer,
  480. DWORD * pdwRequiredBufferSize,
  481. DWORD * pdwNumDataEntries)
  482. {
  483. return E_NOTIMPL;
  484. }
  485. /*===================================================================
  486. CIsapiReqInfo::GetAspMDAllData
  487. ===================================================================*/
  488. HRESULT CIsapiReqInfo::GetAspMDAllDataW(LPWSTR pwszMDPath,
  489. DWORD dwMDUserType,
  490. DWORD dwDefaultBufferSize,
  491. LPVOID pvBuffer,
  492. DWORD * pdwRequiredBufferSize,
  493. DWORD * pdwNumDataEntries)
  494. {
  495. HRESULT hr = S_OK;
  496. IMSAdminBase *pMetabase;
  497. METADATA_HANDLE hKey = NULL;
  498. DWORD dwTimeout = 30000;
  499. DWORD dwDataSet;
  500. HANDLE hCurrentUser = INVALID_HANDLE_VALUE;
  501. AspDoRevertHack( &hCurrentUser );
  502. //
  503. // Wide-ize the metabase path
  504. //
  505. pMetabase = GetMetabaseIF(&hr);
  506. ASSERT(pMetabase);
  507. if (pMetabase)
  508. {
  509. hr = pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  510. pwszMDPath,
  511. METADATA_PERMISSION_READ,
  512. dwTimeout,
  513. &hKey);
  514. if( SUCCEEDED(hr) )
  515. {
  516. hr = pMetabase->GetAllData( hKey,
  517. L"",
  518. METADATA_INHERIT,
  519. dwMDUserType,
  520. ALL_METADATA,
  521. pdwNumDataEntries,
  522. &dwDataSet,
  523. dwDefaultBufferSize,
  524. (UCHAR *)pvBuffer,
  525. pdwRequiredBufferSize);
  526. ASSERT(SUCCEEDED(hr));
  527. pMetabase->CloseKey( hKey );
  528. }
  529. }
  530. else // pMetabase == NULL, but there was No HRESULT set then we will explicitly set it.
  531. {
  532. if (SUCCEEDED(hr))
  533. hr = E_FAIL;
  534. }
  535. AspUndoRevertHack( &hCurrentUser );
  536. return hr;
  537. }
  538. /*===================================================================
  539. CIsapiReqInfo::GetCustomErrorA
  540. ===================================================================*/
  541. BOOL CIsapiReqInfo::GetCustomErrorA(DWORD dwError,
  542. DWORD dwSubError,
  543. DWORD dwBufferSize,
  544. CHAR *pvBuffer,
  545. DWORD *pdwRequiredBufferSize,
  546. BOOL *pfIsFileError,
  547. BOOL *pfSendErrorBody)
  548. {
  549. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  550. return FALSE;
  551. }
  552. /*===================================================================
  553. CIsapiReqInfo::GetCustomErrorW
  554. ===================================================================*/
  555. BOOL CIsapiReqInfo::GetCustomErrorW(DWORD dwError,
  556. DWORD dwSubError,
  557. DWORD dwBufferSize,
  558. WCHAR *pvBuffer,
  559. DWORD *pdwRequiredBufferSize,
  560. BOOL *pfIsFileError,
  561. BOOL *pfSendErrorBody)
  562. {
  563. BOOL fRet;
  564. HSE_CUSTOM_ERROR_PAGE_INFO cei;
  565. STACK_BUFFER(ansiBuf, 1024);
  566. cei.dwError = dwError;
  567. cei.dwSubError = dwSubError;
  568. cei.dwBufferSize = ansiBuf.QuerySize();
  569. cei.pBuffer = (CHAR *)ansiBuf.QueryPtr();
  570. cei.pdwBufferRequired = pdwRequiredBufferSize;
  571. cei.pfIsFileError = pfIsFileError;
  572. cei.pfSendErrorBody = pfSendErrorBody;
  573. fRet = ServerSupportFunction(HSE_REQ_GET_CUSTOM_ERROR_PAGE,
  574. &cei,
  575. NULL,
  576. NULL);
  577. if (!fRet) {
  578. DWORD dwErr = GetLastError();
  579. if (dwErr == ERROR_INSUFFICIENT_BUFFER) {
  580. if (ansiBuf.Resize(*pdwRequiredBufferSize) == FALSE) {
  581. SetLastError(ERROR_OUTOFMEMORY);
  582. return FALSE;
  583. }
  584. cei.dwBufferSize = ansiBuf.QuerySize();
  585. cei.pBuffer = (CHAR *)ansiBuf.QueryPtr();
  586. fRet = ServerSupportFunction(HSE_REQ_GET_CUSTOM_ERROR_PAGE,
  587. &cei,
  588. NULL,
  589. NULL);
  590. }
  591. if (!fRet) {
  592. SetLastError(ERROR_OUTOFMEMORY);
  593. return FALSE;
  594. }
  595. }
  596. CMBCSToWChar convError;
  597. if (FAILED(convError.Init((LPCSTR)ansiBuf.QueryPtr()))) {
  598. SetLastError(ERROR_OUTOFMEMORY);
  599. return FALSE;
  600. }
  601. *pdwRequiredBufferSize = (convError.GetStringLen()+1)*sizeof(WCHAR);
  602. if (*pdwRequiredBufferSize > dwBufferSize) {
  603. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  604. return FALSE;
  605. }
  606. memcpy(pvBuffer, convError.GetString(), *pdwRequiredBufferSize);
  607. if (*pfIsFileError) {
  608. CMBCSToWChar convMime;
  609. DWORD fileNameLen = *pdwRequiredBufferSize;
  610. if (FAILED(convMime.Init((LPCSTR)ansiBuf.QueryPtr()+strlen((LPCSTR)ansiBuf.QueryPtr())+1))) {
  611. SetLastError(ERROR_OUTOFMEMORY);
  612. return FALSE;
  613. }
  614. *pdwRequiredBufferSize += (convMime.GetStringLen()+1)*sizeof(WCHAR);
  615. if (*pdwRequiredBufferSize > dwBufferSize) {
  616. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  617. return FALSE;
  618. }
  619. memcpy(&((BYTE *)pvBuffer)[fileNameLen], convMime.GetString(), (convMime.GetStringLen()+1)*sizeof(WCHAR));
  620. }
  621. return TRUE;
  622. }
  623. /*===================================================================
  624. CIsapiReqInfo::QueryImpersonationToken
  625. ===================================================================*/
  626. HANDLE CIsapiReqInfo::QueryImpersonationToken()
  627. {
  628. HANDLE hToken = INVALID_HANDLE_VALUE;
  629. ServerSupportFunction(HSE_REQ_GET_IMPERSONATION_TOKEN,
  630. &hToken,
  631. NULL,
  632. NULL);
  633. return hToken;
  634. }
  635. /*===================================================================
  636. CIsapiReqInfo::AppendLogParameter
  637. ===================================================================*/
  638. HRESULT CIsapiReqInfo::AppendLogParameter(LPSTR extraParam)
  639. {
  640. if (ServerSupportFunction(HSE_APPEND_LOG_PARAMETER,
  641. extraParam,
  642. NULL,
  643. NULL) == FALSE) {
  644. return HRESULT_FROM_WIN32(GetLastError());
  645. }
  646. return S_OK;
  647. }
  648. /*===================================================================
  649. CIsapiReqInfo::SendHeader
  650. ===================================================================*/
  651. BOOL CIsapiReqInfo::SendHeader(LPVOID pvStatus,
  652. DWORD cchStatus,
  653. LPVOID pvHeader,
  654. DWORD cchHeader,
  655. BOOL fIsaKeepConn)
  656. {
  657. HSE_SEND_HEADER_EX_INFO HeaderInfo;
  658. HeaderInfo.pszStatus = (LPCSTR)pvStatus;
  659. HeaderInfo.cchStatus = cchStatus;
  660. HeaderInfo.pszHeader = (LPCSTR) pvHeader;
  661. HeaderInfo.cchHeader = cchHeader;
  662. HeaderInfo.fKeepConn = fIsaKeepConn;
  663. m_fHeadersWritten = TRUE;
  664. return ServerSupportFunction( HSE_REQ_SEND_RESPONSE_HEADER_EX,
  665. &HeaderInfo,
  666. NULL,
  667. NULL );
  668. }
  669. /*===================================================================
  670. CIsapiReqInfo::GetServerVariableA
  671. ===================================================================*/
  672. BOOL CIsapiReqInfo::GetServerVariableA(LPSTR szVarName,
  673. LPSTR pBuffer,
  674. LPDWORD pdwSize )
  675. {
  676. return m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
  677. szVarName,
  678. pBuffer,
  679. pdwSize );
  680. }
  681. /*===================================================================
  682. CIsapiReqInfo::GetServerVariableW
  683. ===================================================================*/
  684. BOOL CIsapiReqInfo::GetServerVariableW(LPSTR szVarName,
  685. LPWSTR pBuffer,
  686. LPDWORD pdwSize )
  687. {
  688. return m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
  689. szVarName,
  690. pBuffer,
  691. pdwSize );
  692. }
  693. /*===================================================================
  694. CIsapiReqInfo::GetVirtualPathTokenA
  695. ===================================================================*/
  696. HRESULT CIsapiReqInfo::GetVirtualPathTokenA(LPCSTR szPath,
  697. HANDLE *hToken)
  698. {
  699. HRESULT hr = S_OK;
  700. if (!ServerSupportFunction(HSE_REQ_GET_VIRTUAL_PATH_TOKEN,
  701. (LPVOID)szPath,
  702. (DWORD *)hToken,
  703. NULL)) {
  704. hr = HRESULT_FROM_WIN32(GetLastError());
  705. }
  706. return hr;
  707. }
  708. /*===================================================================
  709. CIsapiReqInfo::GetVirtualPathTokenW
  710. ===================================================================*/
  711. HRESULT CIsapiReqInfo::GetVirtualPathTokenW(LPCWSTR szPath,
  712. HANDLE *hToken)
  713. {
  714. HRESULT hr = S_OK;
  715. if (!ServerSupportFunction(HSE_REQ_GET_UNICODE_VIRTUAL_PATH_TOKEN,
  716. (LPVOID)szPath,
  717. (DWORD *)hToken,
  718. NULL)) {
  719. hr = HRESULT_FROM_WIN32(GetLastError());
  720. }
  721. return hr;
  722. }
  723. /*===================================================================
  724. CIsapiReqInfo::ServerSupportFunction
  725. ===================================================================*/
  726. BOOL CIsapiReqInfo::ServerSupportFunction(DWORD dwHSERequest,
  727. LPVOID pvData,
  728. LPDWORD pdwSize,
  729. LPDWORD pdwDataType)
  730. {
  731. return m_pECB->ServerSupportFunction( (HCONN)m_pECB->ConnID,
  732. dwHSERequest,
  733. pvData,
  734. pdwSize,
  735. pdwDataType );
  736. }
  737. /*===================================================================
  738. CIsapiReqInfo::SendClinetResponse
  739. this routine is used to send all of ASP data to the client. the data
  740. may consist of any combination of the following:
  741. - header information as contained in pResponseInfo->HeaderInfo
  742. - contents of a file if pResponseInfo->cWsaBuf == 0xFFFFFFFF
  743. - non-buffered data if pResponseInfo->cWsaBuf > 0
  744. - buffered data if pResponseVectors != NULL
  745. Note, we are changing the semantics of the HSE_SEND_ENTIRE_RESPONSE_INFO
  746. structure as follows:
  747. - if pResponseInfo->cWsaBuf == 0xFFFFFFFF, then pResponseInfo->rgWsaBuf
  748. is a pointer to a single WSABUF, containing a file handle rather than
  749. memory buffer pointer
  750. - we are not reserving entry 0 of the pResponseInfo->rgWsaBuf array, so
  751. entries 0 - (N-1) contain relevant data
  752. Note, the HeaderInfo strings pszStatus and pszContent are set to NULL
  753. after their placed in the AsyncCB SEND_VECTOR structure to indicate
  754. that we've taken ownership of the memory. Note that it is also
  755. assumed that the memory was allocated using malloc().
  756. ===================================================================*/
  757. BOOL CIsapiReqInfo::SendClientResponse(PFN_CLIENT_IO_COMPLETION pComplFunc,
  758. VOID *pComplArg,
  759. LPHSE_SEND_ENTIRE_RESPONSE_INFO pResponseInfo,
  760. LPWSABUF_VECTORS pResponseVectors)
  761. {
  762. HRESULT hr = S_OK;
  763. DWORD nElementCount = 0;
  764. DWORD dwTotalBytes = 0;
  765. HSE_VECTOR_ELEMENT *pVectorElement = NULL;
  766. HSE_RESPONSE_VECTOR *pRespVector;
  767. BOOL fKeepConn;
  768. CAsyncVectorSendCB syncVectorSendCB; // use the async class to manage the resp vector
  769. CAsyncVectorSendCB *pVectorSendCB = &syncVectorSendCB;
  770. // if an error has been recorded during an Async completion, bail out
  771. // early
  772. if (m_dwAsyncError) {
  773. SetLastError(m_dwAsyncError);
  774. return FALSE;
  775. }
  776. // if a completion function was provided, allocate a CAsyncVectorSendCB
  777. // instead of the stack version
  778. if (pComplFunc) {
  779. pVectorSendCB = new CAsyncVectorSendCB(this, pComplArg, pComplFunc);
  780. if (pVectorSendCB == NULL) {
  781. SetLastError(ERROR_OUTOFMEMORY);
  782. return FALSE;
  783. }
  784. }
  785. pRespVector = &pVectorSendCB->m_hseResponseVector;
  786. Assert( pResponseInfo );
  787. Assert( (pResponseInfo->cWsaBuf == 0xFFFFFFFF) ||
  788. (pResponseInfo->cWsaBuf < 0x3FFF) ); // arbitrary logical limit
  789. Assert( (pResponseInfo->cWsaBuf == 0) || (pResponseInfo->rgWsaBuf != NULL));
  790. //
  791. // Set the keep connection flag. It can only be TRUE if the
  792. // ISAPI and the client both want keep alive.
  793. //
  794. fKeepConn = FKeepConn() && pResponseInfo->HeaderInfo.fKeepConn;
  795. //
  796. // Munge the input structure into something that IIsapiCore can
  797. // understand. Note that ASP sets the number of buffer to be one more
  798. // than actual and the first buffer is not valid
  799. //
  800. if (pResponseInfo->cWsaBuf == 0xFFFFFFFF)
  801. {
  802. // indicates a file handle in a single WSABUF
  803. nElementCount ++;
  804. }
  805. else
  806. {
  807. nElementCount += pResponseInfo->cWsaBuf;
  808. }
  809. // Add the optional raw response vectors
  810. if (pResponseVectors)
  811. {
  812. Assert(pResponseVectors->dwVectorLen1 <= RESPONSE_VECTOR_INTRINSIC_SIZE);
  813. Assert(pResponseVectors->dwVectorLen2 < 0x3FFF);
  814. nElementCount += pResponseVectors->dwVectorLen1 + pResponseVectors->dwVectorLen2;
  815. }
  816. if (nElementCount == 0) {
  817. // no body to send. pVectorElement already set to NULL
  818. goto FillHeaderAndSend;
  819. }
  820. Assert( nElementCount < 0x3FFF); // arbitrary logical limit
  821. // let the VectorSendCB know how many elements are needed.
  822. if (FAILED(hr = pVectorSendCB->SetElementCount(nElementCount)))
  823. {
  824. goto Exit;
  825. }
  826. pVectorElement = pVectorSendCB->m_pVectorElements;
  827. #define FILL_HSE_VECTOR_LOOP(cElements, WsaBuf) \
  828. \
  829. for (DWORD i = 0; i < cElements; i++) \
  830. { \
  831. if (WsaBuf[i].len == 0) \
  832. { \
  833. Assert( nElementCount > 0); \
  834. nElementCount--; \
  835. continue; \
  836. } \
  837. \
  838. Assert( !IsBadReadPtr( WsaBuf[i].buf, WsaBuf[i].len)); \
  839. \
  840. pVectorElement->ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; \
  841. pVectorElement->pvContext = WsaBuf[i].buf; \
  842. pVectorElement->cbSize = WsaBuf[i].len; \
  843. dwTotalBytes += WsaBuf[i].len; \
  844. pVectorElement++; \
  845. }
  846. if (pResponseInfo->cWsaBuf == 0xFFFFFFFF) {
  847. // we have a file handle rather than a memory buffer
  848. pVectorElement->ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
  849. pVectorElement->pvContext = pResponseInfo->rgWsaBuf[0].buf;
  850. pVectorElement->cbSize = pResponseInfo->rgWsaBuf[0].len;
  851. dwTotalBytes += pResponseInfo->rgWsaBuf[0].len;
  852. pVectorElement++;
  853. } else {
  854. FILL_HSE_VECTOR_LOOP( pResponseInfo->cWsaBuf, pResponseInfo->rgWsaBuf)
  855. }
  856. if (pResponseVectors) {
  857. FILL_HSE_VECTOR_LOOP( pResponseVectors->dwVectorLen1, pResponseVectors->pVector1)
  858. FILL_HSE_VECTOR_LOOP( pResponseVectors->dwVectorLen2, pResponseVectors->pVector2)
  859. }
  860. #undef FILL_HSE_VECTOR_LOOP
  861. // reset to the begining of buffer
  862. pVectorElement = pVectorSendCB->m_pVectorElements;
  863. FillHeaderAndSend:
  864. pRespVector->dwFlags = (pComplFunc ? HSE_IO_ASYNC : HSE_IO_SYNC) |
  865. (!fKeepConn ? HSE_IO_DISCONNECT_AFTER_SEND : 0) |
  866. (pResponseInfo->HeaderInfo.pszHeader ? HSE_IO_SEND_HEADERS : 0);
  867. pRespVector->pszStatus = (LPSTR)pResponseInfo->HeaderInfo.pszStatus;
  868. pRespVector->pszHeaders = (LPSTR)pResponseInfo->HeaderInfo.pszHeader;
  869. pRespVector->nElementCount = nElementCount;
  870. pRespVector->lpElementArray = pVectorElement;
  871. dwTotalBytes += pResponseInfo->HeaderInfo.cchStatus;
  872. dwTotalBytes += pResponseInfo->HeaderInfo.cchHeader;
  873. // Note that the headers have been written
  874. if (pResponseInfo->HeaderInfo.pszHeader)
  875. m_fHeadersWritten = TRUE;
  876. // by moving these pointers into our SEND_VECTOR, we are taking
  877. // ownership of the memory.
  878. pResponseInfo->HeaderInfo.pszStatus = NULL;
  879. pResponseInfo->HeaderInfo.pszHeader = NULL;
  880. if (pComplFunc) {
  881. hr = AddToPendingList(pVectorSendCB);
  882. }
  883. else {
  884. //
  885. // Send it
  886. //
  887. if (ServerSupportFunction(HSE_REQ_VECTOR_SEND,
  888. pRespVector,
  889. NULL,
  890. NULL) == FALSE) {
  891. hr = HRESULT_FROM_WIN32(GetLastError());
  892. }
  893. }
  894. if (SUCCEEDED(hr)) {
  895. pResponseInfo->cbWritten = dwTotalBytes;
  896. }
  897. Exit:
  898. if (FAILED(hr))
  899. {
  900. SetLastError((HRESULT_FACILITY(hr) == (HRESULT)FACILITY_WIN32)
  901. ? HRESULT_CODE(hr)
  902. : ERROR_INVALID_PARAMETER);
  903. if (pVectorSendCB && (pVectorSendCB != &syncVectorSendCB)) {
  904. delete pVectorSendCB;
  905. }
  906. return FALSE;
  907. }
  908. return TRUE;
  909. }
  910. /*===================================================================
  911. CIsapiReqInfo::TestConnection
  912. ===================================================================*/
  913. BOOL CIsapiReqInfo::TestConnection(BOOL *pfIsConnected)
  914. {
  915. return ServerSupportFunction(HSE_REQ_IS_CONNECTED,
  916. pfIsConnected,
  917. NULL,
  918. NULL);
  919. }
  920. /*===================================================================
  921. CIsapiReqInfo::MapUrlToPathA
  922. ===================================================================*/
  923. BOOL CIsapiReqInfo::MapUrlToPathA(LPSTR pBuffer, LPDWORD pdwBytes)
  924. {
  925. return ServerSupportFunction( HSE_REQ_MAP_URL_TO_PATH,
  926. pBuffer,
  927. pdwBytes,
  928. NULL );
  929. }
  930. /*===================================================================
  931. CIsapiReqInfo::MapUrlToPathW
  932. ===================================================================*/
  933. BOOL CIsapiReqInfo::MapUrlToPathW(LPWSTR pBuffer, LPDWORD pdwBytes)
  934. {
  935. return ServerSupportFunction( HSE_REQ_MAP_UNICODE_URL_TO_PATH,
  936. pBuffer,
  937. pdwBytes,
  938. NULL );
  939. }
  940. /*===================================================================
  941. CIsapiReqInfo::SyncReadClient
  942. ===================================================================*/
  943. BOOL CIsapiReqInfo::SyncReadClient(LPVOID pvBuffer, LPDWORD pdwBytes )
  944. {
  945. return m_pECB->ReadClient(m_pECB->ConnID, pvBuffer, pdwBytes);
  946. }
  947. /*===================================================================
  948. CIsapiReqInfo::SyncWriteClient
  949. ===================================================================*/
  950. BOOL CIsapiReqInfo::SyncWriteClient(LPVOID pvBuffer, LPDWORD pdwBytes)
  951. {
  952. return m_pECB->WriteClient(m_pECB->ConnID, pvBuffer, pdwBytes, HSE_IO_SYNC);
  953. }
  954. /*********************************************************************
  955. PRIVATE FUNCTIONS
  956. *********************************************************************/
  957. /*===================================================================
  958. CIsapiReqInfo::InitVersionInfo
  959. ===================================================================*/
  960. void CIsapiReqInfo::InitVersionInfo()
  961. {
  962. if (m_fVersionInited == FALSE) {
  963. BUFFER version;
  964. m_fVersionInited = TRUE;
  965. m_dwVersionMajor = 1;
  966. m_dwVersionMinor = 0;
  967. if (InternalGetServerVariable("SERVER_PROTOCOL", &version)) {
  968. char *pVersionStr = (char *)version.QueryPtr();
  969. if ((strlen(pVersionStr) >= 8)
  970. && (isdigit((UCHAR)pVersionStr[5]))
  971. && (isdigit((UCHAR)pVersionStr[7]))) {
  972. m_dwVersionMajor = pVersionStr[5] - '0';
  973. m_dwVersionMinor = pVersionStr[7] - '0';
  974. }
  975. }
  976. }
  977. }
  978. /*===================================================================
  979. CIsapiReqInfo::InternalGetServerVariable
  980. ===================================================================*/
  981. BOOL CIsapiReqInfo::InternalGetServerVariable(LPSTR pszVarName, BUFFER *pBuf)
  982. {
  983. BOOL bRet;
  984. DWORD dwRequiredBufSize = pBuf->QuerySize();
  985. bRet = m_pECB->GetServerVariable(m_pECB->ConnID,
  986. pszVarName,
  987. pBuf->QueryPtr(),
  988. &dwRequiredBufSize);
  989. if ((bRet == FALSE) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  990. if (!pBuf->Resize(dwRequiredBufSize)) {
  991. SetLastError(ERROR_OUTOFMEMORY);
  992. return FALSE;
  993. }
  994. bRet = m_pECB->GetServerVariable(m_pECB->ConnID,
  995. pszVarName,
  996. pBuf->QueryPtr(),
  997. &dwRequiredBufSize);
  998. }
  999. return(bRet);
  1000. }
  1001. /*===================================================================
  1002. CIsapiReqInfo::FKeepConn
  1003. ===================================================================*/
  1004. BOOL CIsapiReqInfo::FKeepConn()
  1005. {
  1006. if (m_fFKeepConnInited == FALSE) {
  1007. m_fFKeepConnInited = TRUE;
  1008. m_fKeepConn = FALSE;
  1009. InitVersionInfo();
  1010. if (m_dwVersionMajor == 1) {
  1011. if (m_dwVersionMinor == 1) {
  1012. m_fKeepConn = TRUE;
  1013. }
  1014. BUFFER connectStr;
  1015. if (InternalGetServerVariable("HTTP_CONNECTION", &connectStr)) {
  1016. if (m_dwVersionMinor == 0) {
  1017. m_fKeepConn = !(_stricmp((char *)connectStr.QueryPtr(), "keep-alive"));
  1018. }
  1019. else if (m_dwVersionMinor == 1) {
  1020. m_fKeepConn = !!(_stricmp((char *)connectStr.QueryPtr(), "close"));
  1021. }
  1022. }
  1023. }
  1024. }
  1025. return m_fKeepConn;
  1026. }
  1027. /*===================================================================
  1028. CIsapiReqInfo::GetMetabaseIF
  1029. ===================================================================*/
  1030. IMSAdminBase *CIsapiReqInfo::GetMetabaseIF(HRESULT *pHr)
  1031. {
  1032. IMSAdminBase *pMetabase;
  1033. //
  1034. //Set *pHr to S_OK in case its not initialized
  1035. //
  1036. *pHr = S_OK;
  1037. if (m_pIAdminBase == NULL) {
  1038. *pHr = CoCreateInstance(CLSID_MSAdminBase,
  1039. NULL,
  1040. CLSCTX_ALL,
  1041. IID_IMSAdminBase,
  1042. (void**)&pMetabase);
  1043. ASSERT(SUCCEEDED(*pHr));
  1044. if ( InterlockedCompareExchangePointer( (VOID**)&m_pIAdminBase, pMetabase, NULL) != NULL )
  1045. {
  1046. pMetabase->Release();
  1047. pMetabase = NULL;
  1048. }
  1049. }
  1050. return m_pIAdminBase;
  1051. }
  1052. /*===================================================================
  1053. CIsapiReqInfo::AddToPendingList
  1054. Places an CAsyncVectorSendCB on the PendingSendCS. If this is
  1055. the first entry placed on the list, then IssueNextSend() is called
  1056. to start the possible chain of sends.
  1057. ===================================================================*/
  1058. HRESULT CIsapiReqInfo::AddToPendingList(CAsyncVectorSendCB *pVectorCB)
  1059. {
  1060. HRESULT hr = S_OK;
  1061. // initialize the critical section if it hasn't already
  1062. // been initialized. Note that there isn't a race condition
  1063. // here because there can't be any other thread contenting for
  1064. // this CS until AsyncIOs start to complete. It's safe to
  1065. // assume that the IO hasn't begun if we've never enterred
  1066. // this routine before...
  1067. if (m_fPendSendCSInited == FALSE) {
  1068. ErrInitCriticalSection(&m_csPendingSendCS, hr);
  1069. if (SUCCEEDED(hr))
  1070. m_fPendSendCSInited = TRUE;
  1071. }
  1072. // similar to the CS above, register the completion function
  1073. if (SUCCEEDED(hr) && (m_fIOCompletionRegistered == FALSE)) {
  1074. if (ServerSupportFunction(HSE_REQ_IO_COMPLETION,
  1075. AsyncCompletion,
  1076. NULL,
  1077. (LPDWORD)this) == FALSE)
  1078. hr = HRESULT_FROM_WIN32(GetLastError());
  1079. if (SUCCEEDED(hr))
  1080. m_fIOCompletionRegistered = TRUE;
  1081. }
  1082. // do not queue new requests if an error was previously recorded
  1083. if (SUCCEEDED(hr)) {
  1084. hr = HRESULT_FROM_WIN32(m_dwAsyncError);
  1085. }
  1086. // we'll return error here if anything went wrong. Otherwise, we're
  1087. // going to execute the rest of the logic and return S_OK. Any
  1088. // errors downstream from here will report through the completion
  1089. // functions.
  1090. if (FAILED(hr))
  1091. return hr;
  1092. m_dwRequestStatus = HSE_STATUS_PENDING;
  1093. EnterCriticalSection(&m_csPendingSendCS);
  1094. BOOL fFirstEntry = m_listPendingSends.FIsEmpty();
  1095. pVectorCB->AppendTo(m_listPendingSends);
  1096. LeaveCriticalSection(&m_csPendingSendCS);
  1097. // if the list was empty, then call IssueNextSend() to get things started
  1098. if (fFirstEntry)
  1099. IssueNextSend();
  1100. return S_OK;
  1101. }
  1102. /*===================================================================
  1103. CIsapiReqInfo::IssueNextSend
  1104. Enters the critical section to grab the first entry on the queue.
  1105. Note that the entry is left on the list. This is the easiest
  1106. way to communicate with the completion routine which
  1107. CAsyncVectorSendCB just completed.
  1108. Errors are handled by creating a "fake" completion - i.e the
  1109. registered completion function is called from here instead of
  1110. by the core.
  1111. ===================================================================*/
  1112. void CIsapiReqInfo::IssueNextSend()
  1113. {
  1114. CAsyncVectorSendCB *pVectorSendCB = NULL;
  1115. HRESULT hr = S_OK;
  1116. DWORD dwIOError = 0;
  1117. EnterCriticalSection(&m_csPendingSendCS);
  1118. if (!m_listPendingSends.FIsEmpty()) {
  1119. pVectorSendCB = (CAsyncVectorSendCB *)m_listPendingSends.PNext();
  1120. }
  1121. LeaveCriticalSection(&m_csPendingSendCS);
  1122. if (pVectorSendCB) {
  1123. // increment here that there is about to be an outstanding
  1124. // async write. Note that it is possible that an error
  1125. // condition could result in the AsyncCompletion being called
  1126. // and that routine decrements this counter. Again, once were
  1127. // at this point, one way or another, the async completion
  1128. // routine is going to be called.
  1129. InterlockedIncrement(&g_nOutstandingAsyncWrites);
  1130. // check to see if an error was previously recorded
  1131. if (m_dwAsyncError) {
  1132. dwIOError = m_dwAsyncError;
  1133. }
  1134. // otherwise, call HSE_REQ_VECTOR_SEND
  1135. else if (ServerSupportFunction(HSE_REQ_VECTOR_SEND,
  1136. &pVectorSendCB->m_hseResponseVector,
  1137. NULL,
  1138. NULL) == FALSE) {
  1139. dwIOError = GetLastError();
  1140. }
  1141. // if an error has been noted, call the AsyncCompletion to clean
  1142. // things up
  1143. if (dwIOError) {
  1144. CIsapiReqInfo::AsyncCompletion(pVectorSendCB->m_pIReq->m_pECB,
  1145. pVectorSendCB->m_pIReq,
  1146. 0,
  1147. dwIOError);
  1148. }
  1149. }
  1150. }
  1151. /*===================================================================
  1152. CIsapiReqInfo::AsyncCompletion
  1153. Called to handle the successful, or unsuccessful, completion of
  1154. a pending async send.
  1155. The logic is pretty straightforward. Grab the head entry on the
  1156. async pending queue, call the completion function, call
  1157. call IssueNextSend() to keep the send chain going, release this
  1158. reference on the IsapiReqInfo.
  1159. ===================================================================*/
  1160. WINAPI CIsapiReqInfo::AsyncCompletion(EXTENSION_CONTROL_BLOCK * pECB,
  1161. PVOID pContext,
  1162. DWORD cbIO,
  1163. DWORD dwError)
  1164. {
  1165. CIsapiReqInfo *pIReq = (CIsapiReqInfo *)pContext;
  1166. CAsyncVectorSendCB *pCB;
  1167. BOOL fIsEmpty;
  1168. InterlockedDecrement(&g_nOutstandingAsyncWrites);
  1169. // if an error is being reported, note it.
  1170. // do it here, so subsequent new requests do not get added to the queue and dispatched
  1171. if (dwError)
  1172. pIReq->m_dwAsyncError = dwError;
  1173. //
  1174. // the following block is normally executed once, to handle the completed control
  1175. // block. However, in case of an error, we'll itterate on the queue until it drains.
  1176. //
  1177. do {
  1178. // lock the CS and get the head
  1179. EnterCriticalSection(&pIReq->m_csPendingSendCS);
  1180. Assert(!pIReq->m_listPendingSends.FIsEmpty());
  1181. pCB = (CAsyncVectorSendCB *)pIReq->m_listPendingSends.PNext();
  1182. // this wouldn't be good, and likely impossible because if
  1183. // the list is empty, it will return the head pointer.
  1184. Assert(pCB);
  1185. Assert(pIReq == pCB->m_pIReq);
  1186. // remove it from the list
  1187. pCB->UnLink();
  1188. fIsEmpty = pIReq->m_listPendingSends.FIsEmpty();
  1189. LeaveCriticalSection(&pIReq->m_csPendingSendCS);
  1190. // call the client's completion function
  1191. pCB->m_pCallerFunc(pCB->m_pIReq, pCB->m_pCallerContext, cbIO, dwError);
  1192. // we are done with this CAsyncVectorSendCB
  1193. delete pCB;
  1194. // if no error occured, break out and keep going
  1195. if (!dwError) {
  1196. break;
  1197. }
  1198. } while ( !fIsEmpty );
  1199. // keep the sends going, if there are sends to do
  1200. if (!fIsEmpty)
  1201. pIReq->IssueNextSend();
  1202. }
  1203. /*===================================================================
  1204. CAsyncVectorSendCB::CAsyncVectorSendCB
  1205. Base Constructor - clear everything
  1206. ===================================================================*/
  1207. CAsyncVectorSendCB::CAsyncVectorSendCB() {
  1208. m_pIReq = NULL;
  1209. m_pCallerContext = NULL;
  1210. m_pCallerFunc = NULL;
  1211. m_pVectorElements = m_aVectorElements;
  1212. ZeroMemory(&m_hseResponseVector, sizeof(HSE_RESPONSE_VECTOR));
  1213. ZeroMemory(m_pVectorElements,
  1214. sizeof(m_aVectorElements));
  1215. }
  1216. /*===================================================================
  1217. CAsyncVectorSendCB::CAsyncVectorSendCB
  1218. Overriden Constructor - sets some members based on passed in
  1219. values.
  1220. ===================================================================*/
  1221. CAsyncVectorSendCB::CAsyncVectorSendCB(CIsapiReqInfo *pIReq,
  1222. void *pContext,
  1223. PFN_CLIENT_IO_COMPLETION pFunc) {
  1224. ZeroMemory(&m_hseResponseVector, sizeof(HSE_RESPONSE_VECTOR));
  1225. m_pIReq = pIReq;
  1226. m_pCallerContext = pContext;
  1227. m_pCallerFunc = pFunc;
  1228. m_pVectorElements = m_aVectorElements;
  1229. ZeroMemory(m_pVectorElements,
  1230. sizeof(m_aVectorElements));
  1231. pIReq->AddRef();
  1232. }
  1233. /*===================================================================
  1234. CAsyncVectorSendCB::~CAsyncVectorSendCB
  1235. Destructor - cleans up
  1236. ===================================================================*/
  1237. CAsyncVectorSendCB::~CAsyncVectorSendCB() {
  1238. // if m_pVectorElements is not pointing to the built-in array,
  1239. // then it must be allocated memory. Free it.
  1240. if (m_pVectorElements && (m_pVectorElements != m_aVectorElements))
  1241. free(m_pVectorElements);
  1242. // free the Headers and Status strings, if allocated
  1243. if (m_hseResponseVector.pszHeaders)
  1244. free(m_hseResponseVector.pszHeaders);
  1245. if (m_hseResponseVector.pszStatus)
  1246. free(m_hseResponseVector.pszStatus);
  1247. if (m_pIReq) {
  1248. m_pIReq->Release();
  1249. m_pIReq = NULL;
  1250. }
  1251. }
  1252. /*===================================================================
  1253. CAsyncVectorSendCB::SetElementCount
  1254. Makes sure that m_pVectorElements is sufficiently sized. If the
  1255. number of elements is less than or equal to the size of the
  1256. built-in array, it is used. If not, one is allocated.
  1257. ===================================================================*/
  1258. HRESULT CAsyncVectorSendCB::SetElementCount(DWORD nElements)
  1259. {
  1260. if (nElements <= (sizeof(m_aVectorElements)/sizeof(HSE_VECTOR_ELEMENT)))
  1261. return S_OK;
  1262. m_pVectorElements = (HSE_VECTOR_ELEMENT *)malloc(sizeof(HSE_VECTOR_ELEMENT)*nElements);
  1263. if (m_pVectorElements == NULL) {
  1264. return E_OUTOFMEMORY;
  1265. }
  1266. ZeroMemory(m_pVectorElements,
  1267. nElements * sizeof(HSE_VECTOR_ELEMENT));
  1268. return S_OK;
  1269. }