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.

914 lines
25 KiB

  1. #include <windows.h>
  2. #include <ole2.h>
  3. #include <stdio.h>
  4. #include <urlmon.h>
  5. #include <string.h>
  6. #include <malloc.h>
  7. #include <urlmon.hxx>
  8. #define IE5
  9. #ifdef PRODUCT_PROF
  10. extern "C" void _stdcall StartCAP(void);
  11. extern "C" void _stdcall StopCAP(void);
  12. extern "C" void _stdcall SuspendCAP(void);
  13. extern "C" void _stdcall ResumeCAP(void);
  14. extern "C" void _stdcall StartCAPAll(void);
  15. extern "C" void _stdcall StopCAPAll(void);
  16. #else
  17. #define StartCAP()
  18. #define StopCAP()
  19. #define SuspendCAP()
  20. #define ResumeCAP()
  21. #define StartCAPAll()
  22. #define StopCAPAll()
  23. #endif
  24. #define FLAG_TRACE 1
  25. #define FLAG_DUMPDATA 2
  26. #define MAX_DOWNLOADS 2000
  27. #define MAX_URL INTERNET_MAX_URL_LENGTH
  28. const INT BUF_SIZE = 2 * 1024;
  29. const INT MAX_BUF_SIZE = 1024 * 16;
  30. BOOL g_dwVerbose = 0;
  31. DWORD g_dwNumDownloads = 1;
  32. DWORD g_dwDownloads = 1;
  33. DWORD g_dwTotalBytes = 0;
  34. DWORD g_dwCacheFlag = BINDF_NOWRITECACHE | BINDF_GETNEWESTVERSION;
  35. DWORD dwBuf_Size = BUF_SIZE;
  36. LPWSTR g_pwzUrl = NULL;
  37. LPCSTR g_pInfile = NULL;
  38. LPCSTR g_pTitle = NULL;
  39. LPCSTR g_pRun = NULL;
  40. LPCSTR g_pModule = NULL;
  41. HANDLE g_hCompleted;
  42. __int64 g_ibeg = 0, g_iend, g_ifreq;
  43. //------------------------------------------------------------------------
  44. // Class: COInetProtocolHook
  45. //
  46. // Purpose: Sample Implementation of ProtocolSink and BindInfo
  47. // interface for simplified urlmon async download
  48. //
  49. // Interfaces:
  50. // [Needed For All]
  51. // IOInetProtocolSink
  52. // - provide sink for pluggable prot's callback
  53. // IOInetBindInfo
  54. // - provide the bind options
  55. //
  56. // [Needed For Http]
  57. // IServiceProvider
  58. // - used to query http specific services
  59. // e.g. HttpNegotiate, Authentication, UIWindow
  60. // IHttpNegotiate
  61. // - http negotiation service, it has two methods,
  62. // one is the http pluggable protocol asks the
  63. // client for additional headers, the other is
  64. // callback for returned http server status
  65. // e.g 200, 401, etc.
  66. //
  67. //
  68. // Author: DanpoZ (Danpo Zhang)
  69. //
  70. // History: 11-20-97 Created
  71. // 05-19-98 Modified to act as performance test
  72. //
  73. // NOTE: IOInetXXXX == IInternetXXXX
  74. // on the SDK, you will see IInternetXXXX, these are same
  75. // interfaces
  76. //
  77. //------------------------------------------------------------------------
  78. class COInetProtocolHook : public IOInetProtocolSink,
  79. public IOInetBindInfo,
  80. public IHttpNegotiate,
  81. public IServiceProvider
  82. {
  83. public:
  84. COInetProtocolHook(HANDLE g_hCompleted, IOInetProtocol* pProt);
  85. virtual ~COInetProtocolHook();
  86. // IUnknown methods
  87. STDMETHODIMP QueryInterface(REFIID iid, void **ppvObj);
  88. STDMETHODIMP_(ULONG) AddRef(void);
  89. STDMETHODIMP_(ULONG) Release(void);
  90. // IOInetProtocolSink methods
  91. STDMETHODIMP Switch( PROTOCOLDATA *pStateInfo);
  92. STDMETHODIMP ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText);
  93. STDMETHODIMP ReportData(
  94. DWORD grfBSCF,
  95. ULONG ulProgress,
  96. ULONG ulProgressMax
  97. );
  98. STDMETHODIMP ReportResult(
  99. HRESULT hrResult,
  100. DWORD dwError,
  101. LPCWSTR wzResult
  102. );
  103. //IOInetBindInfo methods
  104. STDMETHODIMP GetBindInfo(
  105. DWORD *grfBINDF,
  106. BINDINFO * pbindinfo
  107. );
  108. STDMETHODIMP GetBindString(
  109. ULONG ulStringType,
  110. LPOLESTR *ppwzStr,
  111. ULONG cEl,
  112. ULONG *pcElFetched
  113. );
  114. //IService Provider methods
  115. STDMETHODIMP QueryService(
  116. REFGUID guidService,
  117. REFIID riid,
  118. void **ppvObj
  119. );
  120. //IHttpNegotiate methods
  121. STDMETHODIMP BeginningTransaction(
  122. LPCWSTR szURL,
  123. LPCWSTR szHeaders,
  124. DWORD dwReserved,
  125. LPWSTR *pszAdditionalHeaders
  126. );
  127. STDMETHODIMP OnResponse(
  128. DWORD dwResponseCode,
  129. LPCWSTR szResponseHeaders,
  130. LPCWSTR szRequestHeaders,
  131. LPWSTR *pszAdditionalHeaders
  132. );
  133. private:
  134. IOInetProtocol* _pProt;
  135. HANDLE _hCompleted;
  136. CRefCount _CRefs;
  137. };
  138. typedef struct tagInfo
  139. {
  140. WCHAR wzUrl[INTERNET_MAX_URL_LENGTH];
  141. IOInetProtocol* pProt;
  142. COInetProtocolHook* pHook;
  143. IOInetProtocolSink* pSink;
  144. IOInetBindInfo* pBindInfo;
  145. } INFO, *PINFO;
  146. typedef BOOL (WINAPI *PFNSPA)(HANDLE, DWORD);
  147. INFO Info[MAX_DOWNLOADS];
  148. //------------------------------------------------------------------------
  149. //------------------------------------------------------------------------
  150. void MylstrcpyW(WCHAR *pwd, WCHAR *pws)
  151. {
  152. while (*pws)
  153. {
  154. *pwd++ = *pws++;
  155. }
  156. *pwd = 0;
  157. }
  158. //------------------------------------------------------------------------
  159. //------------------------------------------------------------------------
  160. WCHAR *MyDupA2W(LPSTR pa)
  161. {
  162. int i;
  163. WCHAR *pw, *pwd;
  164. i = lstrlen(pa);
  165. pw = (WCHAR *)CoTaskMemAlloc((i+1) * sizeof(WCHAR));
  166. pwd = pw;
  167. while (*pa)
  168. {
  169. *pwd++ = (WCHAR)*pa++;
  170. }
  171. *pwd++ = 0;
  172. return pw;
  173. }
  174. //------------------------------------------------------------------------
  175. //------------------------------------------------------------------------
  176. void SetSingleProcessorAffinity()
  177. {
  178. PFNSPA pfn;
  179. pfn = (PFNSPA)GetProcAddress(GetModuleHandleA("KERNEL32.DLL"),
  180. "SetProcessAffinityMask");
  181. if (pfn)
  182. {
  183. pfn(GetCurrentProcess(), 1);
  184. }
  185. }
  186. //------------------------------------------------------------------------
  187. //------------------------------------------------------------------------
  188. VOID DisplayUsage(char **argv)
  189. {
  190. printf("Usage: %s /u:url [/n:# /t:Title /r:RunStr /v:#]\n", argv[0]);
  191. printf(" %s /i:infile [/t:Title /r:RunStr /v:#]\n", argv[0]);
  192. printf(" /c - write to cache (default is NOWRITECACHE)\n");
  193. printf(" /g - read from cache (default is GETNEWESTVERSION)\n");
  194. printf(" /d - direct read (default uses QueryDataAvailable)\n");
  195. printf(" /l:# - read buffer length\n");
  196. printf(" /m:module - pre load module\n");
  197. printf(" /n:# - download # times.\n");
  198. printf(" /1 - single processor affinity (default multiprocessor)\n");
  199. printf(" /v:# - verbose level 1=trace 2=dump data\n");
  200. }
  201. //------------------------------------------------------------------------
  202. //------------------------------------------------------------------------
  203. BOOL ProcessCommandLine(int argcIn, char **argvIn)
  204. {
  205. BOOL bRC = FALSE;
  206. int argc = argcIn;
  207. char **argv = argvIn;
  208. argv++; argc--;
  209. if(argc == 0)
  210. {
  211. DisplayUsage(argvIn);
  212. return(FALSE);
  213. }
  214. while( argc > 0 && argv[0][0] == '/' )
  215. {
  216. switch (argv[0][1])
  217. {
  218. case 'c':
  219. case 'C':
  220. g_dwCacheFlag &= ~BINDF_NOWRITECACHE;
  221. break;
  222. case 'g':
  223. case 'G':
  224. g_dwCacheFlag &= ~BINDF_GETNEWESTVERSION;
  225. break;
  226. case 'd':
  227. case 'D':
  228. g_dwCacheFlag |= BINDF_DIRECT_READ;
  229. break;
  230. case 'i':
  231. case 'I':
  232. g_pInfile = &argv[0][3];
  233. bRC = TRUE;
  234. break;
  235. case 'l':
  236. case 'L':
  237. dwBuf_Size = atoi(&argv[0][3]);
  238. if(dwBuf_Size > MAX_BUF_SIZE)
  239. dwBuf_Size = MAX_BUF_SIZE;
  240. break;
  241. case 'm':
  242. case 'M':
  243. g_pModule = &argv[0][3];
  244. break;
  245. case 'n':
  246. case 'N':
  247. g_dwNumDownloads = (DWORD)atoi(&argv[0][3]);
  248. g_dwNumDownloads = max(1, g_dwNumDownloads);
  249. g_dwNumDownloads = min(MAX_DOWNLOADS, g_dwNumDownloads);
  250. break;
  251. case 'r':
  252. case 'R':
  253. g_pRun = &argv[0][3];
  254. break;
  255. case 't':
  256. case 'T':
  257. g_pTitle = &argv[0][3];
  258. break;
  259. case 'u':
  260. case 'U':
  261. g_pwzUrl = MyDupA2W(&argv[0][3]);
  262. bRC = TRUE;
  263. break;
  264. case 'v':
  265. case 'V':
  266. g_dwVerbose = (DWORD)atoi(&argv[0][3]);
  267. break;
  268. case '1':
  269. SetSingleProcessorAffinity();
  270. break;
  271. case '?':
  272. default:
  273. DisplayUsage(argvIn);
  274. bRC = FALSE;
  275. }
  276. argv++; argc--;
  277. }
  278. return(bRC);
  279. }
  280. //------------------------------------------------------------------------
  281. //------------------------------------------------------------------------
  282. BOOL BuildInfoList(PINFO pInfo, DWORD dwNumDownloads)
  283. {
  284. DWORD i = 0;
  285. if(g_pInfile != NULL)
  286. {
  287. TCHAR szName[INTERNET_MAX_URL_LENGTH+1];
  288. FILE *fp;
  289. if((fp = fopen(g_pInfile, "r")) == NULL)
  290. {
  291. printf("error opening file:%s GLE=%d\n", g_pInfile, GetLastError());
  292. return NULL;
  293. }
  294. while(fgets(szName, INTERNET_MAX_URL_LENGTH, fp) != NULL)
  295. {
  296. if(szName[0] != '#')
  297. {
  298. szName[strlen(szName) - sizeof(char)] = '\0';
  299. int rc;
  300. rc = MultiByteToWideChar(CP_ACP, 0, szName, -1, (pInfo+i)->wzUrl, INTERNET_MAX_URL_LENGTH);
  301. if (!rc)
  302. {
  303. (pInfo+i)->wzUrl[INTERNET_MAX_URL_LENGTH-1] = 0;
  304. wprintf(L"BuildInfoList:string too long; truncated to %s\n", (pInfo+i)->wzUrl);
  305. }
  306. i++;
  307. }
  308. }
  309. g_dwNumDownloads = i;
  310. fclose(fp);
  311. }
  312. else
  313. {
  314. for(i =0; i < dwNumDownloads; i++)
  315. {
  316. MylstrcpyW((pInfo+i)->wzUrl, g_pwzUrl);
  317. }
  318. }
  319. g_dwDownloads = g_dwNumDownloads;
  320. return(TRUE);
  321. }
  322. //------------------------------------------------------------------------
  323. //------------------------------------------------------------------------
  324. HRESULT StartDownloads(IOInetSession* pSession, PINFO pInfo, DWORD dwNumDownloads)
  325. {
  326. HRESULT hr = NOERROR;
  327. for(DWORD i =0; i < dwNumDownloads; i++)
  328. {
  329. // Create a pluggable protocol
  330. hr = pSession->CreateBinding(
  331. NULL, // [in ] BindCtx, always NULL
  332. (pInfo+i)->wzUrl, // [in ] url
  333. NULL, // [in ] IUnknown for Aggregration
  334. NULL, // [out] IUNknown for Aggregration
  335. &(pInfo+i)->pProt, // [out] return pProt pointer
  336. 0 // [in ] bind option, pass 0
  337. );
  338. if(g_dwVerbose & FLAG_TRACE)
  339. printf("MAIN: Session->CreateBinding: %lx\n", hr);
  340. // Create a protocolHook (sink) and Start the async operation
  341. if( hr == NOERROR )
  342. {
  343. (pInfo+i)->pHook = new COInetProtocolHook(g_hCompleted, (pInfo+i)->pProt);
  344. (pInfo+i)->pSink = NULL;
  345. (pInfo+i)->pBindInfo = NULL;
  346. if( (pInfo+i)->pHook )
  347. {
  348. hr = (pInfo+i)->pHook->QueryInterface(IID_IOInetProtocolSink, (void**)&(pInfo+i)->pSink);
  349. hr = (pInfo+i)->pHook->QueryInterface(IID_IOInetBindInfo, (void**)&(pInfo+i)->pBindInfo);
  350. }
  351. if( (pInfo+i)->pProt && (pInfo+i)->pSink && (pInfo+i)->pBindInfo )
  352. {
  353. hr = (pInfo+i)->pProt->Start(
  354. (pInfo+i)->wzUrl,
  355. (pInfo+i)->pSink,
  356. (pInfo+i)->pBindInfo,
  357. PI_FORCE_ASYNC,
  358. 0
  359. );
  360. if(g_dwVerbose & FLAG_TRACE)
  361. printf("MAIN: pProtocol->Start: %lx\n", hr);
  362. }
  363. }
  364. }
  365. return(hr);
  366. }
  367. //------------------------------------------------------------------------
  368. //------------------------------------------------------------------------
  369. VOID CleanInfoList(PINFO pInfo, DWORD dwNumDownloads)
  370. {
  371. for(DWORD i = 0; i < dwNumDownloads; i++)
  372. {
  373. if((pInfo+i)->pProt)
  374. (pInfo+i)->pProt->Terminate(0);
  375. if( (pInfo+i)->pSink )
  376. {
  377. (pInfo+i)->pSink->Release();
  378. }
  379. if( (pInfo+i)->pBindInfo )
  380. {
  381. (pInfo+i)->pBindInfo->Release();
  382. }
  383. if( (pInfo+i)->pHook )
  384. {
  385. (pInfo+i)->pHook->Release();
  386. }
  387. // release COM objects
  388. if( (pInfo+i)->pProt )
  389. {
  390. //
  391. // BUG (POSSIBLE RESOURCE LEAK)
  392. // If the pProt is IE's http/gopher/ftp implementation,
  393. // calling pProt->Release() now might cause resource leak
  394. // since pProt (although finished the download), might
  395. // be still waiting wininet to call back about the
  396. // confirmation of the handle closing.
  397. // The correct time to release pProt is to wait after
  398. // pProtSink get destroyed.
  399. //
  400. (pInfo+i)->pProt->Release();
  401. }
  402. }
  403. }
  404. //------------------------------------------------------------------------
  405. //
  406. // Purpose: create a session object
  407. // Get a pluggable procotol from the session
  408. // Start the pluggable protocol async download
  409. //
  410. // Author: DanpoZ (Danpo Zhang)
  411. //
  412. // History: 11-20-97 Created
  413. //
  414. //------------------------------------------------------------------------
  415. int _cdecl main(int argc, char** argv)
  416. {
  417. IOInetSession* pSession = NULL;
  418. IOInetProtocol* pProt = NULL;
  419. HRESULT hr = NOERROR;
  420. DWORD dwLoadTime;
  421. HMODULE hMod = NULL;
  422. if(!ProcessCommandLine(argc, argv))
  423. return 0;
  424. // Init COM
  425. CoInitialize(NULL);
  426. if(g_pModule != NULL)
  427. {
  428. hMod = LoadLibrary(g_pModule);
  429. }
  430. g_hCompleted = CreateEvent(NULL, FALSE, FALSE, NULL);
  431. // Get a Session
  432. hr = CoInternetGetSession(0, &pSession, 0);
  433. if(g_dwVerbose & FLAG_TRACE)
  434. printf("MAIN: Created Session: %lx\n", hr);
  435. if( hr == NOERROR )
  436. {
  437. if(!BuildInfoList(&Info[0], g_dwNumDownloads))
  438. return(2);
  439. hr = StartDownloads(pSession, &Info[0], g_dwNumDownloads);
  440. if( hr == NOERROR )
  441. {
  442. // wait until the async download finishes
  443. WaitForSingleObject(g_hCompleted, INFINITE);
  444. }
  445. StopCAP();
  446. QueryPerformanceCounter((LARGE_INTEGER *)&g_iend);
  447. QueryPerformanceFrequency((LARGE_INTEGER *)&g_ifreq);
  448. dwLoadTime = (LONG)(((g_iend - g_ibeg) * 1000) / g_ifreq);
  449. float fKB;
  450. float fSec;
  451. float fKBSec;
  452. if(dwLoadTime == 0)
  453. dwLoadTime = 1;
  454. fKB = ((float)g_dwTotalBytes)/1024;
  455. fSec = ((float)dwLoadTime)/1000;
  456. fKBSec = fKB / fSec;
  457. printf("%s,%s,%d,%d,%2.0f\n",
  458. g_pTitle ?g_pTitle :"Oinetperf",
  459. g_pRun ?g_pRun :"1",
  460. dwLoadTime, g_dwTotalBytes, fKBSec);
  461. CleanInfoList(&Info[0], g_dwNumDownloads);
  462. }
  463. if( pSession )
  464. {
  465. pSession->Release();
  466. }
  467. CoTaskMemFree(g_pwzUrl);
  468. if((g_pModule != NULL) && (hMod != NULL))
  469. {
  470. FreeLibrary(hMod);
  471. }
  472. // kill COM
  473. CoUninitialize();
  474. return(0);
  475. }
  476. COInetProtocolHook::COInetProtocolHook
  477. (
  478. HANDLE g_hCompleted,
  479. IOInetProtocol* pProt
  480. )
  481. {
  482. _hCompleted = g_hCompleted;
  483. _pProt = pProt;
  484. }
  485. COInetProtocolHook::~COInetProtocolHook()
  486. {
  487. CloseHandle(_hCompleted);
  488. }
  489. HRESULT
  490. COInetProtocolHook::QueryInterface(REFIID iid, void **ppvObj)
  491. {
  492. HRESULT hr = NOERROR;
  493. *ppvObj = NULL;
  494. if( iid == IID_IUnknown || iid == IID_IOInetProtocolSink )
  495. {
  496. *ppvObj = static_cast<IOInetProtocolSink*>(this);
  497. }
  498. else
  499. if( iid == IID_IOInetBindInfo )
  500. {
  501. *ppvObj = static_cast<IOInetBindInfo*>(this);
  502. }
  503. else
  504. if( iid == IID_IServiceProvider)
  505. {
  506. *ppvObj = static_cast<IServiceProvider*>(this);
  507. }
  508. else
  509. if( iid == IID_IHttpNegotiate )
  510. {
  511. *ppvObj = static_cast<IHttpNegotiate*>(this);
  512. }
  513. else
  514. {
  515. hr = E_NOINTERFACE;
  516. }
  517. if( *ppvObj )
  518. {
  519. AddRef();
  520. }
  521. return hr;
  522. }
  523. ULONG
  524. COInetProtocolHook::AddRef(void)
  525. {
  526. LONG lRet = ++_CRefs;
  527. return lRet;
  528. }
  529. ULONG
  530. COInetProtocolHook::Release(void)
  531. {
  532. LONG lRet = --_CRefs;
  533. if (lRet == 0)
  534. {
  535. delete this;
  536. }
  537. return lRet;
  538. }
  539. HRESULT
  540. COInetProtocolHook::Switch( PROTOCOLDATA *pStateInfo)
  541. {
  542. printf("Are you crazy? I don't know how to do Thread switching!!!\n");
  543. return E_NOTIMPL;
  544. }
  545. HRESULT
  546. COInetProtocolHook::ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText)
  547. {
  548. switch( ulStatusCode )
  549. {
  550. case BINDSTATUS_FINDINGRESOURCE:
  551. if(g_dwVerbose & FLAG_TRACE)
  552. wprintf(
  553. L"CALLBACK(ReportProgress): Resolving name %s\n", szStatusText );
  554. break;
  555. case BINDSTATUS_CONNECTING:
  556. if(g_dwVerbose & FLAG_TRACE)
  557. wprintf(L"CALLBACK(ReportProgress): Connecting to %s\n", szStatusText );
  558. break;
  559. case BINDSTATUS_SENDINGREQUEST:
  560. if(g_dwVerbose & FLAG_TRACE)
  561. wprintf(L"CALLBACK(ReportProgress): Sending request\n");
  562. break;
  563. case BINDSTATUS_CACHEFILENAMEAVAILABLE:
  564. if(g_dwVerbose & FLAG_TRACE)
  565. wprintf(L"CALLBACK(ReportProgress): cache filename available\n");
  566. break;
  567. case BINDSTATUS_MIMETYPEAVAILABLE:
  568. if(g_dwVerbose & FLAG_TRACE)
  569. wprintf(L"CALLBACK(ReportProgress): mimetype available = %s\n", szStatusText);
  570. break;
  571. case BINDSTATUS_REDIRECTING:
  572. if(g_dwVerbose & FLAG_TRACE)
  573. wprintf(L"CALLBACK(ReportProgress): Redirecting to %s\n", szStatusText);
  574. break;
  575. default:
  576. if(g_dwVerbose & FLAG_TRACE)
  577. wprintf(L"CALLBACK(ReportProgress): others...\n");
  578. break;
  579. }
  580. return NOERROR;
  581. }
  582. HRESULT
  583. COInetProtocolHook::ReportData(
  584. DWORD grfBSCF,
  585. ULONG ulProgress,
  586. ULONG ulProgressMax
  587. )
  588. {
  589. if(g_dwVerbose & FLAG_TRACE)
  590. printf("CALLBACK(ReportData) %d, %d, %d \n", grfBSCF, ulProgress, ulProgressMax);
  591. // Pull data via pProt->Read(), here are the possible returned
  592. // HRESULT values and how we should act upon:
  593. //
  594. // if E_PENDING is returned:
  595. // client already get all the data in buffer, there is nothing
  596. // can be done here, client should walk away and wait for the
  597. // next chuck of data, which will be notified via ReportData()
  598. // callback.
  599. //
  600. // if S_FALSE is returned:
  601. // this is EOF, everything is done, however, client must wait
  602. // for ReportResult() callback to indicate that the pluggable
  603. // protocol is ready to shutdown.
  604. //
  605. // if S_OK is returned:
  606. // keep on reading, until you hit E_PENDING/S_FALSE/ERROR, the deal
  607. // is that the client is supposed to pull ALL the available
  608. // data in the buffer
  609. //
  610. // if none of the above is returning:
  611. // Error occured, client should decide how to handle it, most
  612. // commonly, client will call pProt->Abort() to abort the download
  613. char *pBuf = (char *)_alloca(dwBuf_Size);
  614. HRESULT hr = NOERROR;
  615. ULONG cbRead;
  616. while( hr == S_OK )
  617. {
  618. cbRead = 0;
  619. if (g_ibeg == 0)
  620. {
  621. QueryPerformanceCounter((LARGE_INTEGER *)&g_ibeg);
  622. StartCAP();
  623. }
  624. // pull data
  625. if(g_dwVerbose & FLAG_TRACE)
  626. {
  627. printf("MAIN: pProtocol->Read attempting %d bytes\n", dwBuf_Size);
  628. }
  629. hr = _pProt->Read((void*)pBuf, dwBuf_Size, &cbRead);
  630. if( (hr == S_OK || hr == E_PENDING || hr == S_FALSE) && cbRead )
  631. {
  632. if( g_dwVerbose & FLAG_DUMPDATA )
  633. {
  634. for( ULONG i = 0; i < cbRead; i++)
  635. {
  636. printf("%c", pBuf[i]);
  637. }
  638. }
  639. if(g_dwVerbose & FLAG_TRACE)
  640. {
  641. printf("MAIN: pProtocol->Read %d bytes\n", cbRead);
  642. }
  643. g_dwTotalBytes += cbRead;
  644. }
  645. }
  646. if( hr == S_FALSE )
  647. {
  648. if(g_dwVerbose & FLAG_TRACE)
  649. printf("MAIN: pProtocol->Read returned EOF \n");
  650. }
  651. else
  652. if( hr != E_PENDING )
  653. {
  654. if(g_dwVerbose & FLAG_TRACE)
  655. {
  656. printf("MAIN: pProtocol->Read returned Error %1x \n, hr");
  657. printf("MAIN: pProtocol->Abort called \n", hr);
  658. }
  659. _pProt->Abort(hr, 0);
  660. }
  661. return NOERROR;
  662. }
  663. HRESULT
  664. COInetProtocolHook::ReportResult(
  665. HRESULT hrResult,
  666. DWORD dwError,
  667. LPCWSTR wzResult
  668. )
  669. {
  670. // This is the last call back from the pluggable protocol,
  671. // this call is equivlant to the IBindStatusCallBack::OnStopBinding()
  672. // it basically tells you that the pluggable protocol is ready
  673. // to shutdown
  674. if(g_dwVerbose & FLAG_TRACE)
  675. printf("CALLBACK(ReportResult): Download completed with status %1x\n", hrResult);
  676. // set event to the main thread
  677. if(InterlockedDecrement((LONG*)&g_dwDownloads ) == 0)
  678. SetEvent(g_hCompleted);
  679. return NOERROR;
  680. }
  681. HRESULT
  682. COInetProtocolHook::GetBindInfo(
  683. DWORD *grfBINDF,
  684. BINDINFO * pbindinfo
  685. )
  686. {
  687. HRESULT hr = NOERROR;
  688. // *grfBINDF = BINDF_DIRECT_READ | BINDF_ASYNCHRONOUS | BINDF_PULLDATA;
  689. // *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
  690. *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_IGNORESECURITYPROBLEM;
  691. *grfBINDF |= g_dwCacheFlag;
  692. // for HTTP GET, VERB is the only field we interested
  693. // for HTTP POST, BINDINFO will point to Storage structure which
  694. // contains data
  695. BINDINFO bInfo;
  696. ZeroMemory(&bInfo, sizeof(BINDINFO));
  697. // all we need is size and verb field
  698. bInfo.cbSize = sizeof(BINDINFO);
  699. bInfo.dwBindVerb = BINDVERB_GET;
  700. // src -> dest
  701. hr = CopyBindInfo(&bInfo, pbindinfo );
  702. return hr;
  703. }
  704. static LPSTR g_szAcceptStrAll = "*/*";
  705. HRESULT
  706. COInetProtocolHook::GetBindString(
  707. ULONG ulStringType,
  708. LPOLESTR *ppwzStr,
  709. ULONG cEl,
  710. ULONG *pcElFetched
  711. )
  712. {
  713. HRESULT hr = INET_E_USE_DEFAULT_SETTING;
  714. switch (ulStringType)
  715. {
  716. case BINDSTRING_HEADERS :
  717. case BINDSTRING_EXTRA_URL :
  718. case BINDSTRING_LANGUAGE :
  719. case BINDSTRING_USERNAME :
  720. case BINDSTRING_PASSWORD :
  721. case BINDSTRING_ACCEPT_ENCODINGS:
  722. case BINDSTRING_URL:
  723. case BINDSTRING_USER_AGENT :
  724. case BINDSTRING_POST_COOKIE :
  725. case BINDSTRING_POST_DATA_MIME:
  726. break;
  727. case BINDSTRING_ACCEPT_MIMES:
  728. // IE4's http pluggable protocol implementation does not
  729. // honer INET_E_USE_DEFAULT_SETTING returned by this function
  730. // starting from IE5, client can just return the USE_DEFAULT
  731. // use for ie5 so we don't need a seperate bin for ie4 // #ifndef IE5
  732. // this will be freed by the caller
  733. *(ppwzStr + 0) = MyDupA2W(g_szAcceptStrAll);
  734. *(ppwzStr + 1) = NULL;
  735. *pcElFetched = 1;
  736. hr = NOERROR;
  737. //#endif
  738. break;
  739. default:
  740. break;
  741. }
  742. return hr;
  743. }
  744. HRESULT
  745. COInetProtocolHook::QueryService(
  746. REFGUID guidService,
  747. REFIID riid,
  748. void **ppvObj
  749. )
  750. {
  751. HRESULT hr = E_NOINTERFACE;
  752. *ppvObj = NULL;
  753. if( guidService == IID_IHttpNegotiate )
  754. {
  755. *ppvObj = static_cast<IHttpNegotiate*>(this);
  756. }
  757. if( *ppvObj )
  758. {
  759. AddRef();
  760. hr = NOERROR;
  761. }
  762. return hr;
  763. }
  764. HRESULT
  765. COInetProtocolHook::BeginningTransaction(
  766. LPCWSTR szURL,
  767. LPCWSTR szHeaders,
  768. DWORD dwReserved,
  769. LPWSTR *pszAdditionalHeaders
  770. )
  771. {
  772. if(g_dwVerbose & FLAG_TRACE)
  773. printf("HTTPNEGOTIATE: Additional Headers? - No \n");
  774. *pszAdditionalHeaders = NULL;
  775. return NOERROR;
  776. }
  777. HRESULT
  778. COInetProtocolHook::OnResponse(
  779. DWORD dwResponseCode,
  780. LPCWSTR szResponseHeaders,
  781. LPCWSTR szRequestHeaders,
  782. LPWSTR *pszAdditionalHeaders
  783. )
  784. {
  785. if(g_dwVerbose & FLAG_TRACE)
  786. printf("HTTPNEGOTIATE: Http server response code %d\n", dwResponseCode);
  787. return NOERROR;
  788. }