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.

1268 lines
28 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. extern "C" {
  22. BOOL
  23. WINAPI
  24. DLLEntry(
  25. HINSTANCE hDll,
  26. DWORD dwReason,
  27. LPVOID lpvReserved
  28. );
  29. }
  30. //
  31. // Globals
  32. //
  33. IMSAdminBase * g_pMetabase = NULL;
  34. //
  35. // Is this system DBCS?
  36. //
  37. BOOL g_fIsSystemDBCS;
  38. //
  39. // Prototypes
  40. //
  41. HRESULT
  42. ODBCInitialize(
  43. VOID
  44. );
  45. VOID
  46. ODBCTerminate(
  47. VOID
  48. );
  49. HRESULT
  50. DoQuery(
  51. EXTENSION_CONTROL_BLOCK * pecb,
  52. const CHAR * pszQueryFile,
  53. const CHAR * pszParamList,
  54. STRA * pstrError,
  55. int nCharset,
  56. BOOL * pfAccessDenied
  57. );
  58. DWORD
  59. OdbcExtensionOutput(
  60. EXTENSION_CONTROL_BLOCK * pecb,
  61. const CHAR * pchOutput,
  62. DWORD cbOutput
  63. );
  64. BOOL
  65. OdbcExtensionHeader(
  66. EXTENSION_CONTROL_BLOCK * pecb,
  67. const CHAR * pchStatus,
  68. const CHAR * pchHeaders
  69. );
  70. BOOL LookupHttpSymbols( // eliminated, check its functionality
  71. const CHAR * pszSymbolName,
  72. STRA * pstrSymbolValue
  73. );
  74. HRESULT
  75. GetIDCCharset(
  76. CONST CHAR * pszPath,
  77. int * pnCharset,
  78. STRA * pstrError
  79. );
  80. HRESULT
  81. ConvertUrlEncodedStringToSJIS(
  82. int nCharset,
  83. STRA * pstrParams
  84. );
  85. BOOL
  86. IsSystemDBCS(
  87. VOID
  88. );
  89. CHAR *
  90. FlipSlashes(
  91. CHAR * pszPath
  92. );
  93. HRESULT
  94. GetPoolIDCTimeout(
  95. unsigned char * szMdPath,
  96. DWORD * pdwPoolIDCTimeout
  97. );
  98. DWORD
  99. HttpExtensionProc(
  100. EXTENSION_CONTROL_BLOCK * pecb
  101. )
  102. {
  103. STACK_STRA( strPath, MAX_PATH);
  104. STACK_STRA( strParams, MAX_PATH);
  105. STRA strError;
  106. CHAR * pch;
  107. DWORD cch;
  108. int nCharset;
  109. HRESULT hr;
  110. //
  111. // Make sure ODBC is loaded
  112. //
  113. if ( !LoadODBC() )
  114. {
  115. STRA str;
  116. str.FormatString( ODBCMSG_CANT_LOAD_ODBC,
  117. NULL,
  118. HTTP_ODBC_DLL );
  119. pecb->ServerSupportFunction( pecb->ConnID,
  120. HSE_REQ_SEND_RESPONSE_HEADER,
  121. "500 Unable to load ODBC",
  122. NULL,
  123. (LPDWORD) str.QueryStr() );
  124. return HSE_STATUS_ERROR;
  125. }
  126. //
  127. // We currently only support the GET and POST methods
  128. //
  129. if ( !strcmp( pecb->lpszMethod, "POST" ))
  130. {
  131. if ( _stricmp( pecb->lpszContentType,
  132. "application/x-www-form-urlencoded" ) )
  133. {
  134. goto BadRequest;
  135. }
  136. //
  137. // The query params are in the extra data, add a few bytes in
  138. // case we need to double "'"
  139. //
  140. hr = strParams.Resize( pecb->cbAvailable + sizeof(TCHAR) + 3);
  141. if ( FAILED( hr ) )
  142. {
  143. DBGPRINTF(( DBG_CONTEXT,
  144. "Error resizing param buffer, hr = 0x%x.\n",
  145. hr ));
  146. return HSE_STATUS_ERROR;
  147. }
  148. hr = strParams.Copy( ( const char * ) pecb->lpbData,
  149. pecb->cbAvailable );
  150. }
  151. else if ( !strcmp( pecb->lpszMethod, "GET" ) )
  152. {
  153. hr = strParams.Copy( pecb->lpszQueryString );
  154. if ( FAILED( hr ) )
  155. {
  156. DBGPRINTF(( DBG_CONTEXT,
  157. "Error copying params, hr = 0x%x.\n",
  158. hr ));
  159. return HSE_STATUS_ERROR;
  160. }
  161. }
  162. else
  163. {
  164. BadRequest:
  165. STRA str;
  166. str.FormatString( ODBCMSG_UNSUPPORTED_METHOD,
  167. NULL,
  168. HTTP_ODBC_DLL );
  169. pecb->ServerSupportFunction(
  170. pecb->ConnID,
  171. HSE_REQ_SEND_RESPONSE_HEADER,
  172. "400 Unsupported method",
  173. NULL,
  174. (LPDWORD) str.QueryStr() );
  175. return HSE_STATUS_ERROR;
  176. }
  177. //
  178. // "Charset" field is enabled for CP932 (Japanese) only in
  179. // this version.
  180. //
  181. if ( 932 != GetACP() )
  182. {
  183. nCharset = CODE_ONLY_SBCS;
  184. }
  185. else
  186. {
  187. //
  188. // Get the charset from .idc file
  189. //
  190. if ( FAILED( GetIDCCharset( pecb->lpszPathTranslated,
  191. &nCharset,
  192. &strError ) ) )
  193. {
  194. STRA str;
  195. LPCSTR apsz[1];
  196. apsz[0] = strError.QueryStr();
  197. str.FormatString( ODBCMSG_ERROR_PERFORMING_QUERY,
  198. apsz,
  199. HTTP_ODBC_DLL,
  200. 1024 + strError.QueryCB() );
  201. pecb->ServerSupportFunction(
  202. pecb->ConnID,
  203. HSE_REQ_SEND_RESPONSE_HEADER,
  204. (LPDWORD) "500 Error performing query",
  205. NULL,
  206. (LPDWORD) str.QueryStr() );
  207. return HSE_STATUS_ERROR;
  208. }
  209. if ( strParams.QueryCB() )
  210. {
  211. if ( CODE_ONLY_SBCS != nCharset )
  212. {
  213. //
  214. // Convert the charset of Parameters to SJIS
  215. //
  216. if ( FAILED( ConvertUrlEncodedStringToSJIS(
  217. nCharset,
  218. &strParams ) ) )
  219. {
  220. STRA str;
  221. strError.LoadString( GetLastError(),
  222. ( LPCSTR ) NULL );
  223. str.FormatString( ODBCMSG_ERROR_PERFORMING_QUERY,
  224. NULL,
  225. HTTP_ODBC_DLL );
  226. pecb->ServerSupportFunction(
  227. pecb->ConnID,
  228. HSE_REQ_SEND_RESPONSE_HEADER,
  229. (LPDWORD) "500 Error performing Query",
  230. NULL,
  231. (LPDWORD) str.QueryStr() );
  232. return HSE_STATUS_ERROR;
  233. }
  234. }
  235. }
  236. }
  237. //
  238. // Walk the parameter string to do three things:
  239. //
  240. // 1) Double all single quotes to prevent SQL quoting problem
  241. // 2) Remove escaped '\n's so we don't break parameter parsing
  242. // later on
  243. // 3) Replace all '&' parameter delimiters with real '\n' so
  244. // escaped '&'s won't get confused later on
  245. //
  246. pch = strParams.QueryStr();
  247. cch = strParams.QueryCCH();
  248. while ( *pch )
  249. {
  250. switch ( *pch )
  251. {
  252. case '%':
  253. if ( pch[1] == '0' && toupper(pch[2]) == 'A' )
  254. {
  255. pch[1] = '2';
  256. pch[2] = '0';
  257. }
  258. else if ( pch[1] == '2' && pch[2] == '7' )
  259. {
  260. //
  261. // This is an escaped single quote
  262. //
  263. // Include null
  264. if ( strParams.QueryCB() < (cch + 4) )
  265. {
  266. DWORD Pos = DIFF(pch - strParams.QueryStr());
  267. hr = strParams.Resize( cch + 4 );
  268. if ( FAILED( hr ) )
  269. {
  270. return HSE_STATUS_ERROR;
  271. }
  272. //
  273. // Adjust for possible pointer shift
  274. //
  275. pch = strParams.QueryStr() + Pos;
  276. }
  277. //
  278. // Note the memory copy just doubles the existing
  279. // quote
  280. //
  281. memmove( pch+3,
  282. pch,
  283. (cch + 1) - DIFF(pch - strParams.QueryStr()) );
  284. // Adjust for the additional '%27'
  285. cch += 3;
  286. pch += 3;
  287. }
  288. pch += 3;
  289. break;
  290. case '\'':
  291. if ( strParams.QueryCB() < (cch + 2) )
  292. {
  293. DWORD Pos = DIFF(pch - strParams.QueryStr());
  294. hr = strParams.Resize( cch + 2 );
  295. if ( FAILED( hr ) )
  296. {
  297. return HSE_STATUS_ERROR;
  298. }
  299. //
  300. // Adjust for possible pointer shift
  301. //
  302. pch = strParams.QueryStr() + Pos;
  303. }
  304. //
  305. // Note the memory copy just doubles the existing quote
  306. //
  307. memmove( pch+1,
  308. pch,
  309. (cch + 1) - DIFF(pch - strParams.QueryStr()) );
  310. pch += 2;
  311. // Adjust for the additional '''
  312. cch++;
  313. break;
  314. case '&':
  315. *pch = '\n';
  316. pch++;
  317. break;
  318. default:
  319. pch++;
  320. }
  321. }
  322. //
  323. // The path info contains the location of the query file
  324. //
  325. hr = strPath.Copy( pecb->lpszPathTranslated );
  326. if ( FAILED( hr ) )
  327. {
  328. DBGPRINTF(( DBG_CONTEXT,
  329. "Error copying query file path, hr = 0x%x.\n",
  330. hr ));
  331. return HSE_STATUS_ERROR;
  332. }
  333. FlipSlashes( strPath.QueryStr() );
  334. //
  335. // Attempt the query
  336. //
  337. BOOL fAccessDenied = FALSE;
  338. hr = DoQuery( pecb,
  339. strPath.QueryStr(),
  340. strParams.QueryStr(),
  341. &strError,
  342. nCharset,
  343. &fAccessDenied );
  344. if ( FAILED( hr ) )
  345. {
  346. if ( fAccessDenied )
  347. {
  348. pecb->ServerSupportFunction( pecb->ConnID,
  349. HSE_REQ_SEND_RESPONSE_HEADER,
  350. (LPDWORD) "401 Authentication Required",
  351. NULL,
  352. NULL );
  353. return HSE_STATUS_ERROR;
  354. }
  355. else
  356. {
  357. STRA str;
  358. LPCSTR apsz[1];
  359. apsz[0] = strError.QueryStr();
  360. //
  361. // Note we terminate the error message (ODBC sometimes generates
  362. // 22k errors) *and* we double the buffer size we pass to FormatString()
  363. // because the win32 API FormatMessage() has a bug that doesn't
  364. // account for Unicode conversion
  365. //
  366. if ( strlen( apsz[0] ) > 1024 ) {
  367. ((LPSTR)apsz[0])[1024] = '\0';
  368. }
  369. str.FormatString( ODBCMSG_ERROR_PERFORMING_QUERY,
  370. apsz,
  371. HTTP_ODBC_DLL,
  372. 1024 + strError.QueryCB() );
  373. pecb->ServerSupportFunction( pecb->ConnID,
  374. HSE_REQ_SEND_RESPONSE_HEADER,
  375. (LPDWORD) "500 Error performing query",
  376. NULL,
  377. (LPDWORD) str.QueryStr() );
  378. return HSE_STATUS_ERROR;
  379. }
  380. }
  381. return HSE_STATUS_SUCCESS;
  382. }
  383. HRESULT
  384. DoQuery(
  385. EXTENSION_CONTROL_BLOCK * pecb,
  386. const CHAR * pszQueryFile,
  387. const CHAR * pszParamList,
  388. STRA * pstrError,
  389. int nCharset,
  390. BOOL * pfAccessDenied
  391. )
  392. /*++
  393. Routine Description:
  394. Performs the actual query or retrieves the same query from the
  395. query cache
  396. Arguments:
  397. pecb - Extension context
  398. pTsvcInfo - Server info class
  399. pszQueryFile - .wdg file to use for query
  400. pszParamList - Client supplied param list
  401. pstrError - Error text to return errors in
  402. pfAccessDenied - Set to TRUE if the user was denied access
  403. Return Value:
  404. HRESULT
  405. --*/
  406. {
  407. HRESULT hr;
  408. ODBC_REQ * podbcreq;
  409. STACK_STRA( strHeaders, MAX_PATH );
  410. CHAR achPragmas[250];
  411. DWORD cbPragmas = sizeof(achPragmas);
  412. CHAR achInstanceMetaPath[ MAX_PATH ];
  413. DWORD dwInstanceMetaPath =
  414. sizeof( achInstanceMetaPath );
  415. CHAR achURL[ MAX_PATH ];
  416. DWORD dwURL = sizeof( achURL );
  417. STACK_STRA( strMetaPath, MAX_PATH );
  418. DWORD dwPoolIDCTimeout;
  419. DWORD dwRequiredLen;
  420. //
  421. // Get the metapath for the current request
  422. //
  423. if( !pecb->GetServerVariable( pecb->ConnID,
  424. "INSTANCE_META_PATH",
  425. achInstanceMetaPath,
  426. &dwInstanceMetaPath ) ||
  427. !pecb->GetServerVariable( pecb->ConnID,
  428. "URL",
  429. achURL,
  430. &dwURL ) )
  431. {
  432. return E_FAIL;
  433. }
  434. hr = strMetaPath.Copy( achInstanceMetaPath, dwInstanceMetaPath - 1 );
  435. if( FAILED( hr ) )
  436. {
  437. DBGPRINTF(( DBG_CONTEXT,
  438. "Error copying InstanceMetaPath, hr = 0x%x.\n",
  439. hr ));
  440. return hr;
  441. }
  442. hr = strMetaPath.Append( "/Root" );
  443. if( FAILED( hr ) )
  444. {
  445. DBGPRINTF(( DBG_CONTEXT,
  446. "Error appending metapath, hr = 0x%x.\n",
  447. hr ));
  448. return hr;
  449. }
  450. hr = strMetaPath.Append( achURL, dwURL - 1 );
  451. if( FAILED( hr ) )
  452. {
  453. DBGPRINTF(( DBG_CONTEXT,
  454. "Error appending URL, hr = 0x%x.\n",
  455. hr ));
  456. return hr;
  457. }
  458. //
  459. // Get the HTTPODBC metadata PoolIDCTimeout
  460. //
  461. hr = GetPoolIDCTimeout( ( unsigned char * )strMetaPath.QueryStr(),
  462. &dwPoolIDCTimeout );
  463. if( FAILED( hr ) )
  464. {
  465. dwPoolIDCTimeout = IDC_POOL_TIMEOUT;
  466. }
  467. //
  468. // Create an odbc request as we will either use it for the query
  469. // or as the key for the cache lookup
  470. //
  471. podbcreq = new ODBC_REQ( pecb,
  472. dwPoolIDCTimeout,
  473. nCharset );
  474. if( !podbcreq )
  475. {
  476. pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
  477. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  478. }
  479. hr = podbcreq->Create( pszQueryFile, pszParamList );
  480. if ( FAILED( hr ) )
  481. {
  482. DBGPRINTF(( DBG_CONTEXT,
  483. "Error creating ODBC_REQ object, hr = 0x%x.\n",
  484. hr ));
  485. // Best effort
  486. pstrError->LoadString( GetLastError() );
  487. delete podbcreq;
  488. podbcreq = NULL;
  489. return hr;
  490. }
  491. //
  492. // Check to see if user already authentified
  493. //
  494. CHAR achLoggedOnUser[UNLEN + 1];
  495. DWORD dwLoggedOnUser = sizeof( achLoggedOnUser );
  496. BOOL fIsAuth = pecb->GetServerVariable( (HCONN)pecb->ConnID,
  497. "LOGON_USER",
  498. achLoggedOnUser,
  499. &dwLoggedOnUser ) &&
  500. achLoggedOnUser[0] != '\0';
  501. //
  502. // Check to see if the client specified "Pragma: no-cache"
  503. //
  504. /* We don't do cache on HTTPODBC any more
  505. if ( pecb->GetServerVariable( pecb->ConnID,
  506. "HTTP_PRAGMA",
  507. achPragmas,
  508. &cbPragmas ))
  509. {
  510. CHAR * pch;
  511. //
  512. // Look for "no-cache"
  513. //
  514. pch = _strupr( achPragmas );
  515. while ( pch = strchr( pch, 'N' ))
  516. {
  517. if ( !memcmp( pch, "NO-CACHE", 8 ))
  518. {
  519. fRetrieveFromCache = FALSE;
  520. goto Found;
  521. }
  522. pch++;
  523. }
  524. }*/
  525. //
  526. // Open the query file and do the query
  527. //
  528. hr = podbcreq->OpenQueryFile( pfAccessDenied );
  529. if( FAILED( hr ) )
  530. {
  531. DBGPRINTF(( DBG_CONTEXT,
  532. "Error opening query file, hr = 0x%x.\n",
  533. hr ));
  534. goto Exit;
  535. }
  536. hr = podbcreq->ParseAndQuery( achLoggedOnUser );
  537. if( FAILED( hr ) )
  538. {
  539. goto Exit;
  540. }
  541. hr = podbcreq->AppendHeaders( &strHeaders );
  542. if( FAILED( hr ) )
  543. {
  544. DBGPRINTF(( DBG_CONTEXT,
  545. "Error appending headers, hr = 0x%x.\n",
  546. hr ));
  547. goto Exit;
  548. }
  549. hr = podbcreq->OutputResults( (ODBC_REQ_CALLBACK)OdbcExtensionOutput,
  550. pecb, &strHeaders,
  551. (ODBC_REQ_HEADER)OdbcExtensionHeader,
  552. fIsAuth,
  553. pfAccessDenied );
  554. if ( FAILED( hr ) )
  555. {
  556. DBGPRINTF(( DBG_CONTEXT,
  557. "Error in OutputResults(), hr = 0x%x.\n",
  558. hr ));
  559. goto Exit;
  560. }
  561. delete podbcreq;
  562. podbcreq = NULL;
  563. return S_OK;
  564. Exit:
  565. //
  566. // Get the ODBC error to report to client
  567. //
  568. podbcreq->GetLastErrorText( pstrError );
  569. delete podbcreq;
  570. podbcreq = NULL;
  571. return hr;
  572. }
  573. DWORD
  574. OdbcExtensionOutput(
  575. EXTENSION_CONTROL_BLOCK * pecb,
  576. const CHAR * pchOutput,
  577. DWORD cbOutput
  578. )
  579. {
  580. if ( !pecb->WriteClient( pecb->ConnID,
  581. (VOID *) pchOutput,
  582. &cbOutput,
  583. 0 ))
  584. {
  585. return GetLastError();
  586. }
  587. return NO_ERROR;
  588. }
  589. BOOL
  590. OdbcExtensionHeader(
  591. EXTENSION_CONTROL_BLOCK * pecb,
  592. const CHAR * pchStatus,
  593. const CHAR * pchHeaders
  594. )
  595. {
  596. return pecb->ServerSupportFunction(
  597. pecb->ConnID,
  598. HSE_REQ_SEND_RESPONSE_HEADER,
  599. (LPDWORD) "200 OK",
  600. NULL,
  601. (LPDWORD) pchHeaders );
  602. }
  603. BOOL
  604. WINAPI
  605. DLLEntry(
  606. HINSTANCE hDll,
  607. DWORD dwReason,
  608. LPVOID lpvReserved
  609. )
  610. {
  611. DWORD err;
  612. switch ( dwReason )
  613. {
  614. case DLL_PROCESS_ATTACH:
  615. CREATE_DEBUG_PRINT_OBJECT( "httpodbc.dll");
  616. SET_DEBUG_FLAGS( 0 );
  617. DisableThreadLibraryCalls( hDll );
  618. break;
  619. case DLL_PROCESS_DETACH:
  620. DELETE_DEBUG_PRINT_OBJECT();
  621. break;
  622. default:
  623. break;
  624. }
  625. return TRUE;
  626. }
  627. BOOL
  628. GetExtensionVersion(
  629. HSE_VERSION_INFO * pver
  630. )
  631. {
  632. HRESULT hr;
  633. pver->dwExtensionVersion = MAKELONG( 0, 3 );
  634. strcpy( pver->lpszExtensionDesc,
  635. "Microsoft HTTP ODBC Gateway, v3.0" );
  636. hr = ODBCInitialize();
  637. if ( FAILED( hr ) )
  638. {
  639. DBGPRINTF(( DBG_CONTEXT,
  640. "Error on HTTPODBC initialization." ));
  641. SetLastError( hr );
  642. return FALSE;
  643. }
  644. hr = CoCreateInstance(
  645. CLSID_MSAdminBase,
  646. NULL,
  647. CLSCTX_ALL,
  648. IID_IMSAdminBase,
  649. (void**)&g_pMetabase
  650. );
  651. if ( FAILED( hr ) )
  652. {
  653. DBGPRINTF(( DBG_CONTEXT,
  654. "Error getting IMSAdminBase interface." ));
  655. SetLastError( hr );
  656. ODBCTerminate();
  657. return FALSE;
  658. }
  659. return TRUE;
  660. }
  661. BOOL
  662. TerminateExtension(
  663. DWORD dwFlags
  664. )
  665. {
  666. ODBCTerminate();
  667. if ( g_pMetabase )
  668. {
  669. g_pMetabase->Release();
  670. g_pMetabase = NULL;
  671. }
  672. return TRUE;
  673. }
  674. HRESULT
  675. ODBCInitialize(
  676. VOID
  677. )
  678. {
  679. HRESULT hr = E_FAIL;
  680. if( !InitializeOdbcPool() )
  681. {
  682. return hr;
  683. }
  684. hr = ODBC_REQ::Initialize();
  685. if( FAILED( hr ) )
  686. {
  687. DBGPRINTF(( DBG_CONTEXT,
  688. "Error initializing ODBC_REQ, hr = 0x%x.\n",
  689. hr ));
  690. TerminateOdbcPool();
  691. return hr;
  692. }
  693. hr = ODBC_STATEMENT::Initialize();
  694. if( FAILED( hr ) )
  695. {
  696. DBGPRINTF(( DBG_CONTEXT,
  697. "Error initializing ODBC_STATEMENT, hr = 0x%x.\n",
  698. hr ));
  699. TerminateOdbcPool();
  700. ODBC_REQ::Terminate();
  701. return hr;
  702. }
  703. hr = ODBC_CONN_POOL::Initialize();
  704. if( FAILED( hr ) )
  705. {
  706. DBGPRINTF(( DBG_CONTEXT,
  707. "Error initializing ODBC_CONN_POOL, hr = 0x%x.\n",
  708. hr ));
  709. TerminateOdbcPool();
  710. ODBC_REQ::Terminate();
  711. ODBC_STATEMENT::Terminate();
  712. return hr;
  713. }
  714. g_fIsSystemDBCS = IsSystemDBCS();
  715. return hr;
  716. }
  717. VOID
  718. ODBCTerminate(
  719. VOID
  720. )
  721. {
  722. TerminateOdbcPool();
  723. ODBC_REQ::Terminate();
  724. ODBC_STATEMENT::Terminate();
  725. ODBC_CONN_POOL::Terminate();
  726. }
  727. CHAR * skipwhite( CHAR * pch )
  728. {
  729. CHAR ch;
  730. while ( 0 != (ch = *pch) )
  731. {
  732. if ( ' ' != ch && '\t' != ch )
  733. break;
  734. ++pch;
  735. }
  736. return pch;
  737. }
  738. CHAR * nextline( CHAR * pch )
  739. {
  740. CHAR ch;
  741. while ( 0 != (ch = *pch) )
  742. {
  743. ++pch;
  744. if ( '\n' == ch )
  745. {
  746. break;
  747. }
  748. }
  749. return pch;
  750. }
  751. HRESULT
  752. GetIDCCharset(
  753. CONST CHAR * pszPath,
  754. int * pnCharset,
  755. STRA * pstrError
  756. )
  757. {
  758. BUFFER buff;
  759. HANDLE hFile;
  760. DWORD dwSize;
  761. HRESULT hr;
  762. DWORD dwErr;
  763. #define QUERYFILE_READSIZE 4096
  764. if ( (!pnCharset) || (!pszPath) )
  765. {
  766. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  767. }
  768. *pnCharset = CODE_ONLY_SBCS;
  769. if ( !buff.Resize( QUERYFILE_READSIZE + sizeof(TCHAR) ) )
  770. {
  771. pstrError->LoadString( ERROR_NOT_ENOUGH_MEMORY );
  772. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  773. }
  774. hFile = CreateFileA( pszPath,
  775. GENERIC_READ,
  776. FILE_SHARE_READ,
  777. NULL,
  778. OPEN_EXISTING,
  779. FILE_ATTRIBUTE_NORMAL |
  780. FILE_FLAG_SEQUENTIAL_SCAN,
  781. NULL );
  782. if ( INVALID_HANDLE_VALUE == hFile )
  783. {
  784. LPCSTR apsz[1];
  785. apsz[0] = pszPath;
  786. pstrError->FormatString( ODBCMSG_QUERY_FILE_NOT_FOUND,
  787. apsz,
  788. HTTP_ODBC_DLL );
  789. return HRESULT_FROM_WIN32( GetLastError() );
  790. }
  791. if ( !ReadFile( hFile,
  792. buff.QueryPtr(),
  793. QUERYFILE_READSIZE,
  794. &dwSize,
  795. NULL ) )
  796. {
  797. dwErr = GetLastError();
  798. pstrError->LoadString( dwErr );
  799. return HRESULT_FROM_WIN32( dwErr );
  800. }
  801. CloseHandle( hFile );
  802. *((CHAR *) buff.QueryPtr() + dwSize) = '\0';
  803. CHAR * pch = (CHAR *)buff.QueryPtr();
  804. while ( *pch )
  805. {
  806. pch = skipwhite( pch );
  807. if ( 'C' == toupper( *pch ) &&
  808. !_strnicmp( IDC_FIELDNAME_CHARSET,
  809. pch,
  810. sizeof(IDC_FIELDNAME_CHARSET)-1 ) )
  811. {
  812. pch += sizeof(IDC_FIELDNAME_CHARSET) - 1;
  813. pch = skipwhite( pch );
  814. if ( 932 == GetACP() )
  815. {
  816. if ( !_strnicmp( IDC_CHARSET_JIS1,
  817. pch,
  818. sizeof(IDC_CHARSET_JIS1)-1 ) ||
  819. !_strnicmp( IDC_CHARSET_JIS2,
  820. pch,
  821. sizeof(IDC_CHARSET_JIS2)-1 ) )
  822. {
  823. *pnCharset = CODE_JPN_JIS;
  824. break;
  825. }
  826. else if ( !_strnicmp( IDC_CHARSET_EUCJP,
  827. pch,
  828. sizeof(IDC_CHARSET_EUCJP)-1 ) )
  829. {
  830. *pnCharset = CODE_JPN_EUC;
  831. break;
  832. }
  833. else if ( !_strnicmp( IDC_CHARSET_SJIS,
  834. pch,
  835. sizeof(IDC_CHARSET_SJIS)-1 ) )
  836. {
  837. *pnCharset = CODE_ONLY_SBCS;
  838. break;
  839. }
  840. else
  841. {
  842. LPCSTR apsz[1];
  843. //
  844. // illegal value for Charset: field
  845. //
  846. apsz[0] = pszPath;
  847. pstrError->FormatString( ODBCMSG_UNREC_FIELD,
  848. apsz,
  849. HTTP_ODBC_DLL );
  850. return E_FAIL;
  851. }
  852. }
  853. //
  854. // please add code here to support other FE character encoding(FEFEFE)
  855. //
  856. // else if ( 949 == GetACP() )
  857. // ...
  858. }
  859. pch = nextline( pch );
  860. }
  861. return S_OK;
  862. }
  863. HRESULT
  864. ConvertUrlEncodedStringToSJIS(
  865. int nCharset,
  866. STRA * pstrParams
  867. )
  868. {
  869. STACK_STRA( strTemp, MAX_PATH);
  870. int cbSJISSize;
  871. int nResult;
  872. HRESULT hr;
  873. //
  874. // Pre-process the URL encoded parameters
  875. //
  876. for ( char * pch = pstrParams->QueryStr(); *pch; ++pch )
  877. {
  878. if ( *pch == '&' )
  879. {
  880. *pch = '\n';
  881. }
  882. else if ( *pch == '+' )
  883. {
  884. *pch = ' ';
  885. }
  886. }
  887. //
  888. // URL decoding (decode %nn only)
  889. //
  890. hr = pstrParams->Unescape();
  891. if( FAILED( hr ) )
  892. {
  893. DBGPRINTF(( DBG_CONTEXT,
  894. "Error unescaping param string, hr = 0x%x.\n",
  895. hr ));
  896. return hr;
  897. }
  898. //
  899. // charset conversion
  900. //
  901. hr = pstrParams->Clone( &strTemp );
  902. if ( FAILED( hr ) )
  903. {
  904. DBGPRINTF(( DBG_CONTEXT,
  905. "Error cloning param string, hr = 0x%x.\n",
  906. hr ));
  907. return hr;
  908. }
  909. hr = strTemp.Copy( pstrParams->QueryStr() );
  910. if ( FAILED( hr ) )
  911. {
  912. DBGPRINTF(( DBG_CONTEXT,
  913. "Error copying param string, hr = 0x%x.\n",
  914. hr ));
  915. return hr;
  916. }
  917. cbSJISSize = UNIX_to_PC( GetACP(),
  918. nCharset,
  919. (UCHAR *)strTemp.QueryStr(),
  920. strTemp.QueryCB(),
  921. NULL,
  922. 0 );
  923. hr = pstrParams->Resize( cbSJISSize + sizeof(TCHAR) );
  924. if ( FAILED( hr ) )
  925. {
  926. DBGPRINTF(( DBG_CONTEXT,
  927. "Error resizing param string buffer, hr = 0x%x.\n",
  928. hr ));
  929. return hr;
  930. }
  931. nResult = UNIX_to_PC( GetACP(),
  932. nCharset,
  933. (UCHAR *)strTemp.QueryStr(),
  934. strTemp.QueryCB(),
  935. (UCHAR *)pstrParams->QueryStr(),
  936. cbSJISSize );
  937. if ( -1 == nResult || nResult != cbSJISSize )
  938. {
  939. return E_FAIL;
  940. }
  941. DBG_REQUIRE ( pstrParams->SetLen( cbSJISSize) );
  942. //
  943. // URL encoding
  944. //
  945. hr = pstrParams->Escape();
  946. if ( FAILED( hr ) )
  947. {
  948. DBGPRINTF(( DBG_CONTEXT,
  949. "Error escaping param string, hr = 0x%x.\n",
  950. hr ));
  951. return hr;
  952. }
  953. return S_OK;
  954. }
  955. BOOL
  956. IsSystemDBCS(
  957. VOID
  958. )
  959. {
  960. WORD wPrimaryLangID = PRIMARYLANGID( GetSystemDefaultLangID() );
  961. return ( wPrimaryLangID == LANG_JAPANESE ||
  962. wPrimaryLangID == LANG_CHINESE ||
  963. wPrimaryLangID == LANG_KOREAN );
  964. }
  965. CHAR * FlipSlashes( CHAR * pszPath )
  966. {
  967. CHAR ch;
  968. CHAR * pszScan = pszPath;
  969. while( ( ch = *pszScan ) != '\0' )
  970. {
  971. if( ch == '/' )
  972. {
  973. *pszScan = '\\';
  974. }
  975. pszScan++;
  976. }
  977. return pszPath;
  978. } // FlipSlashes
  979. HRESULT
  980. GetPoolIDCTimeout(
  981. unsigned char * szMdPath,
  982. DWORD * pdwPoolIDCTimeout
  983. )
  984. {
  985. HRESULT hr = NOERROR;
  986. DWORD cbBufferRequired;
  987. const DWORD dwTimeout = 2000;
  988. STACK_STRU( strMetaPath, MAX_PATH );
  989. if ( g_pMetabase == NULL )
  990. {
  991. return E_NOINTERFACE;
  992. }
  993. hr = strMetaPath.CopyA( (LPSTR)szMdPath );
  994. if( FAILED(hr) )
  995. {
  996. return hr;
  997. }
  998. METADATA_HANDLE hKey = NULL;
  999. METADATA_RECORD MetadataRecord;
  1000. hr = g_pMetabase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  1001. strMetaPath.QueryStr(),
  1002. METADATA_PERMISSION_READ,
  1003. dwTimeout,
  1004. &hKey
  1005. );
  1006. if( SUCCEEDED(hr) )
  1007. {
  1008. MetadataRecord.dwMDIdentifier = MD_POOL_IDC_TIMEOUT;
  1009. MetadataRecord.dwMDAttributes = METADATA_INHERIT;
  1010. MetadataRecord.dwMDUserType = IIS_MD_UT_FILE;
  1011. MetadataRecord.dwMDDataType = DWORD_METADATA;
  1012. MetadataRecord.dwMDDataLen = sizeof( DWORD );
  1013. MetadataRecord.pbMDData = (unsigned char *) pdwPoolIDCTimeout;
  1014. MetadataRecord.dwMDDataTag = 0;
  1015. hr = g_pMetabase->GetData( hKey,
  1016. L"",
  1017. &MetadataRecord,
  1018. &cbBufferRequired
  1019. );
  1020. g_pMetabase->CloseKey( hKey );
  1021. }
  1022. return hr;
  1023. }