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.

1580 lines
37 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. main.cxx
  5. Abstract:
  6. This is the HTTP ODBC gateway
  7. Author:
  8. John Ludeman (johnl) 20-Feb-1995
  9. Revision History:
  10. Tamas Nemeth (t-tamasn) 12-Jun-1998
  11. --*/
  12. //
  13. // System include files.
  14. //
  15. #include "precomp.hxx"
  16. #include "iadmw.h"
  17. #include <ole2.h>
  18. #include <lmcons.h>
  19. DECLARE_DEBUG_PRINTS_OBJECT();
  20. DECLARE_DEBUG_VARIABLE();
  21. #ifndef ARRAYSIZE
  22. #define ARRAYSIZE(_a) (sizeof((_a))/sizeof(*(_a)))
  23. #endif
  24. extern "C" {
  25. BOOL
  26. WINAPI
  27. DllMain(
  28. HINSTANCE hDll,
  29. DWORD dwReason,
  30. LPVOID lpvReserved
  31. );
  32. }
  33. //
  34. // Globals
  35. //
  36. IMSAdminBase * g_pMetabase = NULL;
  37. //
  38. // Is this system DBCS?
  39. //
  40. BOOL g_fIsSystemDBCS;
  41. //
  42. // Prototypes
  43. //
  44. HRESULT
  45. ODBCInitialize(
  46. VOID
  47. );
  48. VOID
  49. ODBCTerminate(
  50. VOID
  51. );
  52. HRESULT
  53. DoQuery(
  54. EXTENSION_CONTROL_BLOCK * pecb,
  55. const CHAR * pszQueryFile,
  56. const CHAR * pszParamList,
  57. STRA * pstrError,
  58. int nCharset,
  59. BOOL * pfAccessDenied
  60. );
  61. DWORD
  62. OdbcExtensionOutput(
  63. EXTENSION_CONTROL_BLOCK * pecb,
  64. const CHAR * pchOutput,
  65. DWORD cbOutput
  66. );
  67. BOOL
  68. OdbcExtensionHeader(
  69. EXTENSION_CONTROL_BLOCK * pecb,
  70. const CHAR * pchStatus,
  71. const CHAR * pchHeaders
  72. );
  73. BOOL LookupHttpSymbols( // eliminated, check its functionality
  74. const CHAR * pszSymbolName,
  75. STRA * pstrSymbolValue
  76. );
  77. HRESULT
  78. GetIDCCharset(
  79. CONST CHAR * pszPath,
  80. int * pnCharset,
  81. STRA * pstrError
  82. );
  83. HRESULT
  84. ConvertUrlEncodedStringToSJIS(
  85. int nCharset,
  86. STRA * pstrParams
  87. );
  88. BOOL
  89. IsSystemDBCS(
  90. VOID
  91. );
  92. CHAR *
  93. FlipSlashes(
  94. CHAR * pszPath
  95. );
  96. HRESULT
  97. GetPoolIDCTimeout(
  98. unsigned char * szMdPath,
  99. DWORD * pdwPoolIDCTimeout
  100. );
  101. HRESULT
  102. SendCustomError(
  103. EXTENSION_CONTROL_BLOCK *pecb,
  104. const CHAR *pszStatus
  105. );
  106. VOID WINAPI
  107. CustomErrorCompletion(
  108. EXTENSION_CONTROL_BLOCK *pECB,
  109. PVOID pContext,
  110. DWORD cbIO,
  111. DWORD dwError
  112. );
  113. HRESULT
  114. SendErrorResponse(
  115. EXTENSION_CONTROL_BLOCK *pecb,
  116. const CHAR *pszStatus,
  117. DWORD dwResID,
  118. const CHAR *pszParam
  119. );
  120. HRESULT
  121. SendErrorResponseFromHr(
  122. EXTENSION_CONTROL_BLOCK *pecb,
  123. const CHAR *pszStatus,
  124. DWORD dwResID,
  125. HRESULT hrError
  126. );
  127. static const CHAR c_sz500InternalServerError[] = "500 Internal Server Error";
  128. DWORD
  129. HttpExtensionProc(
  130. EXTENSION_CONTROL_BLOCK * pecb
  131. )
  132. {
  133. STACK_STRA( strPath, MAX_PATH);
  134. STACK_STRA( strParams, MAX_PATH);
  135. STRA strError;
  136. CHAR * pch;
  137. DWORD cch;
  138. int nCharset;
  139. HRESULT hr;
  140. //
  141. // Make sure ODBC is loaded
  142. //
  143. if ( !LoadODBC() )
  144. {
  145. hr = SendErrorResponse( pecb,
  146. "500 Unable to load ODBC",
  147. ODBCMSG_CANT_LOAD_ODBC,
  148. NULL);
  149. if ( FAILED( hr ) )
  150. {
  151. goto FatalError;
  152. }
  153. return HSE_STATUS_ERROR;
  154. }
  155. //
  156. // We currently only support the GET and POST methods
  157. //
  158. if ( !strcmp( pecb->lpszMethod, "POST" ))
  159. {
  160. if ( _stricmp( pecb->lpszContentType,
  161. "application/x-www-form-urlencoded" ) )
  162. {
  163. // Try to send custom error
  164. hr = SendCustomError( pecb, "400 Bad Request" );
  165. if ( FAILED( hr ) )
  166. {
  167. goto FatalError;
  168. }
  169. return HSE_STATUS_PENDING;
  170. }
  171. //
  172. // The query params are in the extra data, add a few bytes in
  173. // case we need to double "'"
  174. //
  175. hr = strParams.Resize( pecb->cbAvailable + sizeof(TCHAR) + 3);
  176. if ( SUCCEEDED( hr ) )
  177. {
  178. hr = strParams.Copy( ( const char * ) pecb->lpbData,
  179. pecb->cbAvailable );
  180. }
  181. if ( FAILED( hr ) )
  182. {
  183. DBGPRINTF(( DBG_CONTEXT,
  184. "Error resizing param buffer, hr = 0x%x.\n",
  185. hr ));
  186. hr = SendErrorResponseFromHr( pecb,
  187. "500 Error performing Query",
  188. ODBCMSG_ERROR_PERFORMING_QUERY,
  189. hr);
  190. if ( FAILED( hr ) )
  191. {
  192. goto FatalError;
  193. }
  194. return HSE_STATUS_ERROR;
  195. }
  196. }
  197. else if ( !strcmp( pecb->lpszMethod, "GET" ) )
  198. {
  199. hr = strParams.Copy( pecb->lpszQueryString );
  200. if ( FAILED( hr ) )
  201. {
  202. DBGPRINTF(( DBG_CONTEXT,
  203. "Error copying params, hr = 0x%x.\n",
  204. hr ));
  205. hr = SendErrorResponseFromHr( pecb,
  206. "500 Error performing Query",
  207. ODBCMSG_ERROR_PERFORMING_QUERY,
  208. hr);
  209. if ( FAILED( hr ) )
  210. {
  211. goto FatalError;
  212. }
  213. return HSE_STATUS_ERROR;
  214. }
  215. }
  216. else
  217. {
  218. // Try to send custom error
  219. hr = SendCustomError( pecb, "400 Method Not Allowed" );
  220. if ( FAILED( hr ) )
  221. {
  222. goto FatalError;
  223. }
  224. return HSE_STATUS_PENDING;
  225. }
  226. //
  227. // "Charset" field is enabled for CP932 (Japanese) only in
  228. // this version.
  229. //
  230. if ( 932 != GetACP() )
  231. {
  232. nCharset = CODE_ONLY_SBCS;
  233. }
  234. else
  235. {
  236. //
  237. // Get the charset from .idc file
  238. //
  239. hr = GetIDCCharset( pecb->lpszPathTranslated,
  240. &nCharset,
  241. &strError );
  242. if ( FAILED( hr ) )
  243. {
  244. // If the file was not found
  245. if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) ||
  246. ( hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) ) ||
  247. ( hr == HRESULT_FROM_WIN32( ERROR_INVALID_NAME ) ) )
  248. {
  249. // Try to send custom error
  250. hr = SendCustomError( pecb, "404 Not Found" );
  251. if ( FAILED( hr ) )
  252. {
  253. goto FatalError;
  254. }
  255. return HSE_STATUS_PENDING;
  256. }
  257. hr = SendErrorResponse( pecb,
  258. "500 Error performing Query",
  259. ODBCMSG_ERROR_PERFORMING_QUERY,
  260. strError.QueryStr() );
  261. if ( FAILED( hr ) )
  262. {
  263. goto FatalError;
  264. }
  265. return HSE_STATUS_ERROR;
  266. }
  267. if ( strParams.QueryCB() )
  268. {
  269. if ( CODE_ONLY_SBCS != nCharset )
  270. {
  271. //
  272. // Convert the charset of Parameters to SJIS
  273. //
  274. hr = ConvertUrlEncodedStringToSJIS( nCharset,
  275. &strParams );
  276. if ( FAILED( hr ) )
  277. {
  278. hr = SendErrorResponseFromHr( pecb,
  279. "500 Error performing Query",
  280. ODBCMSG_ERROR_PERFORMING_QUERY,
  281. hr);
  282. if ( FAILED( hr ) )
  283. {
  284. goto FatalError;
  285. }
  286. return HSE_STATUS_ERROR;
  287. }
  288. }
  289. }
  290. }
  291. //
  292. // Walk the parameter string to do two things:
  293. //
  294. // 1) Remove escaped '\n's so we don't break parameter parsing
  295. // later on
  296. // 2) Replace all '&' parameter delimiters with real '\n' so
  297. // escaped '&'s won't get confused later on
  298. //
  299. pch = strParams.QueryStr();
  300. cch = strParams.QueryCCH();
  301. while ( *pch )
  302. {
  303. switch ( *pch )
  304. {
  305. case '%':
  306. if ( pch[1] == '0' && toupper(pch[2]) == 'A' )
  307. {
  308. pch[1] = '2';
  309. pch[2] = '0';
  310. }
  311. pch += 3;
  312. break;
  313. case '&':
  314. *pch = '\n';
  315. pch++;
  316. break;
  317. default:
  318. pch++;
  319. }
  320. }
  321. //
  322. // The path info contains the location of the query file
  323. //
  324. hr = strPath.Copy( pecb->lpszPathTranslated );
  325. if ( FAILED( hr ) )
  326. {
  327. DBGPRINTF(( DBG_CONTEXT,
  328. "Error copying query file path, hr = 0x%x.\n",
  329. hr ));
  330. hr = SendErrorResponseFromHr( pecb,
  331. "500 Error performing Query",
  332. ODBCMSG_ERROR_PERFORMING_QUERY,
  333. hr);
  334. if ( FAILED( hr ) )
  335. {
  336. goto FatalError;
  337. }
  338. return HSE_STATUS_ERROR;
  339. }
  340. FlipSlashes( strPath.QueryStr() );
  341. //
  342. // Attempt the query
  343. //
  344. BOOL fAccessDenied = FALSE;
  345. hr = DoQuery( pecb,
  346. strPath.QueryStr(),
  347. strParams.QueryStr(),
  348. &strError,
  349. nCharset,
  350. &fAccessDenied );
  351. if ( FAILED( hr ) )
  352. {
  353. // If the file was not found
  354. if ( ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) ) ||
  355. ( hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) ) ||
  356. ( hr == HRESULT_FROM_WIN32( ERROR_INVALID_NAME ) ) )
  357. {
  358. // Try to send custom error
  359. hr = SendCustomError( pecb, "404 Not Found" );
  360. if ( FAILED( hr ) )
  361. {
  362. goto FatalError;
  363. }
  364. return HSE_STATUS_PENDING;
  365. }
  366. if ( fAccessDenied )
  367. {
  368. // Try to send custom error
  369. hr = SendCustomError( pecb, "401 Unauthorized" );
  370. if ( FAILED( hr ) )
  371. {
  372. goto FatalError;
  373. }
  374. return HSE_STATUS_PENDING;
  375. }
  376. else
  377. {
  378. hr = SendErrorResponse( pecb,
  379. "500 Error performing Query",
  380. ODBCMSG_ERROR_PERFORMING_QUERY,
  381. strError.QueryStr() );
  382. if ( FAILED( hr ) )
  383. {
  384. goto FatalError;
  385. }
  386. return HSE_STATUS_ERROR;
  387. }
  388. }
  389. return HSE_STATUS_SUCCESS;
  390. FatalError:
  391. pecb->ServerSupportFunction(
  392. pecb->ConnID,
  393. HSE_REQ_SEND_RESPONSE_HEADER,
  394. (VOID*)c_sz500InternalServerError,
  395. NULL,
  396. NULL );
  397. return HSE_STATUS_ERROR;
  398. }
  399. HRESULT
  400. DoQuery(
  401. EXTENSION_CONTROL_BLOCK * pecb,
  402. const CHAR * pszQueryFile,
  403. const CHAR * pszParamList,
  404. STRA * pstrError,
  405. int nCharset,
  406. BOOL * pfAccessDenied
  407. )
  408. /*++
  409. Routine Description:
  410. Performs the actual query or retrieves the same query from the
  411. query cache
  412. Arguments:
  413. pecb - Extension context
  414. pTsvcInfo - Server info class
  415. pszQueryFile - .wdg file to use for query
  416. pszParamList - Client supplied param list
  417. pstrError - Error text to return errors in
  418. pfAccessDenied - Set to TRUE if the user was denied access
  419. Return Value:
  420. HRESULT
  421. --*/
  422. {
  423. HRESULT hr;
  424. ODBC_REQ * podbcreq;
  425. STACK_STRA( strHeaders, MAX_PATH );
  426. CHAR achInstanceMetaPath[ MAX_PATH ];
  427. DWORD dwInstanceMetaPath =
  428. sizeof( achInstanceMetaPath );
  429. CHAR achURL[ MAX_PATH ];
  430. DWORD dwURL = sizeof( achURL );
  431. STACK_STRA( strMetaPath, MAX_PATH );
  432. DWORD dwPoolIDCTimeout;
  433. //
  434. // Get the metapath for the current request
  435. //
  436. if( !pecb->GetServerVariable( pecb->ConnID,
  437. "INSTANCE_META_PATH",
  438. achInstanceMetaPath,
  439. &dwInstanceMetaPath ) ||
  440. !pecb->GetServerVariable( pecb->ConnID,
  441. "URL",
  442. achURL,
  443. &dwURL ) )
  444. {
  445. return E_FAIL;
  446. }
  447. hr = strMetaPath.Copy( achInstanceMetaPath, dwInstanceMetaPath - 1 );
  448. if( FAILED( hr ) )
  449. {
  450. DBGPRINTF(( DBG_CONTEXT,
  451. "Error copying InstanceMetaPath, hr = 0x%x.\n",
  452. hr ));
  453. return hr;
  454. }
  455. hr = strMetaPath.Append( "/Root" );
  456. if( FAILED( hr ) )
  457. {
  458. DBGPRINTF(( DBG_CONTEXT,
  459. "Error appending metapath, hr = 0x%x.\n",
  460. hr ));
  461. return hr;
  462. }
  463. hr = strMetaPath.Append( achURL, dwURL - 1 );
  464. if( FAILED( hr ) )
  465. {
  466. DBGPRINTF(( DBG_CONTEXT,
  467. "Error appending URL, hr = 0x%x.\n",
  468. hr ));
  469. return hr;
  470. }
  471. //
  472. // Get the HTTPODBC metadata PoolIDCTimeout
  473. //
  474. hr = GetPoolIDCTimeout( ( unsigned char * )strMetaPath.QueryStr(),
  475. &dwPoolIDCTimeout );
  476. if( FAILED( hr ) )
  477. {
  478. dwPoolIDCTimeout = IDC_POOL_TIMEOUT;
  479. }
  480. //
  481. // Create an odbc request as we will either use it for the query
  482. // or as the key for the cache lookup
  483. //
  484. podbcreq = new ODBC_REQ( pecb,
  485. dwPoolIDCTimeout,
  486. nCharset );
  487. if( !podbcreq )
  488. {
  489. pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
  490. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  491. }
  492. hr = podbcreq->Create( pszQueryFile, pszParamList );
  493. if ( FAILED( hr ) )
  494. {
  495. DBGPRINTF(( DBG_CONTEXT,
  496. "Error creating ODBC_REQ object, hr = 0x%x.\n",
  497. hr ));
  498. // Best effort
  499. pstrError->LoadString( GetLastError() );
  500. delete podbcreq;
  501. podbcreq = NULL;
  502. return hr;
  503. }
  504. //
  505. // Check to see if user already authentified
  506. //
  507. CHAR achLoggedOnUser[UNLEN + 1];
  508. DWORD dwLoggedOnUser = sizeof( achLoggedOnUser );
  509. BOOL fIsAuth = pecb->GetServerVariable( (HCONN)pecb->ConnID,
  510. "LOGON_USER",
  511. achLoggedOnUser,
  512. &dwLoggedOnUser ) &&
  513. achLoggedOnUser[0] != '\0';
  514. //
  515. // Check to see if the client specified "Pragma: no-cache"
  516. //
  517. /* We don't do cache on HTTPODBC any more
  518. if ( pecb->GetServerVariable( pecb->ConnID,
  519. "HTTP_PRAGMA",
  520. achPragmas,
  521. &cbPragmas ))
  522. {
  523. CHAR * pch;
  524. //
  525. // Look for "no-cache"
  526. //
  527. pch = _strupr( achPragmas );
  528. while ( pch = strchr( pch, 'N' ))
  529. {
  530. if ( !memcmp( pch, "NO-CACHE", 8 ))
  531. {
  532. fRetrieveFromCache = FALSE;
  533. goto Found;
  534. }
  535. pch++;
  536. }
  537. }*/
  538. //
  539. // Open the query file and do the query
  540. //
  541. hr = podbcreq->OpenQueryFile( pfAccessDenied );
  542. if( FAILED( hr ) )
  543. {
  544. DBGPRINTF(( DBG_CONTEXT,
  545. "Error opening query file, hr = 0x%x.\n",
  546. hr ));
  547. goto Exit;
  548. }
  549. hr = podbcreq->ParseAndQuery( achLoggedOnUser );
  550. if( FAILED( hr ) )
  551. {
  552. goto Exit;
  553. }
  554. hr = podbcreq->AppendHeaders( &strHeaders );
  555. if( FAILED( hr ) )
  556. {
  557. DBGPRINTF(( DBG_CONTEXT,
  558. "Error appending headers, hr = 0x%x.\n",
  559. hr ));
  560. goto Exit;
  561. }
  562. hr = podbcreq->OutputResults( (ODBC_REQ_CALLBACK)OdbcExtensionOutput,
  563. pecb, &strHeaders,
  564. (ODBC_REQ_HEADER)OdbcExtensionHeader,
  565. fIsAuth,
  566. pfAccessDenied );
  567. if ( FAILED( hr ) )
  568. {
  569. DBGPRINTF(( DBG_CONTEXT,
  570. "Error in OutputResults(), hr = 0x%x.\n",
  571. hr ));
  572. goto Exit;
  573. }
  574. delete podbcreq;
  575. podbcreq = NULL;
  576. return S_OK;
  577. Exit:
  578. //
  579. // Get the ODBC error to report to client
  580. //
  581. podbcreq->GetLastErrorText( pstrError );
  582. delete podbcreq;
  583. podbcreq = NULL;
  584. return hr;
  585. }
  586. DWORD
  587. OdbcExtensionOutput(
  588. EXTENSION_CONTROL_BLOCK * pecb,
  589. const CHAR * pchOutput,
  590. DWORD cbOutput
  591. )
  592. {
  593. if ( !pecb->WriteClient( pecb->ConnID,
  594. (VOID *) pchOutput,
  595. &cbOutput,
  596. 0 ))
  597. {
  598. return GetLastError();
  599. }
  600. return NO_ERROR;
  601. }
  602. BOOL
  603. OdbcExtensionHeader(
  604. EXTENSION_CONTROL_BLOCK * pecb,
  605. const CHAR * pchStatus,
  606. const CHAR * pchHeaders
  607. )
  608. {
  609. return pecb->ServerSupportFunction(
  610. pecb->ConnID,
  611. HSE_REQ_SEND_RESPONSE_HEADER,
  612. (LPDWORD) "200 OK",
  613. NULL,
  614. (LPDWORD) pchHeaders );
  615. }
  616. BOOL
  617. WINAPI
  618. DllMain(
  619. HINSTANCE hDll,
  620. DWORD dwReason,
  621. LPVOID lpvReserved
  622. )
  623. {
  624. switch ( dwReason )
  625. {
  626. case DLL_PROCESS_ATTACH:
  627. CREATE_DEBUG_PRINT_OBJECT( "httpodbc.dll");
  628. SET_DEBUG_FLAGS( 0 );
  629. DisableThreadLibraryCalls( hDll );
  630. break;
  631. case DLL_PROCESS_DETACH:
  632. DELETE_DEBUG_PRINT_OBJECT();
  633. break;
  634. default:
  635. break;
  636. }
  637. return TRUE;
  638. }
  639. BOOL
  640. GetExtensionVersion(
  641. HSE_VERSION_INFO * pver
  642. )
  643. {
  644. HRESULT hr;
  645. pver->dwExtensionVersion = MAKELONG( 0, 3 );
  646. strcpy( pver->lpszExtensionDesc,
  647. "Microsoft HTTP ODBC Gateway, v3.0" );
  648. hr = ODBCInitialize();
  649. if ( FAILED( hr ) )
  650. {
  651. DBGPRINTF(( DBG_CONTEXT,
  652. "Error on HTTPODBC initialization." ));
  653. SetLastError( hr );
  654. return FALSE;
  655. }
  656. hr = CoCreateInstance(
  657. CLSID_MSAdminBase,
  658. NULL,
  659. CLSCTX_ALL,
  660. IID_IMSAdminBase,
  661. (void**)&g_pMetabase
  662. );
  663. if ( FAILED( hr ) )
  664. {
  665. DBGPRINTF(( DBG_CONTEXT,
  666. "Error getting IMSAdminBase interface." ));
  667. SetLastError( hr );
  668. ODBCTerminate();
  669. return FALSE;
  670. }
  671. return TRUE;
  672. }
  673. BOOL
  674. TerminateExtension(
  675. DWORD dwFlags
  676. )
  677. {
  678. ODBCTerminate();
  679. if ( g_pMetabase )
  680. {
  681. g_pMetabase->Release();
  682. g_pMetabase = NULL;
  683. }
  684. return TRUE;
  685. }
  686. HRESULT
  687. ODBCInitialize(
  688. VOID
  689. )
  690. {
  691. HRESULT hr = E_FAIL;
  692. HKEY hKey;
  693. if( !InitializeOdbcPool() )
  694. {
  695. return hr;
  696. }
  697. hr = ODBC_REQ::Initialize();
  698. if( FAILED( hr ) )
  699. {
  700. DBGPRINTF(( DBG_CONTEXT,
  701. "Error initializing ODBC_REQ, hr = 0x%x.\n",
  702. hr ));
  703. TerminateOdbcPool();
  704. return hr;
  705. }
  706. hr = ODBC_STATEMENT::Initialize();
  707. if( FAILED( hr ) )
  708. {
  709. DBGPRINTF(( DBG_CONTEXT,
  710. "Error initializing ODBC_STATEMENT, hr = 0x%x.\n",
  711. hr ));
  712. TerminateOdbcPool();
  713. ODBC_REQ::Terminate();
  714. return hr;
  715. }
  716. hr = ODBC_CONN_POOL::Initialize();
  717. if( FAILED( hr ) )
  718. {
  719. DBGPRINTF(( DBG_CONTEXT,
  720. "Error initializing ODBC_CONN_POOL, hr = 0x%x.\n",
  721. hr ));
  722. TerminateOdbcPool();
  723. ODBC_REQ::Terminate();
  724. ODBC_STATEMENT::Terminate();
  725. return hr;
  726. }
  727. g_fIsSystemDBCS = IsSystemDBCS();
  728. return hr;
  729. }
  730. VOID
  731. ODBCTerminate(
  732. VOID
  733. )
  734. {
  735. TerminateOdbcPool();
  736. ODBC_REQ::Terminate();
  737. ODBC_STATEMENT::Terminate();
  738. ODBC_CONN_POOL::Terminate();
  739. }
  740. CHAR * skipwhite( CHAR * pch )
  741. {
  742. CHAR ch;
  743. while ( 0 != (ch = *pch) )
  744. {
  745. if ( ' ' != ch && '\t' != ch )
  746. break;
  747. ++pch;
  748. }
  749. return pch;
  750. }
  751. CHAR * nextline( CHAR * pch )
  752. {
  753. CHAR ch;
  754. while ( 0 != (ch = *pch) )
  755. {
  756. ++pch;
  757. if ( '\n' == ch )
  758. {
  759. break;
  760. }
  761. }
  762. return pch;
  763. }
  764. HRESULT
  765. GetIDCCharset(
  766. CONST CHAR * pszPath,
  767. int * pnCharset,
  768. STRA * pstrError
  769. )
  770. {
  771. BUFFER buff;
  772. HANDLE hFile;
  773. DWORD dwSize;
  774. DWORD dwErr;
  775. #define QUERYFILE_READSIZE 4096
  776. if ( (!pnCharset) || (!pszPath) )
  777. {
  778. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  779. }
  780. *pnCharset = CODE_ONLY_SBCS;
  781. if ( !buff.Resize( QUERYFILE_READSIZE + sizeof(TCHAR) ) )
  782. {
  783. pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
  784. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  785. }
  786. hFile = CreateFileA( pszPath,
  787. GENERIC_READ,
  788. FILE_SHARE_READ,
  789. NULL,
  790. OPEN_EXISTING,
  791. FILE_ATTRIBUTE_NORMAL |
  792. FILE_FLAG_SEQUENTIAL_SCAN,
  793. NULL );
  794. if ( ( INVALID_HANDLE_VALUE == hFile ) ||
  795. ( NULL == hFile ) )
  796. {
  797. LPCSTR apsz[1];
  798. DBGPRINTF(( DBG_CONTEXT,
  799. "Error opening query file, hr = 0x%x.\n",
  800. HRESULT_FROM_WIN32( GetLastError() )
  801. ));
  802. apsz[0] = pszPath;
  803. pstrError->FormatString( ODBCMSG_QUERY_FILE_NOT_FOUND,
  804. apsz,
  805. IIS_RESOURCE_DLL_NAME_A );
  806. return HRESULT_FROM_WIN32( GetLastError() );
  807. }
  808. if ( !ReadFile( hFile,
  809. buff.QueryPtr(),
  810. QUERYFILE_READSIZE,
  811. &dwSize,
  812. NULL ) )
  813. {
  814. dwErr = GetLastError();
  815. pstrError->LoadString( dwErr );
  816. CloseHandle( hFile );
  817. return HRESULT_FROM_WIN32( dwErr );
  818. }
  819. CloseHandle( hFile );
  820. *((CHAR *) buff.QueryPtr() + dwSize) = '\0';
  821. CHAR * pch = (CHAR *)buff.QueryPtr();
  822. while ( *pch )
  823. {
  824. pch = skipwhite( pch );
  825. if ( 'C' == toupper( *pch ) &&
  826. !_strnicmp( IDC_FIELDNAME_CHARSET,
  827. pch,
  828. sizeof(IDC_FIELDNAME_CHARSET)-1 ) )
  829. {
  830. pch += sizeof(IDC_FIELDNAME_CHARSET) - 1;
  831. pch = skipwhite( pch );
  832. if ( 932 == GetACP() )
  833. {
  834. if ( !_strnicmp( IDC_CHARSET_JIS1,
  835. pch,
  836. sizeof(IDC_CHARSET_JIS1)-1 ) ||
  837. !_strnicmp( IDC_CHARSET_JIS2,
  838. pch,
  839. sizeof(IDC_CHARSET_JIS2)-1 ) )
  840. {
  841. *pnCharset = CODE_JPN_JIS;
  842. break;
  843. }
  844. else if ( !_strnicmp( IDC_CHARSET_EUCJP,
  845. pch,
  846. sizeof(IDC_CHARSET_EUCJP)-1 ) )
  847. {
  848. *pnCharset = CODE_JPN_EUC;
  849. break;
  850. }
  851. else if ( !_strnicmp( IDC_CHARSET_SJIS,
  852. pch,
  853. sizeof(IDC_CHARSET_SJIS)-1 ) )
  854. {
  855. *pnCharset = CODE_ONLY_SBCS;
  856. break;
  857. }
  858. else
  859. {
  860. LPCSTR apsz[1];
  861. //
  862. // illegal value for Charset: field
  863. //
  864. apsz[0] = pszPath;
  865. pstrError->FormatString( ODBCMSG_UNREC_FIELD,
  866. apsz,
  867. IIS_RESOURCE_DLL_NAME_A );
  868. return E_FAIL;
  869. }
  870. }
  871. //
  872. // please add code here to support other FE character encoding(FEFEFE)
  873. //
  874. // else if ( 949 == GetACP() )
  875. // ...
  876. }
  877. pch = nextline( pch );
  878. }
  879. return S_OK;
  880. }
  881. HRESULT
  882. ConvertUrlEncodedStringToSJIS(
  883. int nCharset,
  884. STRA * pstrParams
  885. )
  886. {
  887. STACK_STRA( strTemp, MAX_PATH);
  888. int cbSJISSize;
  889. int nResult;
  890. HRESULT hr;
  891. //
  892. // Pre-process the URL encoded parameters
  893. //
  894. for ( char * pch = pstrParams->QueryStr(); *pch; ++pch )
  895. {
  896. if ( *pch == '&' )
  897. {
  898. *pch = '\n';
  899. }
  900. else if ( *pch == '+' )
  901. {
  902. *pch = ' ';
  903. }
  904. }
  905. //
  906. // URL decoding (decode %nn only)
  907. //
  908. hr = pstrParams->Unescape();
  909. if( FAILED( hr ) )
  910. {
  911. DBGPRINTF(( DBG_CONTEXT,
  912. "Error unescaping param string, hr = 0x%x.\n",
  913. hr ));
  914. return hr;
  915. }
  916. //
  917. // charset conversion
  918. //
  919. hr = pstrParams->Clone( &strTemp );
  920. if ( FAILED( hr ) )
  921. {
  922. DBGPRINTF(( DBG_CONTEXT,
  923. "Error cloning param string, hr = 0x%x.\n",
  924. hr ));
  925. return hr;
  926. }
  927. hr = strTemp.Copy( pstrParams->QueryStr() );
  928. if ( FAILED( hr ) )
  929. {
  930. DBGPRINTF(( DBG_CONTEXT,
  931. "Error copying param string, hr = 0x%x.\n",
  932. hr ));
  933. return hr;
  934. }
  935. cbSJISSize = UNIX_to_PC( GetACP(),
  936. nCharset,
  937. (UCHAR *)strTemp.QueryStr(),
  938. strTemp.QueryCB(),
  939. NULL,
  940. 0 );
  941. hr = pstrParams->Resize( cbSJISSize + sizeof(TCHAR) );
  942. if ( FAILED( hr ) )
  943. {
  944. DBGPRINTF(( DBG_CONTEXT,
  945. "Error resizing param string buffer, hr = 0x%x.\n",
  946. hr ));
  947. return hr;
  948. }
  949. nResult = UNIX_to_PC( GetACP(),
  950. nCharset,
  951. (UCHAR *)strTemp.QueryStr(),
  952. strTemp.QueryCB(),
  953. (UCHAR *)pstrParams->QueryStr(),
  954. cbSJISSize );
  955. if ( -1 == nResult || nResult != cbSJISSize )
  956. {
  957. return E_FAIL;
  958. }
  959. DBG_REQUIRE ( pstrParams->SetLen( cbSJISSize) );
  960. //
  961. // URL encoding
  962. //
  963. hr = pstrParams->Escape();
  964. if ( FAILED( hr ) )
  965. {
  966. DBGPRINTF(( DBG_CONTEXT,
  967. "Error escaping param string, hr = 0x%x.\n",
  968. hr ));
  969. return hr;
  970. }
  971. return S_OK;
  972. }
  973. BOOL
  974. IsSystemDBCS(
  975. VOID
  976. )
  977. {
  978. WORD wPrimaryLangID = PRIMARYLANGID( GetSystemDefaultLangID() );
  979. return ( wPrimaryLangID == LANG_JAPANESE ||
  980. wPrimaryLangID == LANG_CHINESE ||
  981. wPrimaryLangID == LANG_KOREAN );
  982. }
  983. CHAR * FlipSlashes( CHAR * pszPath )
  984. {
  985. CHAR ch;
  986. CHAR * pszScan = pszPath;
  987. while( ( ch = *pszScan ) != '\0' )
  988. {
  989. if( ch == '/' )
  990. {
  991. *pszScan = '\\';
  992. }
  993. pszScan++;
  994. }
  995. return pszPath;
  996. } // FlipSlashes
  997. HRESULT
  998. GetPoolIDCTimeout(
  999. unsigned char * szMdPath,
  1000. DWORD * pdwPoolIDCTimeout
  1001. )
  1002. {
  1003. HRESULT hr = NOERROR;
  1004. DWORD cbBufferRequired;
  1005. const DWORD dwTimeout = 2000;
  1006. STACK_STRU( strMetaPath, MAX_PATH );
  1007. if ( g_pMetabase == NULL )
  1008. {
  1009. return E_NOINTERFACE;
  1010. }
  1011. hr = strMetaPath.CopyA( (LPSTR)szMdPath );
  1012. if( FAILED(hr) )
  1013. {
  1014. return hr;
  1015. }
  1016. METADATA_HANDLE hKey = NULL;
  1017. METADATA_RECORD MetadataRecord;
  1018. hr = g_pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  1019. strMetaPath.QueryStr(),
  1020. METADATA_PERMISSION_READ,
  1021. dwTimeout,
  1022. &hKey
  1023. );
  1024. if( SUCCEEDED(hr) )
  1025. {
  1026. MetadataRecord.dwMDIdentifier = MD_POOL_IDC_TIMEOUT;
  1027. MetadataRecord.dwMDAttributes = METADATA_INHERIT;
  1028. MetadataRecord.dwMDUserType = IIS_MD_UT_FILE;
  1029. MetadataRecord.dwMDDataType = DWORD_METADATA;
  1030. MetadataRecord.dwMDDataLen = sizeof( DWORD );
  1031. MetadataRecord.pbMDData = (unsigned char *) pdwPoolIDCTimeout;
  1032. MetadataRecord.dwMDDataTag = 0;
  1033. hr = g_pMetabase->GetData( hKey,
  1034. L"",
  1035. &MetadataRecord,
  1036. &cbBufferRequired
  1037. );
  1038. g_pMetabase->CloseKey( hKey );
  1039. }
  1040. return hr;
  1041. }
  1042. HRESULT
  1043. SendCustomError(
  1044. EXTENSION_CONTROL_BLOCK *pecb,
  1045. const CHAR *pszStatus
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. reports custom error
  1050. Arguments:
  1051. pecb
  1052. pszStatus - Status to be reported. If NULL "500" will be sent.
  1053. Return Value:
  1054. HRESULT
  1055. --*/
  1056. {
  1057. // Locals
  1058. HRESULT hr = S_OK;
  1059. BOOL fRet;
  1060. HSE_CUSTOM_ERROR_INFO *pCustomErrorInfo = NULL;
  1061. DWORD cch;
  1062. // Check args
  1063. DBG_ASSERT( pecb );
  1064. if ( !pecb )
  1065. {
  1066. hr = E_INVALIDARG;
  1067. goto Exit;
  1068. }
  1069. // If supplied status
  1070. if (pszStatus)
  1071. {
  1072. cch = strlen( pszStatus )+1;
  1073. }
  1074. else
  1075. {
  1076. pszStatus = c_sz500InternalServerError;
  1077. cch = ARRAYSIZE( c_sz500InternalServerError );
  1078. }
  1079. // Allocate
  1080. pCustomErrorInfo = (HSE_CUSTOM_ERROR_INFO*)(new BYTE[sizeof(HSE_CUSTOM_ERROR_INFO)+cch]);
  1081. if ( !pCustomErrorInfo )
  1082. {
  1083. hr = HRESULT_FROM_WIN32( GetLastError() );
  1084. goto Exit;
  1085. }
  1086. pCustomErrorInfo->pszStatus = (CHAR*)pCustomErrorInfo+sizeof(HSE_CUSTOM_ERROR_INFO);
  1087. // Set the callback
  1088. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  1089. HSE_REQ_IO_COMPLETION,
  1090. CustomErrorCompletion,
  1091. 0,
  1092. (DWORD*)pCustomErrorInfo );
  1093. if ( !fRet )
  1094. {
  1095. hr = HRESULT_FROM_WIN32( GetLastError() );
  1096. goto Exit;
  1097. }
  1098. // All custom errors must be asynchronous
  1099. pCustomErrorInfo->fAsync = TRUE;
  1100. // Copy the status
  1101. memmove( pCustomErrorInfo->pszStatus,
  1102. pszStatus,
  1103. cch*sizeof(CHAR));
  1104. pCustomErrorInfo->uHttpSubError = 0;
  1105. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  1106. HSE_REQ_SEND_CUSTOM_ERROR,
  1107. pCustomErrorInfo,
  1108. NULL,
  1109. NULL );
  1110. if ( !fRet )
  1111. {
  1112. hr = HRESULT_FROM_WIN32( GetLastError() );
  1113. goto Exit;
  1114. }
  1115. // Don't free
  1116. pCustomErrorInfo = NULL;
  1117. Exit:
  1118. // Cleanup
  1119. if (pCustomErrorInfo)
  1120. {
  1121. delete[] (BYTE*)pCustomErrorInfo;
  1122. pCustomErrorInfo = NULL;
  1123. }
  1124. return hr;
  1125. }
  1126. VOID WINAPI
  1127. CustomErrorCompletion(
  1128. EXTENSION_CONTROL_BLOCK *pecb,
  1129. PVOID pContext,
  1130. DWORD /*cbIO*/,
  1131. DWORD /*dwError*/
  1132. )
  1133. /*++
  1134. Routine Description:
  1135. completion routine (for async custom error send)
  1136. Arguments:
  1137. Return Value:
  1138. VOID
  1139. --*/
  1140. {
  1141. HRESULT hr = S_OK;
  1142. BOOL fRet;
  1143. // Check args
  1144. if ( pecb == NULL)
  1145. {
  1146. hr = E_INVALIDARG;
  1147. DBGPRINTF(( DBG_CONTEXT,
  1148. "NULL pecb in CustomErrorCompletion().\n"));
  1149. goto Exit;
  1150. }
  1151. // Notify IIS that we are done with processing
  1152. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  1153. HSE_REQ_DONE_WITH_SESSION,
  1154. NULL,
  1155. NULL,
  1156. NULL );
  1157. if ( !fRet )
  1158. {
  1159. hr = HRESULT_FROM_WIN32( GetLastError() );
  1160. DBGPRINTF(( DBG_CONTEXT,
  1161. "HSE_REQ_DONE_WITH_SESSION failed, hr = 0x%x.\n",
  1162. hr ));
  1163. goto Exit;
  1164. }
  1165. Exit:
  1166. // Cleanup
  1167. if ( pContext )
  1168. {
  1169. // Free
  1170. delete[] (BYTE*)pContext;
  1171. pContext = NULL;
  1172. }
  1173. }
  1174. HRESULT
  1175. SendErrorResponse(
  1176. EXTENSION_CONTROL_BLOCK *pecb,
  1177. const CHAR *pszStatus,
  1178. DWORD dwResID,
  1179. const CHAR *pszParam
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. reports error via HSE_REQ_SEND_RESPONSE_HEADER
  1184. Arguments:
  1185. pecb
  1186. pszStatus - Status to be reported. If NULL "500" will be sent.
  1187. dwResID - Error message to be sent in the body.
  1188. pszParam - string parameter for the message. Can NULL.
  1189. Return Value:
  1190. HRESULT
  1191. --*/
  1192. {
  1193. // Locals
  1194. HRESULT hr=S_OK;
  1195. BOOL fRet;
  1196. STRA str;
  1197. CHAR szParam[1024];
  1198. const CHAR *rgszT[1] = { szParam };
  1199. // Check args
  1200. if ( !pecb )
  1201. {
  1202. hr = E_INVALIDARG;
  1203. goto Exit;
  1204. }
  1205. // If no status given set "500 Internal Server Error"
  1206. if ( !pszStatus )
  1207. {
  1208. pszStatus = c_sz500InternalServerError;
  1209. }
  1210. if ( !pszParam )
  1211. {
  1212. // If no parameter given set emtpy string
  1213. *szParam = '\0';
  1214. }
  1215. else
  1216. {
  1217. //
  1218. // Note we terminate the error message (ODBC sometimes generates
  1219. // 22k errors)
  1220. //
  1221. strncpy( szParam,
  1222. pszParam,
  1223. ARRAYSIZE( szParam )-1 );
  1224. szParam[ ARRAYSIZE( szParam )-1 ] = '\0';
  1225. }
  1226. //
  1227. // *and* we double the buffer size we pass to FormatString()
  1228. // because the win32 API FormatMessage() has a bug that doesn't
  1229. // account for Unicode conversion
  1230. //
  1231. hr = str.FormatString( dwResID,
  1232. rgszT,
  1233. IIS_RESOURCE_DLL_NAME_A,
  1234. 2*ARRAYSIZE( szParam ) );
  1235. if ( FAILED( hr ) )
  1236. {
  1237. goto Exit;
  1238. }
  1239. // Send the error
  1240. fRet = pecb->ServerSupportFunction( pecb->ConnID,
  1241. HSE_REQ_SEND_RESPONSE_HEADER,
  1242. (DWORD*)pszStatus,
  1243. NULL,
  1244. (DWORD*)str.QueryStr() );
  1245. if ( !fRet )
  1246. {
  1247. hr = HRESULT_FROM_WIN32( GetLastError() );
  1248. goto Exit;
  1249. }
  1250. Exit:
  1251. // Done
  1252. return hr;
  1253. }
  1254. HRESULT
  1255. SendErrorResponseFromHr(
  1256. EXTENSION_CONTROL_BLOCK *pecb,
  1257. const CHAR *pszStatus,
  1258. DWORD dwResID,
  1259. HRESULT hrError
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. reports error via HSE_REQ_SEND_RESPONSE_HEADER
  1264. Arguments:
  1265. pecb
  1266. pszStatus - Status to be reported. If NULL "500" will be sent.
  1267. dwResID - Error message to be sent in the body.
  1268. hrError - HRESULT to be reported. The description of the error will be
  1269. used as a parameter for the message. MUST be a failure.
  1270. Return Value:
  1271. HRESULT
  1272. --*/
  1273. {
  1274. // Locals
  1275. HRESULT hr=S_OK;
  1276. STRA strError;
  1277. // Check args
  1278. if ( !pecb )
  1279. {
  1280. hr = E_INVALIDARG;
  1281. goto Exit;
  1282. }
  1283. if ( SUCCEEDED( hrError ) )
  1284. {
  1285. hr = E_INVALIDARG;
  1286. goto Exit;
  1287. }
  1288. // Get the description of the last error
  1289. hr = strError.LoadString( WIN32_FROM_HRESULT( hrError ),
  1290. (LPCSTR)NULL );
  1291. if ( FAILED( hr ) )
  1292. {
  1293. goto Exit;
  1294. }
  1295. // Call SendErrorResponse
  1296. hr = SendErrorResponse( pecb,
  1297. pszStatus,
  1298. dwResID,
  1299. strError.QueryStr() );
  1300. Exit:
  1301. // Done
  1302. return hr;
  1303. }