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.

2170 lines
60 KiB

  1. /**
  2. * Asynchronous pluggable protocol for Applications
  3. *
  4. * Copyright (C) Microsoft Corporation, 2000
  5. */
  6. /////////////////////////////////////////////////////////////////////////////
  7. /////////////////////////////////////////////////////////////////////////////
  8. /////////////////////////////////////////////////////////////////////////////
  9. #include "precomp.h"
  10. #include "app.h"
  11. #include <stdio.h> // for _snprintf
  12. char * stristr(char *pszMain, char *pszSub)
  13. {
  14. char * pszCur = pszMain;
  15. char ch = (char) tolower(*pszSub);
  16. int cb = strlen(pszSub) - 1; // -1 to ignore leading character
  17. for (;;) {
  18. while (tolower(*pszCur) != ch && *pszCur)
  19. pszCur++;
  20. if (!*pszCur)
  21. return NULL;
  22. if (_strnicmp(pszCur + 1, pszSub + 1, cb) == 0)
  23. return pszCur;
  24. pszCur++;
  25. }
  26. }
  27. /**
  28. * Return last Win32 error as an HRESULT.
  29. */
  30. HRESULT
  31. GetLastWin32Error()
  32. {
  33. // Win 95 can return 0, even when there's an error.
  34. DWORD dw = GetLastError();
  35. return dw ? HRESULT_FROM_WIN32(dw) : E_FAIL;
  36. }
  37. HRESULT
  38. RunCommand(WCHAR *cmdLine)
  39. {
  40. HRESULT hr = S_OK;
  41. STARTUPINFO si;
  42. PROCESS_INFORMATION pi;
  43. ZeroMemory(&si, sizeof(si));
  44. ZeroMemory(&pi, sizeof(pi));
  45. si.cb = sizeof(si);
  46. if(!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
  47. {
  48. hr = GetLastWin32Error();
  49. goto exit;
  50. }
  51. if(WaitForSingleObject(pi.hProcess, 180000L) == WAIT_TIMEOUT)
  52. {
  53. hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
  54. goto exit;
  55. }
  56. exit:
  57. if(pi.hProcess) CloseHandle(pi.hProcess);
  58. if(pi.hThread) CloseHandle(pi.hThread);
  59. return hr;
  60. }
  61. #define ToHex(val) val <= 9 ? val + '0': val - 10 + 'A'
  62. DWORD ConvertToHex(WCHAR* strForm, BYTE* byteForm, DWORD dwSize)
  63. {
  64. DWORD i = 0;
  65. DWORD j = 0;
  66. for(i = 0; i < dwSize; i++) {
  67. strForm[j++] = ToHex((0xf & byteForm[i]));
  68. strForm[j++] = ToHex((0xf & (byteForm[i] >> 4)));
  69. }
  70. strForm[j] = L'\0';
  71. return j;
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. /////////////////////////////////////////////////////////////////////////////
  75. /////////////////////////////////////////////////////////////////////////////
  76. // {B8BF3C7E-4DB6-4fdb-9CD3-13D2CE728CA8}, by guidgen VS7
  77. CLSID CLSID_AppProtocol = { 0xb8bf3c7e,
  78. 0x4db6, 0x4fdb,
  79. { 0x9c, 0xd3, 0x13, 0xd2, 0xce, 0x72, 0x8c, 0xa8 } };
  80. BOOL g_fStarted = FALSE;
  81. AppProtocolFactory g_AppProtocolFactory;
  82. IInternetSecurityManager* g_pSecurityMgr = NULL;
  83. /////////////////////////////////////////////////////////////////////////////
  84. /////////////////////////////////////////////////////////////////////////////
  85. /////////////////////////////////////////////////////////////////////////////
  86. // Class AppProtocol ctor
  87. AppProtocol::AppProtocol(IUnknown * pUnkOuter)
  88. : m_refs (1),
  89. m_pProtocolSink (NULL),
  90. // m_cookie (NULL),
  91. m_fullUri (NULL),
  92. m_uriPath (NULL),
  93. m_queryString (NULL),
  94. m_appOrigin (NULL),
  95. m_appRoot (NULL),
  96. m_appRootTranslated (NULL),
  97. m_extraHeaders (NULL),
  98. m_inputDataSize (0),
  99. m_inputData (NULL),
  100. m_pInputRead (NULL),
  101. m_pOutputRead (NULL),
  102. m_pOutputWrite (NULL),
  103. m_started (FALSE),
  104. m_aborted (FALSE),
  105. m_done (FALSE),
  106. m_responseMimeType (NULL),
  107. m_cbOutput (0),
  108. m_extraHeadersUpr (NULL),
  109. m_strResponseHeader (NULL),
  110. m_postedMimeType (NULL),
  111. m_verb (NULL),
  112. m_localStoreFilePath (NULL),
  113. m_appType (APPTYPE_IE),
  114. m_status (STATUS_CLEAR)
  115. {
  116. m_pUnkOuter = (pUnkOuter ? pUnkOuter : (IUnknown *)(IPrivateUnknown *)this);
  117. InitializeCriticalSection(&m_csOutputWriter);
  118. }
  119. /////////////////////////////////////////////////////////////////////////////
  120. /////////////////////////////////////////////////////////////////////////////
  121. /////////////////////////////////////////////////////////////////////////////
  122. void
  123. AppProtocol::Cleanup()
  124. {
  125. ClearInterface(&m_pOutputRead);
  126. ClearInterface(&m_pOutputWrite);
  127. ClearInterface(&m_pProtocolSink);
  128. ClearInterface(&m_pInputRead);
  129. m_appType = APPTYPE_IE;
  130. m_status = STATUS_CLEAR;
  131. m_done = TRUE;
  132. m_aborted = FALSE; //???
  133. if (m_bindinfo.cbSize)
  134. {
  135. ReleaseBindInfo(&m_bindinfo);
  136. ZeroMemory(&m_bindinfo, sizeof(m_bindinfo));
  137. }
  138. }
  139. /////////////////////////////////////////////////////////////////////////////
  140. /////////////////////////////////////////////////////////////////////////////
  141. /////////////////////////////////////////////////////////////////////////////
  142. void
  143. AppProtocol::FreeStrings()
  144. {
  145. MemClearFn((void **)&m_fullUri);
  146. m_uriPath = NULL;
  147. m_queryString = NULL;
  148. MemClearFn((void **)&m_appOrigin) ;
  149. m_appRoot = NULL;
  150. MemClearFn((void **)&m_appRootTranslated);
  151. if(m_extraHeaders)
  152. {
  153. CoTaskMemFree(m_extraHeaders);
  154. m_extraHeaders = NULL;
  155. }
  156. // MemClearFn((void **)&m_cookie);
  157. MemClearFn((void **)&m_extraHeadersUpr);
  158. MemClearFn((void **)&m_strResponseHeader);
  159. MemClearFn((void **)&m_verb);
  160. MemClearFn((void **)&m_postedMimeType);
  161. MemClearFn((void **)&m_responseMimeType);
  162. MemClearFn((void **)&m_localStoreFilePath);
  163. }
  164. /////////////////////////////////////////////////////////////////////////////
  165. /////////////////////////////////////////////////////////////////////////////
  166. /////////////////////////////////////////////////////////////////////////////
  167. AppProtocol::~AppProtocol()
  168. {
  169. FreeStrings();
  170. Cleanup();
  171. DeleteCriticalSection(&m_csOutputWriter);
  172. if (g_pSecurityMgr != NULL)
  173. {
  174. g_pSecurityMgr->Release();
  175. g_pSecurityMgr = NULL;
  176. }
  177. }
  178. /////////////////////////////////////////////////////////////////////////////
  179. /////////////////////////////////////////////////////////////////////////////
  180. /////////////////////////////////////////////////////////////////////////////
  181. // Private QI
  182. ULONG
  183. AppProtocol::PrivateAddRef()
  184. {
  185. return ++m_refs;
  186. }
  187. ULONG
  188. AppProtocol::PrivateRelease()
  189. {
  190. if (--m_refs > 0)
  191. return m_refs;
  192. delete this;
  193. return 0;
  194. }
  195. HRESULT
  196. AppProtocol::PrivateQueryInterface(
  197. REFIID iid,
  198. void** ppv)
  199. {
  200. *ppv = NULL;
  201. if (iid == IID_IInternetProtocol ||
  202. iid == IID_IInternetProtocolRoot)
  203. {
  204. *ppv = (IInternetProtocol *)this;
  205. }
  206. else if (iid == IID_IUnknown)
  207. {
  208. *ppv = (IUnknown *)(IPrivateUnknown *)this;
  209. }
  210. else if (iid == IID_IWinInetHttpInfo)
  211. {
  212. *ppv = (IWinInetHttpInfo *)this;
  213. }
  214. else
  215. {
  216. return E_NOINTERFACE;
  217. }
  218. ((IUnknown *)*ppv)->AddRef();
  219. return S_OK;
  220. }
  221. /////////////////////////////////////////////////////////////////////////////
  222. /////////////////////////////////////////////////////////////////////////////
  223. /////////////////////////////////////////////////////////////////////////////
  224. // Public (delegated) QI
  225. ULONG
  226. AppProtocol::AddRef()
  227. {
  228. m_pUnkOuter->AddRef();
  229. return PrivateAddRef();
  230. }
  231. ULONG
  232. AppProtocol::Release()
  233. {
  234. m_pUnkOuter->Release();
  235. return PrivateRelease();
  236. }
  237. HRESULT
  238. AppProtocol::QueryInterface(
  239. REFIID iid,
  240. void ** ppv)
  241. {
  242. return m_pUnkOuter->QueryInterface(iid, ppv);
  243. }
  244. /////////////////////////////////////////////////////////////////////////////
  245. /////////////////////////////////////////////////////////////////////////////
  246. /////////////////////////////////////////////////////////////////////////////
  247. HRESULT
  248. AppProtocol::Start(
  249. LPCWSTR url,
  250. IInternetProtocolSink * pProtocolSink,
  251. IInternetBindInfo * pBindInfo,
  252. DWORD grfSTI,
  253. DWORD )
  254. {
  255. HRESULT hr = S_OK;
  256. WCHAR * Strings[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  257. DWORD cStrings = sizeof(Strings) / sizeof(Strings[0]);
  258. // DWORD cookieSize = 0;
  259. IServiceProvider * pServiceProvider = NULL;
  260. IHttpNegotiate * pHttpNegotiate = NULL;
  261. FreeStrings();
  262. ReplaceInterface(&m_pProtocolSink, pProtocolSink);
  263. // ?????
  264. if (grfSTI & PI_PARSE_URL)
  265. goto exit;
  266. if (pProtocolSink == NULL)
  267. {
  268. hr = E_INVALIDARG;
  269. goto exit;
  270. }
  271. // get bindinfo
  272. m_bindinfo.cbSize = sizeof(BINDINFO);
  273. if (pBindInfo != NULL)
  274. {
  275. if (FAILED(hr = pBindInfo->GetBindInfo(&m_bindf, &m_bindinfo)))
  276. goto exit;
  277. }
  278. if (m_bindinfo.dwCodePage == 0)
  279. m_bindinfo.dwCodePage = CP_ACP;
  280. // extract root, uri path and query string from url
  281. if (FAILED(hr = ParseUrl(url)))
  282. goto exit;
  283. // get to headers in MSHtml
  284. if (FAILED(hr = pBindInfo->QueryInterface(IID_IServiceProvider, (void **) &pServiceProvider)))
  285. goto exit;
  286. if(pServiceProvider != NULL)
  287. {
  288. if (FAILED(hr = pServiceProvider->QueryService(IID_IHttpNegotiate, IID_IHttpNegotiate, (void **) &pHttpNegotiate)))
  289. goto exit;
  290. if(pHttpNegotiate != NULL)
  291. {
  292. hr = pHttpNegotiate->BeginningTransaction(url, NULL, 0, &m_extraHeaders);
  293. pHttpNegotiate->Release();
  294. pHttpNegotiate = NULL;
  295. if (FAILED(hr))
  296. goto exit;
  297. }
  298. pServiceProvider->Release();
  299. pServiceProvider = NULL;
  300. }
  301. // determine verb
  302. switch (m_bindinfo.dwBindVerb)
  303. {
  304. case BINDVERB_GET:
  305. m_verb = DuplicateString(L"GET");
  306. break;
  307. case BINDVERB_POST:
  308. m_verb = DuplicateString(L"POST");
  309. break;
  310. case BINDVERB_PUT:
  311. m_verb = DuplicateString(L"PUT");
  312. break;
  313. default:
  314. if (m_bindinfo.szCustomVerb != NULL && m_bindinfo.dwBindVerb == BINDVERB_CUSTOM)
  315. {
  316. m_verb = DuplicateString(m_bindinfo.szCustomVerb);
  317. }
  318. else
  319. {
  320. m_verb = DuplicateString(L"GET");
  321. }
  322. break;
  323. }
  324. // get mime type of posted data from binding
  325. hr = pBindInfo->GetBindString(BINDSTRING_POST_DATA_MIME, Strings, cStrings, &cStrings);
  326. if(hr == S_OK && cStrings)
  327. {
  328. DWORD i;
  329. m_postedMimeType = DuplicateString(Strings[0]);
  330. if (m_postedMimeType == NULL)
  331. {
  332. hr = E_OUTOFMEMORY;
  333. goto exit;
  334. }
  335. for(i = 0; i < cStrings; i++)
  336. CoTaskMemFree(Strings[i]);
  337. }
  338. // don't fail if we failed to get bind string,
  339. hr = S_OK;
  340. // retrieve cookie
  341. /* cookieSize = 0;
  342. if(g_pInternetGetCookieW(m_fullUri, NULL, NULL, &cookieSize) && cookieSize)
  343. {
  344. m_cookie = (WCHAR *)MemAlloc(cookieSize + sizeof(WCHAR));
  345. if (m_cookie == NULL)
  346. {
  347. hr = E_OUTOFMEMORY;
  348. goto exit;
  349. }
  350. g_pInternetGetCookieW(m_fullUri, NULL, m_cookie, &cookieSize);
  351. }
  352. */
  353. // Input data
  354. if (m_bindinfo.stgmedData.tymed == TYMED_HGLOBAL)
  355. {
  356. m_inputDataSize = m_bindinfo.cbstgmedData;
  357. m_inputData = (BYTE *)m_bindinfo.stgmedData.hGlobal;
  358. }
  359. else if (m_bindinfo.stgmedData.tymed == TYMED_ISTREAM)
  360. {
  361. STATSTG statstg;
  362. ReplaceInterface(&m_pInputRead, m_bindinfo.stgmedData.pstm);
  363. if(m_pInputRead)
  364. {
  365. hr = m_pInputRead->Stat(&statstg, STATFLAG_NONAME);
  366. if(hr == S_OK)
  367. m_inputDataSize = statstg.cbSize.LowPart;
  368. else
  369. m_inputDataSize = (DWORD)-1;
  370. }
  371. }
  372. if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pOutputWrite)))
  373. goto exit;
  374. if (FAILED(hr = m_pOutputWrite->Clone(&m_pOutputRead)))
  375. goto exit;
  376. PROTOCOLDATA protData;
  377. protData.dwState = 1;
  378. protData.grfFlags = PI_FORCE_ASYNC;
  379. protData.pData = NULL;
  380. protData.cbData = 0;
  381. pProtocolSink->Switch(&protData);
  382. //*** hr = E_PENDING;
  383. exit:
  384. if (pHttpNegotiate)
  385. {
  386. pHttpNegotiate->Release();
  387. pHttpNegotiate = NULL;
  388. }
  389. if (pServiceProvider)
  390. {
  391. pServiceProvider->Release();
  392. pServiceProvider = NULL;
  393. }
  394. return hr;
  395. }
  396. /////////////////////////////////////////////////////////////////////////////
  397. /////////////////////////////////////////////////////////////////////////////
  398. /////////////////////////////////////////////////////////////////////////////
  399. HRESULT
  400. AppProtocol::Continue(
  401. PROTOCOLDATA * pProtData)
  402. {
  403. HRESULT hr = S_OK;
  404. // CHAR appDomainPath[MAX_PATH] = "";
  405. WCHAR appRootTranslated[MAX_PATH];
  406. if(pProtData->dwState != 1)
  407. {
  408. hr = E_FAIL;
  409. goto exit;
  410. }
  411. // step 1: "install" the specified file
  412. appRootTranslated[0] = L'\0';
  413. hr = SetupAndInstall(m_fullUri, appRootTranslated);
  414. if (FAILED(hr))
  415. goto exit;
  416. if (m_localStoreFilePath == NULL)
  417. {
  418. hr = E_FAIL;
  419. goto exit;
  420. }
  421. m_appRootTranslated = DuplicateString(appRootTranslated);
  422. if (m_appRootTranslated == NULL)
  423. {
  424. hr = E_OUTOFMEMORY;
  425. goto exit;
  426. }
  427. // step 2: check error status
  428. if ((m_status & STATUS_OFFLINE_MODE) && (m_status & STATUS_NOT_IN_CACHE))
  429. {
  430. char buffer[100 + MAX_PATH];
  431. SendHeaders(HTTP_RESPONSEOK);
  432. _snprintf(buffer, 100+MAX_PATH, "Error: In offline mode and file not found in application store.\r\nLocal path expected- %ws", m_localStoreFilePath);
  433. WriteBytes((BYTE*) buffer, lstrlenA(buffer)+1);
  434. hr = Finish();
  435. goto exit;
  436. }
  437. // step 3: process different file types
  438. if (m_appType == APPTYPE_BYMANIFEST)
  439. {
  440. char buffer[512 + MAX_PATH];
  441. SendHeaders(HTTP_RESPONSEOK);
  442. // ???? ignore if excess buffer len
  443. // do this before as m_localStoreFilePath might be overwritten
  444. _snprintf(buffer, 512 + MAX_PATH, "Application installed and executed with manifest file - %ws\r\nSource - %ws", m_localStoreFilePath, m_fullUri);
  445. if (FAILED(hr = ProcessAppManifest()))
  446. goto exit;
  447. WriteBytes((BYTE *) buffer, lstrlenA(buffer)+1); //???? includes last '\0'
  448. hr = Finish();
  449. }
  450. else if (m_appType == APPTYPE_ASM)
  451. {
  452. char buffer[512 + MAX_PATH];
  453. SendHeaders(HTTP_RESPONSEOK);
  454. // ???? ignore if excess buffer len
  455. _snprintf(buffer, 512+MAX_PATH, "Assembly Executed - %ws\r\nSource - %ws", m_localStoreFilePath, m_fullUri);
  456. WriteBytes((BYTE*) buffer, lstrlenA(buffer)+1); //???? includes last '\0'
  457. hr = Finish();
  458. }
  459. else if (m_appType == APPTYPE_IE)
  460. {
  461. DWORD dwLength;
  462. BYTE buffer[512];
  463. char header[60];
  464. HANDLE hFile;
  465. int len;
  466. WCHAR* p;
  467. // set mime type
  468. // assume lower cases
  469. len = lstrlen(m_localStoreFilePath);
  470. p = m_localStoreFilePath + len - 5;
  471. if ((p[1] == L'.' && p[2] == L'h' && p[3] == L't' && p[4] == L'm')
  472. || (p[0] == L'.' && p[1] == L'h' && p[2] == L't' && p[3] == L'm' && p[4] == L'l')) //L".htm" ".html"
  473. sprintf(header, "%s\r\nContent-Type: text/html\r\n", HTTP_RESPONSEOK);
  474. else if (p[1] == L'.' && p[2] == L'g' && p[3] == L'i' && p[4] == L'f') //L".gif"
  475. sprintf(header, "%s\r\nContent-Type: image/gif\r\n", HTTP_RESPONSEOK);
  476. else if ((p[1] == L'.' && p[2] == L'j' && p[3] == L'p' && p[4] == L'g')
  477. || (p[0] == L'.' && p[1] == L'j' && p[2] == L'p' && p[3] == L'e' && p[4] == L'g')) //L".jpg" ".jpeg"
  478. sprintf(header, "%s\r\nContent-Type: image/jpeg\r\n", HTTP_RESPONSEOK);
  479. else
  480. sprintf(header, "%s", HTTP_RESPONSEOK);
  481. SendHeaders(header);
  482. hFile = CreateFile(m_localStoreFilePath, GENERIC_READ, 0, NULL,
  483. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  484. if(hFile == INVALID_HANDLE_VALUE)
  485. {
  486. hr = GetLastWin32Error();
  487. goto exit;
  488. }
  489. ZeroMemory(buffer, sizeof(buffer));
  490. while ( ReadFile (hFile, buffer, 512, &dwLength, NULL) && dwLength )
  491. {
  492. WriteBytes(buffer, dwLength);
  493. }
  494. if (hFile != INVALID_HANDLE_VALUE)
  495. CloseHandle(hFile);
  496. hr = Finish();
  497. }
  498. exit:
  499. return hr;
  500. }
  501. /////////////////////////////////////////////////////////////////////////////
  502. /////////////////////////////////////////////////////////////////////////////
  503. /////////////////////////////////////////////////////////////////////////////
  504. HRESULT
  505. AppProtocol::Finish()
  506. {
  507. HRESULT hr = S_OK;
  508. if (m_done == FALSE)
  509. {
  510. m_done = TRUE;
  511. m_pProtocolSink->ReportData(BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 0, m_cbOutput);
  512. if (m_aborted == FALSE)
  513. m_pProtocolSink->ReportResult(S_OK, 0, NULL);
  514. }
  515. return hr;
  516. }
  517. /////////////////////////////////////////////////////////////////////////////
  518. /////////////////////////////////////////////////////////////////////////////
  519. /////////////////////////////////////////////////////////////////////////////
  520. HRESULT
  521. AppProtocol::Abort(
  522. HRESULT hrReason,
  523. DWORD )
  524. {
  525. HRESULT hr = S_OK;
  526. m_aborted = TRUE;
  527. if (m_pProtocolSink != NULL)
  528. {
  529. hr = m_pProtocolSink->ReportResult(hrReason, 0, 0);
  530. if (FAILED(hr))
  531. goto exit;
  532. }
  533. exit:
  534. return hr;
  535. }
  536. /////////////////////////////////////////////////////////////////////////////
  537. /////////////////////////////////////////////////////////////////////////////
  538. /////////////////////////////////////////////////////////////////////////////
  539. HRESULT
  540. AppProtocol::Terminate(
  541. DWORD )
  542. {
  543. Cleanup();
  544. return S_OK;
  545. }
  546. HRESULT
  547. AppProtocol::Suspend()
  548. {
  549. return E_NOTIMPL;
  550. }
  551. HRESULT
  552. AppProtocol::Resume()
  553. {
  554. return E_NOTIMPL;
  555. }
  556. HRESULT
  557. AppProtocol::Read(
  558. void *pv,
  559. ULONG cb,
  560. ULONG *pcbRead)
  561. {
  562. HRESULT hr;
  563. hr = m_pOutputRead->Read(pv, cb, pcbRead);
  564. // We must only return S_FALSE when we have hit the absolute end of the stream
  565. // If we think there is more data coming down the wire, then we return E_PENDING
  566. // here. Even if we return S_OK and no data, UrlMON will still think we've hit
  567. // the end of the stream.
  568. // if (S_OK == hr && 0 == *pcbRead)
  569. //****
  570. if (S_OK == hr && (0 == *pcbRead || cb > *pcbRead))
  571. {
  572. hr = m_done ? S_FALSE : E_PENDING;
  573. }
  574. return hr;
  575. }
  576. /////////////////////////////////////////////////////////////////////////////
  577. /////////////////////////////////////////////////////////////////////////////
  578. /////////////////////////////////////////////////////////////////////////////
  579. HRESULT
  580. AppProtocol::Seek(
  581. LARGE_INTEGER offset,
  582. DWORD origin,
  583. ULARGE_INTEGER *pPos)
  584. {
  585. return m_pOutputRead->Seek(offset, origin, pPos);
  586. }
  587. HRESULT
  588. AppProtocol::LockRequest(
  589. DWORD )
  590. {
  591. return S_OK;
  592. }
  593. HRESULT
  594. AppProtocol::UnlockRequest()
  595. {
  596. return S_OK;
  597. }
  598. /////////////////////////////////////////////////////////////////////////////
  599. /////////////////////////////////////////////////////////////////////////////
  600. /////////////////////////////////////////////////////////////////////////////
  601. HRESULT
  602. AppProtocol::SendHeaders(
  603. LPSTR headers)
  604. {
  605. HRESULT hr = S_OK;
  606. // DWORD flags = 0;
  607. DWORD dwLength = 0;
  608. LPSTR mime = NULL;
  609. LPSTR tail = NULL;
  610. int iHLen = 0;
  611. if(headers == NULL)
  612. {
  613. hr = E_UNEXPECTED;
  614. goto exit;
  615. }
  616. if (m_strResponseHeader != NULL)
  617. MemFree(m_strResponseHeader);
  618. iHLen = strlen(headers);
  619. m_strResponseHeader = (WCHAR *) MemAllocClear(iHLen*sizeof(WCHAR) + 512);
  620. if (m_strResponseHeader != NULL)
  621. {
  622. wcscpy(m_strResponseHeader, L"Server: Microsoft.Net-App/1.0\r\nDate:"); // Microsoft-IIS/App 1.0
  623. WCHAR szTemp[100];
  624. szTemp[0] = NULL;
  625. GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL, szTemp, 100);
  626. wcscat(m_strResponseHeader, szTemp);
  627. wcscat(m_strResponseHeader, L" ");
  628. GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, szTemp, 100);
  629. wcscat(m_strResponseHeader, szTemp);
  630. wcscat(m_strResponseHeader, L"\r\n");
  631. int iLen = wcslen(m_strResponseHeader);
  632. MultiByteToWideChar(CP_ACP, 0, headers, -1, &m_strResponseHeader[iLen], iHLen + 256 - iLen - 1);
  633. }
  634. mime = stristr(headers, "Content-Type:");
  635. if(mime)
  636. {
  637. mime += 13;
  638. while(*mime && isspace(*mime))
  639. mime++;
  640. tail = mime;
  641. while(*tail && *tail != '\r')
  642. tail++;
  643. dwLength = tail - mime;
  644. if(dwLength)
  645. {
  646. if (m_responseMimeType)
  647. MemFree(m_responseMimeType);
  648. m_responseMimeType = (WCHAR *) MemAlloc((dwLength + 1) * sizeof(WCHAR));
  649. if (m_responseMimeType == NULL)
  650. {
  651. hr = E_OUTOFMEMORY;
  652. goto exit;
  653. }
  654. MultiByteToWideChar(CP_ACP, 0, mime, dwLength, m_responseMimeType, dwLength);
  655. m_responseMimeType[dwLength] = L'\0';
  656. }
  657. }
  658. if (m_responseMimeType && *m_responseMimeType)
  659. m_pProtocolSink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, m_responseMimeType);
  660. else
  661. m_pProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"text/plain"); //proper default not L"text/html");
  662. //**** SaveCookie(headers);
  663. exit:
  664. return hr;
  665. }
  666. /////////////////////////////////////////////////////////////////////////////
  667. /////////////////////////////////////////////////////////////////////////////
  668. /////////////////////////////////////////////////////////////////////////////
  669. /*HRESULT
  670. AppProtocol::SaveCookie(
  671. LPSTR header)
  672. {
  673. HRESULT hr = S_OK;
  674. LPSTR cookie, tail;
  675. WCHAR *cookieBody = NULL;
  676. int bodyLength;
  677. for(cookie = stristr(header, "Set-Cookie:");
  678. cookie != NULL;
  679. cookie = (*tail ? stristr(tail, "Set-Cookie:") : NULL)) //???? added () around ? :
  680. {
  681. cookie += 11;
  682. while(*cookie && isspace(*cookie))
  683. cookie++;
  684. tail = cookie;
  685. while(*tail && *tail != '\r')
  686. tail++;
  687. bodyLength = tail - cookie;
  688. if(bodyLength)
  689. {
  690. cookieBody = (WCHAR *)MemAlloc(sizeof(WCHAR) *(bodyLength + 1));
  691. if (cookieBody == NULL)
  692. {
  693. hr = E_OUTOFMEMORY;
  694. goto exit;
  695. }
  696. MultiByteToWideChar(CP_ACP, 0, cookie, bodyLength, cookieBody, bodyLength);
  697. cookieBody[bodyLength] = '\0';
  698. if(!g_pInternetSetCookieW(m_cookiePath, NULL, cookieBody))
  699. {
  700. hr = GetLastWin32Error();
  701. goto exit;
  702. }
  703. }
  704. }
  705. exit:
  706. if (cookieBody)
  707. MemFree(cookieBody);
  708. return hr;
  709. }*/
  710. /////////////////////////////////////////////////////////////////////////////
  711. /////////////////////////////////////////////////////////////////////////////
  712. /////////////////////////////////////////////////////////////////////////////
  713. HRESULT
  714. AppProtocol::WriteBytes(
  715. BYTE * buffer,
  716. DWORD dwLength)
  717. {
  718. HRESULT hr = S_OK;
  719. DWORD flags = 0;
  720. EnterCriticalSection(&m_csOutputWriter);
  721. if (!m_pOutputWrite)
  722. {
  723. hr = E_UNEXPECTED;
  724. }
  725. if (FAILED(hr = m_pOutputWrite->Write(buffer, dwLength, &dwLength)))
  726. goto exit;
  727. m_cbOutput += dwLength;
  728. if (!m_started)
  729. {
  730. m_started = TRUE;
  731. flags |= BSCF_FIRSTDATANOTIFICATION;
  732. }
  733. else //****
  734. if (m_done)
  735. {
  736. flags |= BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE;
  737. }
  738. else //****
  739. flags |= BSCF_INTERMEDIATEDATANOTIFICATION;
  740. if (FAILED(hr = m_pProtocolSink->ReportData(flags, dwLength, m_cbOutput)))
  741. goto exit;
  742. exit:
  743. LeaveCriticalSection(&m_csOutputWriter);
  744. return hr;
  745. }
  746. /////////////////////////////////////////////////////////////////////////////
  747. /////////////////////////////////////////////////////////////////////////////
  748. /////////////////////////////////////////////////////////////////////////////
  749. /*int
  750. AppProtocol::GetKnownRequestHeader (
  751. LPCWSTR szHeader,
  752. LPWSTR buf,
  753. int size)
  754. {
  755. if (szHeader == NULL || szHeader[0] == NULL || wcslen(szHeader) > 256)
  756. return 0;
  757. LPCWSTR szReturn = NULL;
  758. LPCWSTR szStart = NULL;
  759. int iLen = 0;
  760. HRESULT hr = S_OK;
  761. // int iter = 0;
  762. WCHAR szHeadUpr[260] = L"";
  763. wcscpy(szHeadUpr, szHeader);
  764. _wcsupr(szHeadUpr);
  765. if (wcscmp(szHeadUpr, SZ_HTTP_COOKIE) == 0)
  766. {
  767. szReturn = m_cookie;
  768. iLen = (m_cookie ? wcslen(m_cookie) : 0);
  769. goto exit;
  770. }
  771. if (m_extraHeadersUpr == NULL && m_extraHeaders != NULL)
  772. {
  773. m_extraHeadersUpr = DuplicateString(m_extraHeaders);
  774. if (m_extraHeadersUpr == NULL)
  775. {
  776. hr = E_OUTOFMEMORY;
  777. goto exit;
  778. }
  779. _wcsupr(m_extraHeadersUpr);
  780. }
  781. if (m_extraHeadersUpr == NULL)
  782. goto exit;
  783. szStart = wcsstr(m_extraHeadersUpr, szHeadUpr);
  784. if (szStart == NULL)
  785. goto exit;
  786. iLen = wcslen(szHeadUpr);
  787. szReturn = &(m_extraHeaders[iLen+1]);
  788. while(iswspace(*szReturn))
  789. szReturn++;
  790. for (iLen = 0; szReturn[iLen] != L'\r' && szReturn[iLen] != NULL; iLen++);
  791. exit:
  792. if (szReturn == NULL || iLen == 0)
  793. return 0;
  794. if (iLen >= size)
  795. return -(iLen + 1);
  796. buf[iLen] = NULL;
  797. memcpy(buf, szReturn, iLen*sizeof(WCHAR));
  798. return iLen;
  799. }
  800. */
  801. /////////////////////////////////////////////////////////////////////////////
  802. /////////////////////////////////////////////////////////////////////////////
  803. /////////////////////////////////////////////////////////////////////////////
  804. //
  805. // TODO: make it real, netclasses, manifest and all that
  806. //
  807. // ???? construct filename, create directory
  808. HRESULT
  809. AppProtocol::SetupAndInstall(
  810. LPTSTR url, /* *not* ok to modify */
  811. LPTSTR path /* out */)
  812. {
  813. HRESULT hr = S_OK;
  814. // WCHAR *installFromPath = NULL; // full path - app://www.microsoft.com/app5/app.manifest
  815. WCHAR *origin = NULL; // src - www.microsoft.com/app5
  816. WCHAR *p, *q;
  817. int i, j;
  818. // skip app:// part
  819. origin = DuplicateString(url + lstrlen(PROTOCOL_SCHEME));
  820. if (origin == NULL)
  821. {
  822. hr = E_OUTOFMEMORY;
  823. goto exit;
  824. }
  825. // installFromPath = (WCHAR *) MemAlloc((lstrlen(origin/*url*/) + lstrlen(HTTP_SCHEME)/*MAX_PATH*/) * sizeof(WCHAR));
  826. // if (installFromPath == NULL)
  827. // {
  828. // hr = E_OUTOFMEMORY;
  829. // goto exit;
  830. // }
  831. //???????????????????????
  832. WCHAR installFromPath[MAX_URL_LENGTH];
  833. lstrcpy(installFromPath, HTTP_SCHEME);
  834. lstrcat(installFromPath, origin);
  835. // assume file name is given (it's now passed in) - not myweb.cab
  836. // better? - check if last contain ".", if so assume has filename, else attach app.manifest as filename
  837. // lstrcat(installFromPath, L"/MyWeb.cab"); //????????? if no filename it will get index.html, if exists!
  838. // remove the filename, if specified
  839. // ?????????? this assume all filename has a '.'
  840. p = wcsrchr(origin, L'/');
  841. q = wcsrchr(origin, L'.');
  842. if (p && q && /*((p - origin) > 6) &&*/ (p < q))
  843. *p = L'\0';
  844. // else - no filename -> do something to installFromPath? or no '/' after "app://" in url
  845. else
  846. {
  847. hr = E_INVALIDARG;
  848. goto exit;
  849. }
  850. // install to
  851. if(GetEnvironmentVariable(L"ProgramFiles", path, MAX_PATH-lstrlen(STORE_PATH)-1) == 0) //????????
  852. {
  853. //
  854. hr = CO_E_PATHTOOLONG;//E_FAIL;
  855. goto exit;
  856. }
  857. // ????????
  858. lstrcat(path, STORE_PATH);
  859. if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
  860. {
  861. hr = GetLastWin32Error();
  862. goto exit;
  863. }
  864. lstrcat(path, L"\\");
  865. i = lstrlen(path);
  866. j = 0;
  867. while(origin[j])
  868. {
  869. if(origin[j] == L'/')
  870. {
  871. path[i] = L'\0';
  872. if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
  873. {
  874. hr = GetLastWin32Error();
  875. goto exit;
  876. }
  877. path[i] = L'\\';
  878. }
  879. else
  880. path[i] = origin[j];
  881. i++;
  882. j++;
  883. }
  884. path[i] = L'\0';
  885. if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
  886. {
  887. hr = GetLastWin32Error();
  888. goto exit;
  889. }
  890. // grab the files
  891. hr = InstallInternetFile(installFromPath, path);
  892. exit:
  893. // if(installFromPath) MemFree(installFromPath);
  894. if(origin) MemFree(origin);
  895. return hr;
  896. }
  897. /////////////////////////////////////////////////////////////////////////////
  898. /////////////////////////////////////////////////////////////////////////////
  899. /////////////////////////////////////////////////////////////////////////////
  900. //
  901. // given the url like MyWeb://www.site.com/app/something/else?querystring=aa
  902. // sets
  903. // m_uriPath to /app/something/else
  904. // m_queryString to querystring=aa
  905. // m_appRoot to /app or
  906. // /app/something or
  907. // /app/something/else,
  908. // depending on which was successfully mapped to
  909. // m_appRootTranslated to, for instance, c:\program files\site app\
  910. // not set till SetupAndInstall() is called
  911. // m_appOrigin to www.site.com
  912. // m_fullUri to myweb://www.site.com/app/something/else
  913. //
  914. // if application was not installed, attempts to install it
  915. //
  916. // ???? setup strings, find out if needs install
  917. HRESULT
  918. AppProtocol::ParseUrl(LPCTSTR url)
  919. {
  920. HRESULT hr = S_OK;
  921. WCHAR slash = L'/';
  922. WCHAR *p, *base;
  923. int cchFullUri = 0;
  924. // WCHAR appRootTranslated[MAX_PATH];
  925. // copy the cookie path into member variable
  926. m_fullUri = DuplicateString(url);
  927. if (m_fullUri == NULL)
  928. {
  929. hr = E_OUTOFMEMORY;
  930. goto exit;
  931. }
  932. // locate, store and strip query string, if any
  933. p = wcschr(m_fullUri, L'?');
  934. if(p != NULL && p[1] != L'\0')
  935. {
  936. m_queryString = p + 1;
  937. *p = L'\0';
  938. }
  939. // ????? to be moved
  940. // assume lower cases
  941. // need to find from end, skip ?querystring, use m_fullUri instead?
  942. cchFullUri = lstrlen(m_fullUri);
  943. m_appType = APPTYPE_IE;
  944. // ????? BUGBUG assume >= than 9 characters
  945. if (cchFullUri >= 9)
  946. {
  947. p = m_fullUri + cchFullUri - 5;
  948. /* if (p[0] != L'.' && p[1] != L'.')
  949. // error? no extension
  950. m_appType = APPTYPE_IE;
  951. else*/
  952. if (p[1] == L'.' && (p[2] == L'e' && p[3] == L'x' && p[4] == L'e')
  953. || (p[2] == L'd' && p[3] == L'l' && p[4] == L'l')) //L".exe" ".dll"
  954. m_appType = APPTYPE_ASM; // (check asm or not?)
  955. else if (p[0] == L'.' && p[1] == L'a' && p[2] == L's' && p[3] == L'p' && p[4] == L'x') //L".aspx"
  956. m_appType = APPTYPE_MYWEB;
  957. else if (wcsncmp(p = m_fullUri + cchFullUri - 9, L".manifest", 9) == 0)
  958. m_appType = APPTYPE_BYMANIFEST;
  959. //else //default or others
  960. // m_appType = APPTYPE_IE;
  961. }
  962. // skip through protocol://
  963. p = wcschr(m_fullUri, L':');
  964. if(p == NULL || p[1] != slash || p[2] != slash || p[3] == L'\0')
  965. {
  966. hr = E_INVALIDARG;
  967. }
  968. // copy full origin path
  969. m_appOrigin = DuplicateString(p + 3);
  970. if (m_appOrigin == NULL)
  971. {
  972. hr = E_OUTOFMEMORY;
  973. goto exit;
  974. }
  975. // point to the end of site
  976. base = wcschr(m_appOrigin, slash);
  977. if(base == NULL)
  978. {
  979. hr = E_INVALIDARG;
  980. goto exit;
  981. }
  982. // appRootTranslated[0] = L'\0';
  983. // tear off one segment at a time from the end
  984. while((p = wcsrchr(m_appOrigin, slash)) != base)
  985. {
  986. *p = L'\0';
  987. // if(GetAppBaseDir(m_appOrigin, appRootTranslated) == S_OK)
  988. // {
  989. // break;
  990. // }
  991. }
  992. // moved to Continue()
  993. // if(appRootTranslated[0] == L'\0')
  994. // {
  995. // WCHAR * appPath = DuplicateString(m_fullUri);
  996. // WCHAR * p;
  997. // application not installed, install it
  998. /* if (appPath == NULL)
  999. {
  1000. hr = E_OUTOFMEMORY;
  1001. goto exit;
  1002. }
  1003. */
  1004. // ???? why? - this will remove the last - supposingly the filename?
  1005. // p = wcsrchr(appPath, L'/');
  1006. // if(p) *p = NULL;
  1007. // hr = SetupAndInstall(m_fullUri/*appPath*/, appRootTranslated);
  1008. // if (FAILED(hr))
  1009. // goto exit;
  1010. // if(appPath) MemFree(appPath);
  1011. // }
  1012. /* m_appRootTranslated = DuplicateString(appRootTranslated);
  1013. if (m_appRootTranslated == NULL)
  1014. {
  1015. hr = E_OUTOFMEMORY;
  1016. goto exit;
  1017. }
  1018. */
  1019. m_appRoot = wcschr(m_appOrigin, slash);
  1020. // ???? this should be ok
  1021. /* if(m_appRoot == NULL)
  1022. {
  1023. hr = E_INVALIDARG;
  1024. goto exit;
  1025. }
  1026. */
  1027. if (m_appRoot)
  1028. m_uriPath = wcsstr(m_fullUri, m_appRoot);
  1029. else
  1030. // ???? this should be ok
  1031. m_uriPath = NULL;
  1032. exit:
  1033. return hr;
  1034. }
  1035. /////////////////////////////////////////////////////////////////////////////
  1036. /////////////////////////////////////////////////////////////////////////////
  1037. /////////////////////////////////////////////////////////////////////////////
  1038. //
  1039. // Note: appRoot is assumed to have enough space (MAX_PATH)
  1040. //
  1041. /*HRESULT AppProtocol::GetAppBaseDir(LPCTSTR base, LPTSTR appRoot)
  1042. {
  1043. HKEY hKey = NULL;
  1044. HRESULT hr = E_FAIL;
  1045. HKEY hSubKey = NULL;
  1046. appRoot[0] = L'\0';
  1047. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, MYWEBS_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
  1048. {
  1049. hr = GetLastWin32Error();
  1050. goto exit;
  1051. }
  1052. if(RegOpenKeyEx(hKey, base, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
  1053. {
  1054. DWORD dwType, cb = MAX_PATH * sizeof(WCHAR);
  1055. if(RegQueryValueEx(hSubKey, MYWEBS_APPROOT, NULL, &dwType, (LPBYTE)appRoot, &cb) == ERROR_SUCCESS)
  1056. {
  1057. dwType = GetFileAttributes(appRoot);
  1058. if (dwType == (DWORD) -1 || (dwType & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1059. appRoot[0] = NULL;
  1060. else
  1061. hr = S_OK;
  1062. }
  1063. RegCloseKey(hSubKey);
  1064. }
  1065. RegCloseKey(hKey);
  1066. //exit:
  1067. return hr;
  1068. }*/
  1069. /////////////////////////////////////////////////////////////////////////////
  1070. /////////////////////////////////////////////////////////////////////////////
  1071. /////////////////////////////////////////////////////////////////////////////
  1072. // ???????called only from managed code?
  1073. WCHAR *
  1074. AppProtocol::MapString(
  1075. int key)
  1076. {
  1077. /* switch(key)
  1078. {
  1079. case IEWR_URIPATH:
  1080. return m_uriPath;
  1081. case IEWR_QUERYSTRING:
  1082. return m_queryString;
  1083. case IEWR_VERB:
  1084. return m_verb;
  1085. case IEWR_APPPATH:
  1086. return m_appRoot;
  1087. case IEWR_APPPATHTRANSLATED:
  1088. return m_appRootTranslated;
  1089. default:*/
  1090. if (key)
  1091. key=key; // ???????
  1092. return NULL;
  1093. // }
  1094. }
  1095. /////////////////////////////////////////////////////////////////////////////
  1096. /////////////////////////////////////////////////////////////////////////////
  1097. /////////////////////////////////////////////////////////////////////////////
  1098. // ????????called only from managed code?
  1099. int
  1100. AppProtocol::GetStringLength(
  1101. int key)
  1102. {
  1103. WCHAR *targetString = MapString(key);
  1104. return targetString ? lstrlen(targetString) + 1 : 0;
  1105. }
  1106. /////////////////////////////////////////////////////////////////////////////
  1107. /////////////////////////////////////////////////////////////////////////////
  1108. /////////////////////////////////////////////////////////////////////////////
  1109. int
  1110. AppProtocol::GetString(
  1111. int key,
  1112. WCHAR * buf,
  1113. int size)
  1114. {
  1115. WCHAR *targetString = MapString(key);
  1116. int len;
  1117. if(targetString == NULL)
  1118. return 0;
  1119. len = lstrlen(targetString);
  1120. if(len >= size)
  1121. return 0;
  1122. lstrcpy(buf, targetString);
  1123. return len + 1;
  1124. }
  1125. /////////////////////////////////////////////////////////////////////////////
  1126. /////////////////////////////////////////////////////////////////////////////
  1127. /////////////////////////////////////////////////////////////////////////////
  1128. /*int
  1129. AppProtocol::MapPath(
  1130. WCHAR * virtualPath,
  1131. WCHAR * physicalPath,
  1132. int length)
  1133. {
  1134. int requiredLength = lstrlen(m_appRootTranslated) + 2;
  1135. int rootLength = lstrlen(m_appRoot);
  1136. int i = 0;
  1137. if(virtualPath && virtualPath[0] != '\0')
  1138. {
  1139. requiredLength += lstrlen(virtualPath) - rootLength;
  1140. }
  1141. if(requiredLength <= 0)
  1142. return 0;
  1143. if(requiredLength > length)
  1144. return - requiredLength;
  1145. while(m_appRootTranslated[i])
  1146. {
  1147. physicalPath[i] = m_appRootTranslated[i];
  1148. i++;
  1149. }
  1150. if(virtualPath && virtualPath[0] != L'\0')
  1151. {
  1152. if(_memicmp(virtualPath, m_appRoot, sizeof(WCHAR) * rootLength))
  1153. return 0;
  1154. virtualPath += rootLength;
  1155. if(*virtualPath && *virtualPath != L'/')
  1156. physicalPath[i++] = L'\\';
  1157. while(*virtualPath)
  1158. {
  1159. if(*virtualPath == L'/')
  1160. physicalPath[i++] = L'\\';
  1161. else
  1162. physicalPath[i++] = *virtualPath;
  1163. virtualPath++;
  1164. }
  1165. }
  1166. physicalPath[i] = L'\0';
  1167. return 1;
  1168. }
  1169. */
  1170. /////////////////////////////////////////////////////////////////////////////
  1171. /////////////////////////////////////////////////////////////////////////////
  1172. /////////////////////////////////////////////////////////////////////////////
  1173. // ????? download file from url into path
  1174. HRESULT
  1175. AppProtocol::InstallInternetFile(
  1176. LPTSTR url,
  1177. LPTSTR path)
  1178. {
  1179. HRESULT hr = S_OK;
  1180. HINTERNET hInternet = NULL;
  1181. HINTERNET hTransfer = NULL;
  1182. HANDLE hFile = INVALID_HANDLE_VALUE;
  1183. WCHAR * file = NULL;
  1184. DWORD bytesRead = 0;
  1185. DWORD bytesWritten = 0;
  1186. WCHAR szFile[MAX_PATH];
  1187. BYTE buffer[4096];
  1188. BOOL bNeedDownload = TRUE;
  1189. // CabHandlerInfo cabInfo;
  1190. // ????????? TO BE MOVED!
  1191. // check offline mode
  1192. DWORD dwState = 0;
  1193. DWORD dwSize = sizeof(DWORD);
  1194. BOOL bRemoveEmptyFile = FALSE;
  1195. if(g_pInternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize))
  1196. {
  1197. if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
  1198. m_status |= STATUS_OFFLINE_MODE;
  1199. }
  1200. ////////////////////////////////////////////////////////////
  1201. // Step 1: Construct the file name
  1202. // ???? this assumes there is a filename after the last '/'
  1203. ZeroMemory(szFile, sizeof(szFile));
  1204. wcsncpy(szFile, path, MAX_PATH - 2);
  1205. lstrcat(szFile, L"\\");
  1206. file = wcsrchr(url, L'/');
  1207. if (file != NULL && wcslen(szFile) + wcslen(file) < MAX_PATH)
  1208. wcscat(szFile, file + 1);
  1209. else
  1210. {
  1211. hr = CO_E_PATHTOOLONG;//E_FAIL;
  1212. goto exit;
  1213. }
  1214. MemClearFn((void **)&m_localStoreFilePath);
  1215. m_localStoreFilePath = DuplicateString(szFile);
  1216. ////////////////////////////////////////////////////////////
  1217. // Step 2: Create the file
  1218. // need write access, will open (and replace/overwrite) exiting file
  1219. // ??? FILE_SHARE_READ? but we might write to if outdated...
  1220. hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL,
  1221. OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1222. if(hFile == INVALID_HANDLE_VALUE)
  1223. {
  1224. hr = GetLastWin32Error();
  1225. goto exit;
  1226. }
  1227. // ????????? TO BE MOVED!
  1228. if (GetLastError() == ERROR_ALREADY_EXISTS)
  1229. {
  1230. FILETIME ftLastModified;
  1231. #define FTTICKSPERDAY (60*60*24*(LONGLONG) 10000000) // == 864000000000
  1232. if (GetFileTime(hFile, NULL, NULL, &ftLastModified))
  1233. {
  1234. SYSTEMTIME sSysT;
  1235. FILETIME ft;
  1236. GetSystemTime(&sSysT);
  1237. SystemTimeToFileTime(&sSysT, &ft);
  1238. ULARGE_INTEGER ulInt = * (ULARGE_INTEGER *) &ft;
  1239. ulInt.QuadPart -= FTTICKSPERDAY * 3; // 3 days
  1240. ft = * (FILETIME *) &ulInt;
  1241. if (CompareFileTime(&ftLastModified, &ft) != -1)
  1242. // reuse file, just execute it
  1243. bNeedDownload = FALSE;
  1244. }
  1245. }
  1246. else
  1247. m_status |= STATUS_NOT_IN_CACHE;
  1248. if ((m_status & STATUS_OFFLINE_MODE) && (m_status & STATUS_NOT_IN_CACHE))
  1249. {
  1250. // hr = E_FAIL; // ???? file not found - if uncomment this line, generic IE error page will display instead
  1251. bRemoveEmptyFile = TRUE;
  1252. goto exit;
  1253. }
  1254. if (bNeedDownload && !(m_status & STATUS_OFFLINE_MODE))
  1255. {
  1256. ////////////////////////////////////////////////////////////
  1257. // Step 3: Copy the files over the internet
  1258. hInternet = g_pInternetOpen(L"App", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
  1259. if(hInternet == NULL)
  1260. {
  1261. hr = GetLastWin32Error();
  1262. bRemoveEmptyFile = TRUE;
  1263. goto exit;
  1264. }
  1265. // use own caching instead
  1266. hTransfer = g_pInternetOpenUrl(hInternet, url, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0);
  1267. if(hTransfer == NULL)
  1268. {
  1269. hr = GetLastWin32Error();
  1270. bRemoveEmptyFile = TRUE;
  1271. goto exit;
  1272. }
  1273. // need to check if there's any error, eg. not found (404)...
  1274. // synchronous download
  1275. while(g_pInternetReadFile(hTransfer, buffer, sizeof(buffer), &bytesRead) && bytesRead != 0)
  1276. {
  1277. if ( !WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL) ||
  1278. bytesWritten != bytesRead )
  1279. {
  1280. hr = GetLastWin32Error();
  1281. bRemoveEmptyFile = TRUE;
  1282. goto exit;
  1283. }
  1284. }
  1285. }
  1286. // ensure file/internet handles are closed before further processing is done
  1287. if (hFile != INVALID_HANDLE_VALUE)
  1288. CloseHandle(hFile);
  1289. if (hInternet != NULL)
  1290. g_pInternetCloseHandle(hInternet);
  1291. if (hTransfer != NULL)
  1292. g_pInternetCloseHandle(hTransfer);
  1293. hInternet = NULL;
  1294. hTransfer = NULL;
  1295. hFile = INVALID_HANDLE_VALUE;
  1296. // ????????? TO BE MOVED!
  1297. // process - run all .exe
  1298. // lower case? end of string?
  1299. if (/*m_appType == APPTYPE_ASM)*/wcsstr(file, L".exe"))
  1300. {
  1301. //#define MAX_SIZE_SECURITY_ID 0x200
  1302. DWORD dwZone;
  1303. DWORD dwSize = MAX_SIZE_SECURITY_ID;
  1304. BYTE byUniqueID[MAX_SIZE_SECURITY_ID];
  1305. WCHAR wzUniqueID[MAX_SIZE_SECURITY_ID * 2 + 1];
  1306. WCHAR wzCmdLine[1025];
  1307. //IInternetSecurityManager::ProcessUrlAction
  1308. // lazy init
  1309. if (g_pSecurityMgr == NULL)
  1310. {
  1311. hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
  1312. IID_IInternetSecurityManager, (void**)&g_pSecurityMgr);
  1313. //???? should this fails at all if security info/manager is undef?
  1314. if (FAILED(hr))
  1315. {
  1316. g_pSecurityMgr = NULL;
  1317. goto exit;
  1318. }
  1319. }
  1320. // m_fullUri -> this should translate correctly in IInternetProtocolInfo->ParseUrl()
  1321. if (SUCCEEDED(hr = g_pSecurityMgr->MapUrlToZone(m_fullUri, &dwZone, 0)))
  1322. {
  1323. // check space in site? - assume checked in GetSecurityId
  1324. // should site be just www.abc.com or www.abc.com/app2/appmain.exe?
  1325. if (FAILED(hr)
  1326. || FAILED(hr = g_pSecurityMgr->GetSecurityId(m_fullUri, byUniqueID, &dwSize, 0)))
  1327. goto exit;
  1328. ConvertToHex(wzUniqueID, byUniqueID, dwSize);
  1329. }
  1330. else
  1331. {
  1332. goto exit;
  1333. }
  1334. // ???? any space in url? start a new proc for that asm, not hang the browser
  1335. /* C:\\Documents and Settings\\felixybc.NTDEV\\Desktop\\work\\conexec\\Debug\\*/
  1336. if (_snwprintf(wzCmdLine, 1025,
  1337. L"conexec.exe \"%s\" +3 %d %s %s", szFile, dwZone, wzUniqueID, url) < 0)
  1338. {
  1339. hr = CO_E_PATHTOOLONG;
  1340. goto exit;
  1341. }
  1342. RunCommand(wzCmdLine);
  1343. }
  1344. exit:
  1345. if (hFile != INVALID_HANDLE_VALUE)
  1346. CloseHandle(hFile);
  1347. if (hInternet != NULL)
  1348. g_pInternetCloseHandle(hInternet);
  1349. if (hTransfer != NULL)
  1350. g_pInternetCloseHandle(hTransfer);
  1351. hInternet = NULL;
  1352. hTransfer = NULL;
  1353. hFile = INVALID_HANDLE_VALUE;
  1354. // remove the file so that it will not be mistaken next time this runs
  1355. // ignore if error deleting the file so the hr is not overwritten
  1356. if (bRemoveEmptyFile)
  1357. DeleteFile(szFile);
  1358. return hr;
  1359. }
  1360. /////////////////////////////////////////////////////////////////////////////
  1361. /////////////////////////////////////////////////////////////////////////////
  1362. /////////////////////////////////////////////////////////////////////////////
  1363. HRESULT
  1364. AppProtocol::QueryOption(DWORD, LPVOID, DWORD*)
  1365. {
  1366. return E_NOTIMPL;
  1367. }
  1368. /////////////////////////////////////////////////////////////////////////////
  1369. /////////////////////////////////////////////////////////////////////////////
  1370. /////////////////////////////////////////////////////////////////////////////
  1371. HRESULT
  1372. AppProtocol::QueryInfo(
  1373. DWORD dwOption,
  1374. LPVOID pBuffer,
  1375. LPDWORD pcbBuf,
  1376. LPDWORD ,
  1377. LPDWORD )
  1378. {
  1379. if (pcbBuf == NULL)
  1380. return E_FAIL;
  1381. HRESULT hr = S_OK;
  1382. LPCWSTR szHeader = NULL;
  1383. DWORD dwOpt = (dwOption & HTTP_QUERY_HEADER_MASK);
  1384. DWORD dwLen = (m_strResponseHeader ? wcslen(m_strResponseHeader) : 0);
  1385. switch(dwOpt)
  1386. {
  1387. case HTTP_QUERY_RAW_HEADERS_CRLF:
  1388. case HTTP_QUERY_RAW_HEADERS:
  1389. if (m_strResponseHeader == NULL)
  1390. return E_FAIL;
  1391. if (*pcbBuf < dwLen + 1)
  1392. {
  1393. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1394. }
  1395. else
  1396. {
  1397. if (dwOpt == HTTP_QUERY_RAW_HEADERS_CRLF)
  1398. {
  1399. wcscpy((WCHAR *) pBuffer, m_strResponseHeader);
  1400. }
  1401. else
  1402. {
  1403. DWORD iPos = 0;
  1404. for(DWORD iter=0; iter<dwLen; iter++)
  1405. if (m_strResponseHeader[iter] == L'\r' && m_strResponseHeader[iter+1] == L'\n')
  1406. {
  1407. ((WCHAR *)pBuffer)[iPos++] = L'0';
  1408. iter++;
  1409. }
  1410. else
  1411. {
  1412. ((WCHAR *)pBuffer)[iPos++] = m_strResponseHeader[iter];
  1413. }
  1414. *pcbBuf = iPos;
  1415. }
  1416. }
  1417. goto exit;
  1418. case HTTP_QUERY_ACCEPT:
  1419. szHeader = L"Accept:";
  1420. break;
  1421. case HTTP_QUERY_ACCEPT_CHARSET:
  1422. szHeader = L"Accept-Charset:";
  1423. break;
  1424. case HTTP_QUERY_ACCEPT_ENCODING:
  1425. szHeader = L"Accept-Encoding:";
  1426. break;
  1427. case HTTP_QUERY_ACCEPT_LANGUAGE:
  1428. szHeader = L"Accept-Language:";
  1429. break;
  1430. case HTTP_QUERY_ACCEPT_RANGES:
  1431. szHeader = L"Accept-Ranges:";
  1432. break;
  1433. case HTTP_QUERY_AGE:
  1434. szHeader = L"Age:";
  1435. break;
  1436. case HTTP_QUERY_ALLOW:
  1437. szHeader = L"Allow:";
  1438. break;
  1439. case HTTP_QUERY_AUTHORIZATION:
  1440. szHeader = L"Authorization:";
  1441. break;
  1442. case HTTP_QUERY_CACHE_CONTROL:
  1443. szHeader = L"Cache-Control:";
  1444. break;
  1445. case HTTP_QUERY_CONNECTION:
  1446. szHeader = L"Connection:";
  1447. break;
  1448. case HTTP_QUERY_CONTENT_BASE:
  1449. szHeader = L"Content-Base:";
  1450. break;
  1451. case HTTP_QUERY_CONTENT_DESCRIPTION:
  1452. szHeader = L"Content-Description:";
  1453. break;
  1454. case HTTP_QUERY_CONTENT_DISPOSITION:
  1455. szHeader = L"Content-Disposition:";
  1456. break;
  1457. case HTTP_QUERY_CONTENT_ENCODING:
  1458. szHeader = L"Content-encoding:";
  1459. break;
  1460. case HTTP_QUERY_CONTENT_ID:
  1461. szHeader = L"Content-ID:";
  1462. break;
  1463. case HTTP_QUERY_CONTENT_LANGUAGE:
  1464. szHeader = L"Content-Language:";
  1465. break;
  1466. case HTTP_QUERY_CONTENT_LENGTH:
  1467. szHeader = L"Content-Langth:";
  1468. break;
  1469. case HTTP_QUERY_CONTENT_LOCATION:
  1470. szHeader = L"Content-Location:";
  1471. break;
  1472. case HTTP_QUERY_CONTENT_MD5:
  1473. szHeader = L"Content-MD5:";
  1474. break;
  1475. case HTTP_QUERY_CONTENT_TRANSFER_ENCODING:
  1476. szHeader = L"Content-Transfer-Encoding:";
  1477. break;
  1478. case HTTP_QUERY_CONTENT_TYPE:
  1479. szHeader = L"Content-Type:";
  1480. break;
  1481. case HTTP_QUERY_COOKIE:
  1482. szHeader = L"Cookie:";
  1483. break;
  1484. case HTTP_QUERY_COST:
  1485. szHeader = L"Cost:";
  1486. break;
  1487. case HTTP_QUERY_CUSTOM:
  1488. szHeader = L"Custom:";
  1489. break;
  1490. case HTTP_QUERY_DATE:
  1491. szHeader = L"Date:";
  1492. break;
  1493. case HTTP_QUERY_DERIVED_FROM:
  1494. szHeader = L"Derived-From:";
  1495. break;
  1496. case HTTP_QUERY_ECHO_HEADERS:
  1497. szHeader = L"Echo-Headers:";
  1498. break;
  1499. case HTTP_QUERY_ECHO_HEADERS_CRLF:
  1500. szHeader = L"Echo-Headers-Crlf:";
  1501. break;
  1502. case HTTP_QUERY_ECHO_REPLY:
  1503. szHeader = L"Echo-Reply:";
  1504. break;
  1505. case HTTP_QUERY_ECHO_REQUEST:
  1506. szHeader = L"Echo-Request:";
  1507. break;
  1508. case HTTP_QUERY_ETAG:
  1509. szHeader = L"ETag:";
  1510. break;
  1511. case HTTP_QUERY_EXPECT:
  1512. szHeader = L"Expect:";
  1513. break;
  1514. case HTTP_QUERY_EXPIRES:
  1515. szHeader = L"Expires:";
  1516. break;
  1517. case HTTP_QUERY_FORWARDED:
  1518. szHeader = L"Forwarded:";
  1519. break;
  1520. case HTTP_QUERY_FROM:
  1521. szHeader = L"From:";
  1522. break;
  1523. case HTTP_QUERY_HOST:
  1524. szHeader = L"Host:";
  1525. break;
  1526. case HTTP_QUERY_IF_MATCH:
  1527. szHeader = L"If-Match:";
  1528. break;
  1529. case HTTP_QUERY_IF_MODIFIED_SINCE:
  1530. szHeader = L"If-Modified-Since:";
  1531. break;
  1532. case HTTP_QUERY_IF_NONE_MATCH:
  1533. szHeader = L"If-None-Match:";
  1534. break;
  1535. case HTTP_QUERY_IF_RANGE:
  1536. szHeader = L"If-Range:";
  1537. break;
  1538. case HTTP_QUERY_IF_UNMODIFIED_SINCE:
  1539. szHeader = L"If-Unmodified-since:";
  1540. break;
  1541. case HTTP_QUERY_LINK:
  1542. szHeader = L"Link:";
  1543. break;
  1544. case HTTP_QUERY_LAST_MODIFIED:
  1545. szHeader = L"Last-Modified:";
  1546. break;
  1547. case HTTP_QUERY_LOCATION:
  1548. szHeader = L"Location:";
  1549. break;
  1550. case HTTP_QUERY_MAX_FORWARDS:
  1551. szHeader = L"Max-Forwards:";
  1552. break;
  1553. case HTTP_QUERY_MESSAGE_ID:
  1554. szHeader = L"Message_Id:";
  1555. break;
  1556. case HTTP_QUERY_MIME_VERSION:
  1557. szHeader = L"Mime-Version:";
  1558. break;
  1559. case HTTP_QUERY_ORIG_URI:
  1560. szHeader = L"Orig-Uri:";
  1561. break;
  1562. case HTTP_QUERY_PRAGMA:
  1563. szHeader = L"Pragma:";
  1564. break;
  1565. case HTTP_QUERY_PROXY_AUTHENTICATE:
  1566. szHeader = L"Authenticate:";
  1567. break;
  1568. case HTTP_QUERY_PROXY_AUTHORIZATION:
  1569. szHeader = L"Proxy-Authorization:";
  1570. break;
  1571. case HTTP_QUERY_PROXY_CONNECTION:
  1572. szHeader = L"Proxy-Connection:";
  1573. break;
  1574. case HTTP_QUERY_PUBLIC:
  1575. szHeader = L"Public:";
  1576. break;
  1577. case HTTP_QUERY_RANGE:
  1578. szHeader = L"Range:";
  1579. break;
  1580. case HTTP_QUERY_REFERER:
  1581. szHeader = L"Referer:";
  1582. break;
  1583. case HTTP_QUERY_REFRESH:
  1584. szHeader = L"Refresh:";
  1585. break;
  1586. case HTTP_QUERY_REQUEST_METHOD:
  1587. szHeader = L"Request-Method:";
  1588. break;
  1589. case HTTP_QUERY_RETRY_AFTER:
  1590. szHeader = L"Retry-After:";
  1591. break;
  1592. case HTTP_QUERY_SERVER:
  1593. szHeader = L"Server:";
  1594. break;
  1595. case HTTP_QUERY_SET_COOKIE:
  1596. szHeader = L"Set-Cookie:";
  1597. break;
  1598. case HTTP_QUERY_STATUS_CODE:
  1599. szHeader = L"HTTP/1.1"; // Special!!!
  1600. break;
  1601. case HTTP_QUERY_STATUS_TEXT:
  1602. szHeader = L"HTTP/1.1"; // Special!!!
  1603. break;
  1604. case HTTP_QUERY_TITLE:
  1605. szHeader = L"Title:";
  1606. break;
  1607. case HTTP_QUERY_TRANSFER_ENCODING:
  1608. szHeader = L"Transfer-Encoding:";
  1609. break;
  1610. case HTTP_QUERY_UNLESS_MODIFIED_SINCE:
  1611. szHeader = L"Unless-Modified-Since:";
  1612. break;
  1613. case HTTP_QUERY_UPGRADE:
  1614. szHeader = L"Upgrade:";
  1615. break;
  1616. case HTTP_QUERY_URI:
  1617. szHeader = L"Uri:";
  1618. break;
  1619. case HTTP_QUERY_USER_AGENT:
  1620. szHeader = L"User-Agent:";
  1621. break;
  1622. case HTTP_QUERY_VARY:
  1623. szHeader = L"Vary:";
  1624. break;
  1625. case HTTP_QUERY_VERSION:
  1626. szHeader = L"Version:";
  1627. break;
  1628. case HTTP_QUERY_VIA:
  1629. szHeader = L"Via:";
  1630. break;
  1631. case HTTP_QUERY_WARNING:
  1632. szHeader = L"Warning:";
  1633. break;
  1634. case HTTP_QUERY_WWW_AUTHENTICATE:
  1635. szHeader = L"WWW-Authenticate:";
  1636. break;
  1637. default:
  1638. goto exit;
  1639. }
  1640. if (dwOption & HTTP_QUERY_FLAG_SYSTEMTIME)
  1641. {
  1642. if (*pcbBuf < sizeof(SYSTEMTIME) || pBuffer == NULL)
  1643. {
  1644. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1645. goto exit;
  1646. }
  1647. else
  1648. {
  1649. LPSYSTEMTIME pSys = (LPSYSTEMTIME) pBuffer;
  1650. GetSystemTime(pSys);
  1651. *pcbBuf = sizeof(SYSTEMTIME);
  1652. goto exit;
  1653. }
  1654. }
  1655. if ((dwOption & HTTP_QUERY_FLAG_REQUEST_HEADERS) == 0)
  1656. hr = DealWithBuffer(m_strResponseHeader, szHeader, dwOpt, dwOption, pBuffer, pcbBuf);
  1657. if (hr == E_FAIL)
  1658. hr = DealWithBuffer(m_extraHeaders, szHeader, dwOpt, dwOption, pBuffer, pcbBuf);
  1659. exit:
  1660. return hr;
  1661. }
  1662. /////////////////////////////////////////////////////////////////////////////
  1663. /////////////////////////////////////////////////////////////////////////////
  1664. /////////////////////////////////////////////////////////////////////////////
  1665. HRESULT
  1666. AppProtocol::DealWithBuffer(
  1667. LPWSTR szHeaders,
  1668. LPCWSTR szHeader,
  1669. DWORD dwOpt,
  1670. DWORD dwOption,
  1671. LPVOID pBuffer,
  1672. LPDWORD pcbBuf)
  1673. {
  1674. LPCWSTR szValue = wcsstr(szHeaders, (LPWSTR) szHeader);
  1675. if (szValue == NULL)
  1676. return E_FAIL;
  1677. DWORD dwStart = wcslen(szHeader);
  1678. while(iswspace(szValue[dwStart]) && szValue[dwStart] != L'\r')
  1679. dwStart++;
  1680. DWORD dwEnd = dwStart;
  1681. switch(dwOpt)
  1682. {
  1683. case HTTP_QUERY_STATUS_CODE:
  1684. dwEnd = dwStart + 3;
  1685. break;
  1686. case HTTP_QUERY_STATUS_TEXT:
  1687. dwStart += 4;// Fall thru to default
  1688. dwEnd = dwStart;
  1689. default:
  1690. while(szValue[dwEnd] != NULL && szValue[dwEnd] != L'\r')
  1691. dwEnd++;
  1692. dwEnd--;
  1693. }
  1694. DWORD dwReq = (dwEnd - dwStart + 1);
  1695. if ((dwOption & HTTP_QUERY_FLAG_NUMBER) && *pcbBuf < 4)
  1696. {
  1697. *pcbBuf = 4;
  1698. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1699. }
  1700. if ((dwOption & HTTP_QUERY_FLAG_NUMBER) == 0 && *pcbBuf < dwReq)
  1701. {
  1702. *pcbBuf = dwReq;
  1703. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1704. }
  1705. if (dwOption & HTTP_QUERY_FLAG_NUMBER)
  1706. {
  1707. LPDWORD lpD = (LPDWORD) pBuffer;
  1708. *lpD = _wtoi(&szValue[dwStart]);
  1709. *pcbBuf = 4;
  1710. }
  1711. else
  1712. {
  1713. memcpy(pBuffer, &szValue[dwStart], dwReq*sizeof(WCHAR));
  1714. ((WCHAR *) pBuffer)[dwReq] = NULL;
  1715. }
  1716. return S_OK;
  1717. }
  1718. /////////////////////////////////////////////////////////////////////////////
  1719. /////////////////////////////////////////////////////////////////////////////
  1720. /////////////////////////////////////////////////////////////////////////////
  1721. HRESULT
  1722. AppProtocol::ProcessAppManifest()
  1723. {
  1724. HRESULT hr = S_OK;
  1725. char *szManifest;
  1726. HANDLE hFile;
  1727. BYTE buffer[1024];
  1728. DWORD dwLength;
  1729. APPINFO aiApplication;
  1730. aiApplication._wzNewRef[0] = L'\0';
  1731. aiApplication._wzEntryAssemblyFileName[0] = L'\0';
  1732. aiApplication._pFileList = NULL;
  1733. // step 1: read the .manifest
  1734. hFile = CreateFile(m_localStoreFilePath, GENERIC_READ, 0, NULL,
  1735. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1736. if(hFile == INVALID_HANDLE_VALUE)
  1737. {
  1738. hr = GetLastWin32Error();
  1739. goto exit;
  1740. }
  1741. ZeroMemory(buffer, sizeof(buffer));
  1742. while ( ReadFile (hFile, buffer, sizeof(buffer), &dwLength, NULL) && dwLength )
  1743. {
  1744. break; //BUGBUG: read once - only the 1st 1024 bytes
  1745. }
  1746. if (hFile != INVALID_HANDLE_VALUE)
  1747. CloseHandle(hFile);
  1748. *(buffer + dwLength) = '\0';
  1749. szManifest = (char*) buffer;
  1750. // step 2: parsing
  1751. ParseManifest(szManifest, &aiApplication);
  1752. // step 3: do "the works"
  1753. // should take the base Uri, base appRoot, + file name
  1754. //*** if (FAILED(hr = InstallInternetFile2(wzSourceUri, m_appRootTranslated, filename, hash)))
  1755. // goto exit;
  1756. exit:
  1757. return hr;
  1758. }
  1759. void
  1760. AppProtocol::ParseManifest(char* szManifest, APPINFO* pAppInfo)
  1761. {
  1762. char *token;
  1763. char seps[] = " </>=\"\t\n\r";
  1764. FILEINFOLIST* pCurrent = NULL;
  1765. // WCHAR wzDummyPath[MAX_PATH];
  1766. WCHAR wzSourceUri[MAX_PATH];
  1767. BOOL fSkipNextToken = FALSE;
  1768. // parsing code - limitation: does not work w/ space in field, even if enclosed w/ quotes
  1769. // szManifest will be modified!
  1770. token = strtok( szManifest, seps );
  1771. while( token != NULL )
  1772. {
  1773. // wzDummyPath[0] = L'\0';
  1774. // While there are tokens
  1775. if (!_stricmp(token, "file"))
  1776. {
  1777. // get around in spaced tag
  1778. token = strtok( NULL, seps );
  1779. if (!_stricmp(token, "name"))
  1780. {
  1781. token = strtok( NULL, seps );
  1782. /* lstrcpy(wzSourceUri, m_fullUri);
  1783. WCHAR* p = wcsrchr(wzSourceUri, L'/');
  1784. WCHAR* q = wcsrchr(wzSourceUri, L'.');
  1785. if (p && q && (p < q))
  1786. *p = L'\0';
  1787. else
  1788. {
  1789. hr = E_INVALIDARG;
  1790. goto exit;
  1791. }
  1792. _snwprintf(wzSourceUri, MAX_PATH, L"%s/%S", wzSourceUri, token);*/
  1793. // init
  1794. if (pCurrent == NULL)
  1795. {
  1796. pAppInfo->_pFileList = new FILEINFOLIST;
  1797. pCurrent = pAppInfo->_pFileList;
  1798. }
  1799. else
  1800. {
  1801. pCurrent->_pNext = new FILEINFOLIST;
  1802. pCurrent = pCurrent->_pNext;
  1803. }
  1804. pCurrent->_pNext = NULL;
  1805. _snwprintf(pCurrent->_wzFilename, MAX_PATH, L"%S", token); // worry about total path len later
  1806. //no need m_pProtocolSink->ReportProgress(BINDSTATUS_BEGINDOWNLOADCOMPONENTS, L"downloading application files");
  1807. token = strtok( NULL, seps );
  1808. if (!_stricmp(token, "hash"))
  1809. {
  1810. _snwprintf(pCurrent->_wzHash, 33, L"%S", token);
  1811. // ???? should i reuse the file handle instead?
  1812. //* if (IsFileCorrupted(m_localStoreFilePath, token)) Integrity
  1813. //* ...
  1814. }
  1815. else
  1816. fSkipNextToken = TRUE;
  1817. }
  1818. }
  1819. else if (!_stricmp(token, "newhref"))
  1820. {
  1821. // note, different handling... because '/' is one of seps
  1822. for (int i = 0; i < MAX_URL_LENGTH; i++)
  1823. {
  1824. if (*(token+8+i) == '<')
  1825. {
  1826. // BUGBUG: 8 == strlen("newhref>")
  1827. *(token+8+i) = '\0';
  1828. _snwprintf(pAppInfo->_wzNewRef, i, L"%S", token+8);
  1829. // BUGBUG? is this going to work?
  1830. token = strtok( token+i+9, seps);
  1831. // now token == "newhref" && *(token-1) == '/'
  1832. }
  1833. }
  1834. // BUGBUG: ignoring > MAX_URL_LENGTH case here... may mess up later if the URL contain a "keyword"
  1835. // <newhref></newhref> may be ok...
  1836. }
  1837. //else
  1838. // ignore others for now
  1839. // Get next token...
  1840. if(!fSkipNextToken)
  1841. token = strtok( NULL, seps );
  1842. else
  1843. fSkipNextToken = FALSE;
  1844. }
  1845. }