|
|
/**
* Asynchronous pluggable protocol for Applications * * Copyright (C) Microsoft Corporation, 2000 */
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "app.h"
#include <stdio.h> // for _snprintf
char * stristr(char *pszMain, char *pszSub) { char * pszCur = pszMain; char ch = (char) tolower(*pszSub); int cb = strlen(pszSub) - 1; // -1 to ignore leading character
for (;;) { while (tolower(*pszCur) != ch && *pszCur) pszCur++;
if (!*pszCur) return NULL;
if (_strnicmp(pszCur + 1, pszSub + 1, cb) == 0) return pszCur;
pszCur++; } }
/**
* Return last Win32 error as an HRESULT. */ HRESULT GetLastWin32Error() { // Win 95 can return 0, even when there's an error.
DWORD dw = GetLastError(); return dw ? HRESULT_FROM_WIN32(dw) : E_FAIL; }
HRESULT RunCommand(WCHAR *cmdLine) { HRESULT hr = S_OK; STARTUPINFO si; PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si); if(!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { hr = GetLastWin32Error(); goto exit; }
if(WaitForSingleObject(pi.hProcess, 180000L) == WAIT_TIMEOUT) { hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); goto exit; }
exit: if(pi.hProcess) CloseHandle(pi.hProcess); if(pi.hThread) CloseHandle(pi.hThread);
return hr; }
#define ToHex(val) val <= 9 ? val + '0': val - 10 + 'A'
DWORD ConvertToHex(WCHAR* strForm, BYTE* byteForm, DWORD dwSize) { DWORD i = 0; DWORD j = 0; for(i = 0; i < dwSize; i++) { strForm[j++] = ToHex((0xf & byteForm[i])); strForm[j++] = ToHex((0xf & (byteForm[i] >> 4))); } strForm[j] = L'\0'; return j; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// {B8BF3C7E-4DB6-4fdb-9CD3-13D2CE728CA8}, by guidgen VS7
CLSID CLSID_AppProtocol = { 0xb8bf3c7e, 0x4db6, 0x4fdb, { 0x9c, 0xd3, 0x13, 0xd2, 0xce, 0x72, 0x8c, 0xa8 } };
BOOL g_fStarted = FALSE; AppProtocolFactory g_AppProtocolFactory; IInternetSecurityManager* g_pSecurityMgr = NULL;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Class AppProtocol ctor
AppProtocol::AppProtocol(IUnknown * pUnkOuter) : m_refs (1), m_pProtocolSink (NULL), // m_cookie (NULL),
m_fullUri (NULL), m_uriPath (NULL), m_queryString (NULL), m_appOrigin (NULL), m_appRoot (NULL), m_appRootTranslated (NULL), m_extraHeaders (NULL), m_inputDataSize (0), m_inputData (NULL), m_pInputRead (NULL), m_pOutputRead (NULL), m_pOutputWrite (NULL), m_started (FALSE), m_aborted (FALSE), m_done (FALSE), m_responseMimeType (NULL), m_cbOutput (0), m_extraHeadersUpr (NULL), m_strResponseHeader (NULL), m_postedMimeType (NULL), m_verb (NULL), m_localStoreFilePath (NULL), m_appType (APPTYPE_IE), m_status (STATUS_CLEAR) { m_pUnkOuter = (pUnkOuter ? pUnkOuter : (IUnknown *)(IPrivateUnknown *)this); InitializeCriticalSection(&m_csOutputWriter); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void AppProtocol::Cleanup() { ClearInterface(&m_pOutputRead); ClearInterface(&m_pOutputWrite); ClearInterface(&m_pProtocolSink); ClearInterface(&m_pInputRead);
m_appType = APPTYPE_IE; m_status = STATUS_CLEAR; m_done = TRUE; m_aborted = FALSE; //???
if (m_bindinfo.cbSize) { ReleaseBindInfo(&m_bindinfo); ZeroMemory(&m_bindinfo, sizeof(m_bindinfo)); } }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void AppProtocol::FreeStrings() { MemClearFn((void **)&m_fullUri); m_uriPath = NULL; m_queryString = NULL;
MemClearFn((void **)&m_appOrigin) ; m_appRoot = NULL;
MemClearFn((void **)&m_appRootTranslated);
if(m_extraHeaders) { CoTaskMemFree(m_extraHeaders); m_extraHeaders = NULL; }
// MemClearFn((void **)&m_cookie);
MemClearFn((void **)&m_extraHeadersUpr); MemClearFn((void **)&m_strResponseHeader); MemClearFn((void **)&m_verb); MemClearFn((void **)&m_postedMimeType); MemClearFn((void **)&m_responseMimeType); MemClearFn((void **)&m_localStoreFilePath); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
AppProtocol::~AppProtocol() { FreeStrings();
Cleanup();
DeleteCriticalSection(&m_csOutputWriter);
if (g_pSecurityMgr != NULL) { g_pSecurityMgr->Release(); g_pSecurityMgr = NULL; } }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Private QI
ULONG AppProtocol::PrivateAddRef() { return ++m_refs; }
ULONG AppProtocol::PrivateRelease() { if (--m_refs > 0) return m_refs;
delete this; return 0; }
HRESULT AppProtocol::PrivateQueryInterface( REFIID iid, void** ppv) { *ppv = NULL;
if (iid == IID_IInternetProtocol || iid == IID_IInternetProtocolRoot) { *ppv = (IInternetProtocol *)this; } else if (iid == IID_IUnknown) { *ppv = (IUnknown *)(IPrivateUnknown *)this; } else if (iid == IID_IWinInetHttpInfo) { *ppv = (IWinInetHttpInfo *)this; } else { return E_NOINTERFACE; }
((IUnknown *)*ppv)->AddRef(); return S_OK; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Public (delegated) QI
ULONG AppProtocol::AddRef() { m_pUnkOuter->AddRef(); return PrivateAddRef(); }
ULONG AppProtocol::Release() { m_pUnkOuter->Release(); return PrivateRelease(); }
HRESULT AppProtocol::QueryInterface( REFIID iid, void ** ppv) { return m_pUnkOuter->QueryInterface(iid, ppv); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Start( LPCWSTR url, IInternetProtocolSink * pProtocolSink, IInternetBindInfo * pBindInfo, DWORD grfSTI, DWORD ) { HRESULT hr = S_OK; WCHAR * Strings[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DWORD cStrings = sizeof(Strings) / sizeof(Strings[0]); // DWORD cookieSize = 0;
IServiceProvider * pServiceProvider = NULL; IHttpNegotiate * pHttpNegotiate = NULL;
FreeStrings();
ReplaceInterface(&m_pProtocolSink, pProtocolSink);
// ?????
if (grfSTI & PI_PARSE_URL) goto exit;
if (pProtocolSink == NULL) { hr = E_INVALIDARG; goto exit; }
// get bindinfo
m_bindinfo.cbSize = sizeof(BINDINFO); if (pBindInfo != NULL) { if (FAILED(hr = pBindInfo->GetBindInfo(&m_bindf, &m_bindinfo))) goto exit; }
if (m_bindinfo.dwCodePage == 0) m_bindinfo.dwCodePage = CP_ACP;
// extract root, uri path and query string from url
if (FAILED(hr = ParseUrl(url))) goto exit;
// get to headers in MSHtml
if (FAILED(hr = pBindInfo->QueryInterface(IID_IServiceProvider, (void **) &pServiceProvider))) goto exit; if(pServiceProvider != NULL) { if (FAILED(hr = pServiceProvider->QueryService(IID_IHttpNegotiate, IID_IHttpNegotiate, (void **) &pHttpNegotiate))) goto exit; if(pHttpNegotiate != NULL) { hr = pHttpNegotiate->BeginningTransaction(url, NULL, 0, &m_extraHeaders); pHttpNegotiate->Release(); pHttpNegotiate = NULL; if (FAILED(hr)) goto exit; } pServiceProvider->Release(); pServiceProvider = NULL; }
// determine verb
switch (m_bindinfo.dwBindVerb) { case BINDVERB_GET: m_verb = DuplicateString(L"GET"); break;
case BINDVERB_POST: m_verb = DuplicateString(L"POST"); break;
case BINDVERB_PUT: m_verb = DuplicateString(L"PUT"); break;
default: if (m_bindinfo.szCustomVerb != NULL && m_bindinfo.dwBindVerb == BINDVERB_CUSTOM) { m_verb = DuplicateString(m_bindinfo.szCustomVerb); } else { m_verb = DuplicateString(L"GET"); } break; }
// get mime type of posted data from binding
hr = pBindInfo->GetBindString(BINDSTRING_POST_DATA_MIME, Strings, cStrings, &cStrings); if(hr == S_OK && cStrings) { DWORD i;
m_postedMimeType = DuplicateString(Strings[0]); if (m_postedMimeType == NULL) { hr = E_OUTOFMEMORY; goto exit; }
for(i = 0; i < cStrings; i++) CoTaskMemFree(Strings[i]); }
// don't fail if we failed to get bind string,
hr = S_OK;
// retrieve cookie
/* cookieSize = 0;
if(g_pInternetGetCookieW(m_fullUri, NULL, NULL, &cookieSize) && cookieSize) { m_cookie = (WCHAR *)MemAlloc(cookieSize + sizeof(WCHAR)); if (m_cookie == NULL) { hr = E_OUTOFMEMORY; goto exit; }
g_pInternetGetCookieW(m_fullUri, NULL, m_cookie, &cookieSize); } */
// Input data
if (m_bindinfo.stgmedData.tymed == TYMED_HGLOBAL) { m_inputDataSize = m_bindinfo.cbstgmedData; m_inputData = (BYTE *)m_bindinfo.stgmedData.hGlobal; } else if (m_bindinfo.stgmedData.tymed == TYMED_ISTREAM) { STATSTG statstg;
ReplaceInterface(&m_pInputRead, m_bindinfo.stgmedData.pstm);
if(m_pInputRead) { hr = m_pInputRead->Stat(&statstg, STATFLAG_NONAME); if(hr == S_OK) m_inputDataSize = statstg.cbSize.LowPart; else m_inputDataSize = (DWORD)-1; }
}
if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pOutputWrite))) goto exit;
if (FAILED(hr = m_pOutputWrite->Clone(&m_pOutputRead))) goto exit;
PROTOCOLDATA protData; protData.dwState = 1; protData.grfFlags = PI_FORCE_ASYNC; protData.pData = NULL; protData.cbData = 0;
pProtocolSink->Switch(&protData); //*** hr = E_PENDING;
exit: if (pHttpNegotiate) { pHttpNegotiate->Release(); pHttpNegotiate = NULL; }
if (pServiceProvider) { pServiceProvider->Release(); pServiceProvider = NULL; }
return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Continue( PROTOCOLDATA * pProtData) { HRESULT hr = S_OK; // CHAR appDomainPath[MAX_PATH] = "";
WCHAR appRootTranslated[MAX_PATH];
if(pProtData->dwState != 1) { hr = E_FAIL; goto exit; }
// step 1: "install" the specified file
appRootTranslated[0] = L'\0';
hr = SetupAndInstall(m_fullUri, appRootTranslated); if (FAILED(hr)) goto exit;
if (m_localStoreFilePath == NULL) { hr = E_FAIL; goto exit; }
m_appRootTranslated = DuplicateString(appRootTranslated); if (m_appRootTranslated == NULL) { hr = E_OUTOFMEMORY; goto exit; } // step 2: check error status
if ((m_status & STATUS_OFFLINE_MODE) && (m_status & STATUS_NOT_IN_CACHE)) { char buffer[100 + MAX_PATH]; SendHeaders(HTTP_RESPONSEOK);
_snprintf(buffer, 100+MAX_PATH, "Error: In offline mode and file not found in application store.\r\nLocal path expected- %ws", m_localStoreFilePath); WriteBytes((BYTE*) buffer, lstrlenA(buffer)+1); hr = Finish();
goto exit; }
// step 3: process different file types
if (m_appType == APPTYPE_BYMANIFEST) { char buffer[512 + MAX_PATH];
SendHeaders(HTTP_RESPONSEOK);
// ???? ignore if excess buffer len
// do this before as m_localStoreFilePath might be overwritten
_snprintf(buffer, 512 + MAX_PATH, "Application installed and executed with manifest file - %ws\r\nSource - %ws", m_localStoreFilePath, m_fullUri);
if (FAILED(hr = ProcessAppManifest())) goto exit;
WriteBytes((BYTE *) buffer, lstrlenA(buffer)+1); //???? includes last '\0'
hr = Finish(); } else if (m_appType == APPTYPE_ASM) { char buffer[512 + MAX_PATH]; SendHeaders(HTTP_RESPONSEOK);
// ???? ignore if excess buffer len
_snprintf(buffer, 512+MAX_PATH, "Assembly Executed - %ws\r\nSource - %ws", m_localStoreFilePath, m_fullUri);
WriteBytes((BYTE*) buffer, lstrlenA(buffer)+1); //???? includes last '\0'
hr = Finish(); } else if (m_appType == APPTYPE_IE) { DWORD dwLength; BYTE buffer[512]; char header[60]; HANDLE hFile; int len; WCHAR* p;
// set mime type
// assume lower cases
len = lstrlen(m_localStoreFilePath); p = m_localStoreFilePath + len - 5; if ((p[1] == L'.' && p[2] == L'h' && p[3] == L't' && p[4] == L'm') || (p[0] == L'.' && p[1] == L'h' && p[2] == L't' && p[3] == L'm' && p[4] == L'l')) //L".htm" ".html"
sprintf(header, "%s\r\nContent-Type: text/html\r\n", HTTP_RESPONSEOK); else if (p[1] == L'.' && p[2] == L'g' && p[3] == L'i' && p[4] == L'f') //L".gif"
sprintf(header, "%s\r\nContent-Type: image/gif\r\n", HTTP_RESPONSEOK); else if ((p[1] == L'.' && p[2] == L'j' && p[3] == L'p' && p[4] == L'g') || (p[0] == L'.' && p[1] == L'j' && p[2] == L'p' && p[3] == L'e' && p[4] == L'g')) //L".jpg" ".jpeg"
sprintf(header, "%s\r\nContent-Type: image/jpeg\r\n", HTTP_RESPONSEOK); else sprintf(header, "%s", HTTP_RESPONSEOK);
SendHeaders(header);
hFile = CreateFile(m_localStoreFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastWin32Error(); goto exit; }
ZeroMemory(buffer, sizeof(buffer));
while ( ReadFile (hFile, buffer, 512, &dwLength, NULL) && dwLength ) { WriteBytes(buffer, dwLength); } if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
hr = Finish(); }
exit: return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Finish() { HRESULT hr = S_OK;
if (m_done == FALSE) { m_done = TRUE;
m_pProtocolSink->ReportData(BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 0, m_cbOutput);
if (m_aborted == FALSE) m_pProtocolSink->ReportResult(S_OK, 0, NULL); } return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Abort( HRESULT hrReason, DWORD ) { HRESULT hr = S_OK;
m_aborted = TRUE; if (m_pProtocolSink != NULL) { hr = m_pProtocolSink->ReportResult(hrReason, 0, 0); if (FAILED(hr)) goto exit; }
exit: return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Terminate( DWORD ) { Cleanup(); return S_OK; }
HRESULT AppProtocol::Suspend() { return E_NOTIMPL; }
HRESULT AppProtocol::Resume() { return E_NOTIMPL; }
HRESULT AppProtocol::Read( void *pv, ULONG cb, ULONG *pcbRead) { HRESULT hr;
hr = m_pOutputRead->Read(pv, cb, pcbRead);
// We must only return S_FALSE when we have hit the absolute end of the stream
// If we think there is more data coming down the wire, then we return E_PENDING
// here. Even if we return S_OK and no data, UrlMON will still think we've hit
// the end of the stream.
// if (S_OK == hr && 0 == *pcbRead)
//****
if (S_OK == hr && (0 == *pcbRead || cb > *pcbRead)) { hr = m_done ? S_FALSE : E_PENDING; }
return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::Seek( LARGE_INTEGER offset, DWORD origin, ULARGE_INTEGER *pPos) { return m_pOutputRead->Seek(offset, origin, pPos); }
HRESULT AppProtocol::LockRequest( DWORD ) { return S_OK; }
HRESULT AppProtocol::UnlockRequest() { return S_OK; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::SendHeaders( LPSTR headers) { HRESULT hr = S_OK; // DWORD flags = 0;
DWORD dwLength = 0; LPSTR mime = NULL; LPSTR tail = NULL; int iHLen = 0;
if(headers == NULL) { hr = E_UNEXPECTED; goto exit; }
if (m_strResponseHeader != NULL) MemFree(m_strResponseHeader); iHLen = strlen(headers); m_strResponseHeader = (WCHAR *) MemAllocClear(iHLen*sizeof(WCHAR) + 512); if (m_strResponseHeader != NULL) { wcscpy(m_strResponseHeader, L"Server: Microsoft.Net-App/1.0\r\nDate:"); // Microsoft-IIS/App 1.0
WCHAR szTemp[100]; szTemp[0] = NULL; GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, NULL, NULL, szTemp, 100); wcscat(m_strResponseHeader, szTemp); wcscat(m_strResponseHeader, L" ");
GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, szTemp, 100); wcscat(m_strResponseHeader, szTemp); wcscat(m_strResponseHeader, L"\r\n"); int iLen = wcslen(m_strResponseHeader); MultiByteToWideChar(CP_ACP, 0, headers, -1, &m_strResponseHeader[iLen], iHLen + 256 - iLen - 1); }
mime = stristr(headers, "Content-Type:"); if(mime) { mime += 13; while(*mime && isspace(*mime)) mime++; tail = mime;
while(*tail && *tail != '\r') tail++;
dwLength = tail - mime; if(dwLength) { if (m_responseMimeType) MemFree(m_responseMimeType);
m_responseMimeType = (WCHAR *) MemAlloc((dwLength + 1) * sizeof(WCHAR)); if (m_responseMimeType == NULL) { hr = E_OUTOFMEMORY; goto exit; }
MultiByteToWideChar(CP_ACP, 0, mime, dwLength, m_responseMimeType, dwLength); m_responseMimeType[dwLength] = L'\0'; } }
if (m_responseMimeType && *m_responseMimeType) m_pProtocolSink->ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, m_responseMimeType); else m_pProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"text/plain"); //proper default not L"text/html");
//**** SaveCookie(headers);
exit: return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/*HRESULT
AppProtocol::SaveCookie( LPSTR header) { HRESULT hr = S_OK; LPSTR cookie, tail; WCHAR *cookieBody = NULL; int bodyLength;
for(cookie = stristr(header, "Set-Cookie:"); cookie != NULL; cookie = (*tail ? stristr(tail, "Set-Cookie:") : NULL)) //???? added () around ? :
{ cookie += 11; while(*cookie && isspace(*cookie)) cookie++; tail = cookie; while(*tail && *tail != '\r') tail++; bodyLength = tail - cookie;
if(bodyLength) { cookieBody = (WCHAR *)MemAlloc(sizeof(WCHAR) *(bodyLength + 1)); if (cookieBody == NULL) { hr = E_OUTOFMEMORY; goto exit; } MultiByteToWideChar(CP_ACP, 0, cookie, bodyLength, cookieBody, bodyLength); cookieBody[bodyLength] = '\0';
if(!g_pInternetSetCookieW(m_cookiePath, NULL, cookieBody)) { hr = GetLastWin32Error(); goto exit; } } } exit: if (cookieBody) MemFree(cookieBody);
return hr; }*/
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::WriteBytes( BYTE * buffer, DWORD dwLength) { HRESULT hr = S_OK; DWORD flags = 0;
EnterCriticalSection(&m_csOutputWriter);
if (!m_pOutputWrite) { hr = E_UNEXPECTED; }
if (FAILED(hr = m_pOutputWrite->Write(buffer, dwLength, &dwLength))) goto exit;
m_cbOutput += dwLength;
if (!m_started) { m_started = TRUE; flags |= BSCF_FIRSTDATANOTIFICATION; } else //****
if (m_done) { flags |= BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE; }
else //****
flags |= BSCF_INTERMEDIATEDATANOTIFICATION;
if (FAILED(hr = m_pProtocolSink->ReportData(flags, dwLength, m_cbOutput))) goto exit;
exit: LeaveCriticalSection(&m_csOutputWriter); return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/*int
AppProtocol::GetKnownRequestHeader ( LPCWSTR szHeader, LPWSTR buf, int size) { if (szHeader == NULL || szHeader[0] == NULL || wcslen(szHeader) > 256) return 0;
LPCWSTR szReturn = NULL; LPCWSTR szStart = NULL; int iLen = 0; HRESULT hr = S_OK; // int iter = 0;
WCHAR szHeadUpr[260] = L"";
wcscpy(szHeadUpr, szHeader); _wcsupr(szHeadUpr);
if (wcscmp(szHeadUpr, SZ_HTTP_COOKIE) == 0) { szReturn = m_cookie; iLen = (m_cookie ? wcslen(m_cookie) : 0); goto exit; }
if (m_extraHeadersUpr == NULL && m_extraHeaders != NULL) { m_extraHeadersUpr = DuplicateString(m_extraHeaders); if (m_extraHeadersUpr == NULL) { hr = E_OUTOFMEMORY; goto exit; }
_wcsupr(m_extraHeadersUpr); }
if (m_extraHeadersUpr == NULL) goto exit; szStart = wcsstr(m_extraHeadersUpr, szHeadUpr); if (szStart == NULL) goto exit;
iLen = wcslen(szHeadUpr); szReturn = &(m_extraHeaders[iLen+1]);
while(iswspace(*szReturn)) szReturn++;
for (iLen = 0; szReturn[iLen] != L'\r' && szReturn[iLen] != NULL; iLen++);
exit: if (szReturn == NULL || iLen == 0) return 0;
if (iLen >= size) return -(iLen + 1);
buf[iLen] = NULL; memcpy(buf, szReturn, iLen*sizeof(WCHAR)); return iLen; } */ /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// TODO: make it real, netclasses, manifest and all that
//
// ???? construct filename, create directory
HRESULT AppProtocol::SetupAndInstall( LPTSTR url, /* *not* ok to modify */ LPTSTR path /* out */) { HRESULT hr = S_OK; // WCHAR *installFromPath = NULL; // full path - app://www.microsoft.com/app5/app.manifest
WCHAR *origin = NULL; // src - www.microsoft.com/app5
WCHAR *p, *q; int i, j;
// skip app:// part
origin = DuplicateString(url + lstrlen(PROTOCOL_SCHEME)); if (origin == NULL) { hr = E_OUTOFMEMORY; goto exit; }
// installFromPath = (WCHAR *) MemAlloc((lstrlen(origin/*url*/) + lstrlen(HTTP_SCHEME)/*MAX_PATH*/) * sizeof(WCHAR));
// if (installFromPath == NULL)
// {
// hr = E_OUTOFMEMORY;
// goto exit;
// }
//???????????????????????
WCHAR installFromPath[MAX_URL_LENGTH];
lstrcpy(installFromPath, HTTP_SCHEME); lstrcat(installFromPath, origin); // assume file name is given (it's now passed in) - not myweb.cab
// better? - check if last contain ".", if so assume has filename, else attach app.manifest as filename
// lstrcat(installFromPath, L"/MyWeb.cab"); //????????? if no filename it will get index.html, if exists!
// remove the filename, if specified
// ?????????? this assume all filename has a '.'
p = wcsrchr(origin, L'/'); q = wcsrchr(origin, L'.'); if (p && q && /*((p - origin) > 6) &&*/ (p < q)) *p = L'\0'; // else - no filename -> do something to installFromPath? or no '/' after "app://" in url
else { hr = E_INVALIDARG; goto exit; }
// install to
if(GetEnvironmentVariable(L"ProgramFiles", path, MAX_PATH-lstrlen(STORE_PATH)-1) == 0) //????????
{ //
hr = CO_E_PATHTOOLONG;//E_FAIL;
goto exit; }
// ????????
lstrcat(path, STORE_PATH); if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { hr = GetLastWin32Error(); goto exit; } lstrcat(path, L"\\");
i = lstrlen(path); j = 0; while(origin[j]) { if(origin[j] == L'/') { path[i] = L'\0'; if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { hr = GetLastWin32Error(); goto exit; }
path[i] = L'\\'; } else path[i] = origin[j]; i++; j++; } path[i] = L'\0'; if(!CreateDirectory(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { hr = GetLastWin32Error(); goto exit; }
// grab the files
hr = InstallInternetFile(installFromPath, path);
exit: // if(installFromPath) MemFree(installFromPath);
if(origin) MemFree(origin);
return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// given the url like MyWeb://www.site.com/app/something/else?querystring=aa
// sets
// m_uriPath to /app/something/else
// m_queryString to querystring=aa
// m_appRoot to /app or
// /app/something or
// /app/something/else,
// depending on which was successfully mapped to
// m_appRootTranslated to, for instance, c:\program files\site app\ // not set till SetupAndInstall() is called
// m_appOrigin to www.site.com
// m_fullUri to myweb://www.site.com/app/something/else
//
// if application was not installed, attempts to install it
//
// ???? setup strings, find out if needs install
HRESULT AppProtocol::ParseUrl(LPCTSTR url) { HRESULT hr = S_OK; WCHAR slash = L'/'; WCHAR *p, *base; int cchFullUri = 0; // WCHAR appRootTranslated[MAX_PATH];
// copy the cookie path into member variable
m_fullUri = DuplicateString(url); if (m_fullUri == NULL) { hr = E_OUTOFMEMORY; goto exit; }
// locate, store and strip query string, if any
p = wcschr(m_fullUri, L'?'); if(p != NULL && p[1] != L'\0') { m_queryString = p + 1; *p = L'\0'; }
// ????? to be moved
// assume lower cases
// need to find from end, skip ?querystring, use m_fullUri instead?
cchFullUri = lstrlen(m_fullUri); m_appType = APPTYPE_IE;
// ????? BUGBUG assume >= than 9 characters
if (cchFullUri >= 9) { p = m_fullUri + cchFullUri - 5; /* if (p[0] != L'.' && p[1] != L'.')
// error? no extension
m_appType = APPTYPE_IE; else*/ if (p[1] == L'.' && (p[2] == L'e' && p[3] == L'x' && p[4] == L'e') || (p[2] == L'd' && p[3] == L'l' && p[4] == L'l')) //L".exe" ".dll"
m_appType = APPTYPE_ASM; // (check asm or not?)
else if (p[0] == L'.' && p[1] == L'a' && p[2] == L's' && p[3] == L'p' && p[4] == L'x') //L".aspx"
m_appType = APPTYPE_MYWEB; else if (wcsncmp(p = m_fullUri + cchFullUri - 9, L".manifest", 9) == 0) m_appType = APPTYPE_BYMANIFEST; //else //default or others
// m_appType = APPTYPE_IE;
}
// skip through protocol://
p = wcschr(m_fullUri, L':'); if(p == NULL || p[1] != slash || p[2] != slash || p[3] == L'\0') { hr = E_INVALIDARG; }
// copy full origin path
m_appOrigin = DuplicateString(p + 3); if (m_appOrigin == NULL) { hr = E_OUTOFMEMORY; goto exit; }
// point to the end of site
base = wcschr(m_appOrigin, slash); if(base == NULL) { hr = E_INVALIDARG; goto exit; }
// appRootTranslated[0] = L'\0';
// tear off one segment at a time from the end
while((p = wcsrchr(m_appOrigin, slash)) != base) { *p = L'\0'; // if(GetAppBaseDir(m_appOrigin, appRootTranslated) == S_OK)
// {
// break;
// }
}
// moved to Continue()
// if(appRootTranslated[0] == L'\0')
// {
// WCHAR * appPath = DuplicateString(m_fullUri);
// WCHAR * p;
// application not installed, install it
/* if (appPath == NULL)
{ hr = E_OUTOFMEMORY; goto exit; } */ // ???? why? - this will remove the last - supposingly the filename?
// p = wcsrchr(appPath, L'/');
// if(p) *p = NULL;
// hr = SetupAndInstall(m_fullUri/*appPath*/, appRootTranslated);
// if (FAILED(hr))
// goto exit;
// if(appPath) MemFree(appPath);
// }
/* m_appRootTranslated = DuplicateString(appRootTranslated);
if (m_appRootTranslated == NULL) { hr = E_OUTOFMEMORY; goto exit; } */ m_appRoot = wcschr(m_appOrigin, slash);
// ???? this should be ok
/* if(m_appRoot == NULL)
{ hr = E_INVALIDARG; goto exit; } */ if (m_appRoot) m_uriPath = wcsstr(m_fullUri, m_appRoot); else // ???? this should be ok
m_uriPath = NULL;
exit: return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Note: appRoot is assumed to have enough space (MAX_PATH)
//
/*HRESULT AppProtocol::GetAppBaseDir(LPCTSTR base, LPTSTR appRoot)
{ HKEY hKey = NULL; HRESULT hr = E_FAIL; HKEY hSubKey = NULL;
appRoot[0] = L'\0';
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, MYWEBS_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { hr = GetLastWin32Error(); goto exit; }
if(RegOpenKeyEx(hKey, base, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { DWORD dwType, cb = MAX_PATH * sizeof(WCHAR); if(RegQueryValueEx(hSubKey, MYWEBS_APPROOT, NULL, &dwType, (LPBYTE)appRoot, &cb) == ERROR_SUCCESS) { dwType = GetFileAttributes(appRoot); if (dwType == (DWORD) -1 || (dwType & FILE_ATTRIBUTE_DIRECTORY) == 0) appRoot[0] = NULL; else hr = S_OK; } RegCloseKey(hSubKey); }
RegCloseKey(hKey);
//exit:
return hr; }*/
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// ???????called only from managed code?
WCHAR * AppProtocol::MapString( int key) { /* switch(key)
{ case IEWR_URIPATH: return m_uriPath; case IEWR_QUERYSTRING: return m_queryString; case IEWR_VERB: return m_verb; case IEWR_APPPATH: return m_appRoot; case IEWR_APPPATHTRANSLATED: return m_appRootTranslated; default:*/ if (key) key=key; // ???????
return NULL; // }
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// ????????called only from managed code?
int AppProtocol::GetStringLength( int key) { WCHAR *targetString = MapString(key); return targetString ? lstrlen(targetString) + 1 : 0; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int AppProtocol::GetString( int key, WCHAR * buf, int size) { WCHAR *targetString = MapString(key); int len;
if(targetString == NULL) return 0;
len = lstrlen(targetString);
if(len >= size) return 0;
lstrcpy(buf, targetString);
return len + 1; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/*int
AppProtocol::MapPath( WCHAR * virtualPath, WCHAR * physicalPath, int length) { int requiredLength = lstrlen(m_appRootTranslated) + 2; int rootLength = lstrlen(m_appRoot); int i = 0;
if(virtualPath && virtualPath[0] != '\0') { requiredLength += lstrlen(virtualPath) - rootLength; }
if(requiredLength <= 0) return 0;
if(requiredLength > length) return - requiredLength;
while(m_appRootTranslated[i]) { physicalPath[i] = m_appRootTranslated[i]; i++; }
if(virtualPath && virtualPath[0] != L'\0') {
if(_memicmp(virtualPath, m_appRoot, sizeof(WCHAR) * rootLength)) return 0;
virtualPath += rootLength; if(*virtualPath && *virtualPath != L'/') physicalPath[i++] = L'\\';
while(*virtualPath) { if(*virtualPath == L'/') physicalPath[i++] = L'\\'; else physicalPath[i++] = *virtualPath; virtualPath++; } }
physicalPath[i] = L'\0';
return 1; } */ /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// ????? download file from url into path
HRESULT AppProtocol::InstallInternetFile( LPTSTR url, LPTSTR path) { HRESULT hr = S_OK; HINTERNET hInternet = NULL; HINTERNET hTransfer = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; WCHAR * file = NULL; DWORD bytesRead = 0; DWORD bytesWritten = 0; WCHAR szFile[MAX_PATH]; BYTE buffer[4096];
BOOL bNeedDownload = TRUE;
// CabHandlerInfo cabInfo;
// ????????? TO BE MOVED!
// check offline mode
DWORD dwState = 0; DWORD dwSize = sizeof(DWORD); BOOL bRemoveEmptyFile = FALSE;
if(g_pInternetQueryOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize)) { if(dwState & INTERNET_STATE_DISCONNECTED_BY_USER) m_status |= STATUS_OFFLINE_MODE; }
////////////////////////////////////////////////////////////
// Step 1: Construct the file name
// ???? this assumes there is a filename after the last '/'
ZeroMemory(szFile, sizeof(szFile)); wcsncpy(szFile, path, MAX_PATH - 2); lstrcat(szFile, L"\\"); file = wcsrchr(url, L'/');
if (file != NULL && wcslen(szFile) + wcslen(file) < MAX_PATH) wcscat(szFile, file + 1); else { hr = CO_E_PATHTOOLONG;//E_FAIL;
goto exit; }
MemClearFn((void **)&m_localStoreFilePath); m_localStoreFilePath = DuplicateString(szFile);
////////////////////////////////////////////////////////////
// Step 2: Create the file
// need write access, will open (and replace/overwrite) exiting file
// ??? FILE_SHARE_READ? but we might write to if outdated...
hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastWin32Error(); goto exit; }
// ????????? TO BE MOVED!
if (GetLastError() == ERROR_ALREADY_EXISTS) { FILETIME ftLastModified; #define FTTICKSPERDAY (60*60*24*(LONGLONG) 10000000) // == 864000000000
if (GetFileTime(hFile, NULL, NULL, &ftLastModified)) { SYSTEMTIME sSysT; FILETIME ft;
GetSystemTime(&sSysT); SystemTimeToFileTime(&sSysT, &ft);
ULARGE_INTEGER ulInt = * (ULARGE_INTEGER *) &ft; ulInt.QuadPart -= FTTICKSPERDAY * 3; // 3 days
ft = * (FILETIME *) &ulInt;
if (CompareFileTime(&ftLastModified, &ft) != -1) // reuse file, just execute it
bNeedDownload = FALSE; } } else m_status |= STATUS_NOT_IN_CACHE;
if ((m_status & STATUS_OFFLINE_MODE) && (m_status & STATUS_NOT_IN_CACHE)) { // hr = E_FAIL; // ???? file not found - if uncomment this line, generic IE error page will display instead
bRemoveEmptyFile = TRUE; goto exit; }
if (bNeedDownload && !(m_status & STATUS_OFFLINE_MODE)) { ////////////////////////////////////////////////////////////
// Step 3: Copy the files over the internet
hInternet = g_pInternetOpen(L"App", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if(hInternet == NULL) { hr = GetLastWin32Error(); bRemoveEmptyFile = TRUE; goto exit; }
// use own caching instead
hTransfer = g_pInternetOpenUrl(hInternet, url, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0); if(hTransfer == NULL) { hr = GetLastWin32Error(); bRemoveEmptyFile = TRUE; goto exit; }
// need to check if there's any error, eg. not found (404)...
// synchronous download
while(g_pInternetReadFile(hTransfer, buffer, sizeof(buffer), &bytesRead) && bytesRead != 0) { if ( !WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten != bytesRead ) { hr = GetLastWin32Error(); bRemoveEmptyFile = TRUE; goto exit; } } }
// ensure file/internet handles are closed before further processing is done
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); if (hInternet != NULL) g_pInternetCloseHandle(hInternet); if (hTransfer != NULL) g_pInternetCloseHandle(hTransfer); hInternet = NULL; hTransfer = NULL; hFile = INVALID_HANDLE_VALUE;
// ????????? TO BE MOVED!
// process - run all .exe
// lower case? end of string?
if (/*m_appType == APPTYPE_ASM)*/wcsstr(file, L".exe")) { //#define MAX_SIZE_SECURITY_ID 0x200
DWORD dwZone; DWORD dwSize = MAX_SIZE_SECURITY_ID; BYTE byUniqueID[MAX_SIZE_SECURITY_ID]; WCHAR wzUniqueID[MAX_SIZE_SECURITY_ID * 2 + 1]; WCHAR wzCmdLine[1025];
//IInternetSecurityManager::ProcessUrlAction
// lazy init
if (g_pSecurityMgr == NULL) { hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER, IID_IInternetSecurityManager, (void**)&g_pSecurityMgr);
//???? should this fails at all if security info/manager is undef?
if (FAILED(hr)) { g_pSecurityMgr = NULL; goto exit; } } // m_fullUri -> this should translate correctly in IInternetProtocolInfo->ParseUrl()
if (SUCCEEDED(hr = g_pSecurityMgr->MapUrlToZone(m_fullUri, &dwZone, 0))) { // check space in site? - assume checked in GetSecurityId
// should site be just www.abc.com or www.abc.com/app2/appmain.exe?
if (FAILED(hr) || FAILED(hr = g_pSecurityMgr->GetSecurityId(m_fullUri, byUniqueID, &dwSize, 0))) goto exit;
ConvertToHex(wzUniqueID, byUniqueID, dwSize); } else { goto exit; }
// ???? any space in url? start a new proc for that asm, not hang the browser
/* C:\\Documents and Settings\\felixybc.NTDEV\\Desktop\\work\\conexec\\Debug\\*/ if (_snwprintf(wzCmdLine, 1025, L"conexec.exe \"%s\" +3 %d %s %s", szFile, dwZone, wzUniqueID, url) < 0) { hr = CO_E_PATHTOOLONG; goto exit; } RunCommand(wzCmdLine); }
exit: if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); if (hInternet != NULL) g_pInternetCloseHandle(hInternet); if (hTransfer != NULL) g_pInternetCloseHandle(hTransfer); hInternet = NULL; hTransfer = NULL; hFile = INVALID_HANDLE_VALUE;
// remove the file so that it will not be mistaken next time this runs
// ignore if error deleting the file so the hr is not overwritten
if (bRemoveEmptyFile) DeleteFile(szFile);
return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::QueryOption(DWORD, LPVOID, DWORD*) { return E_NOTIMPL; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::QueryInfo( DWORD dwOption, LPVOID pBuffer, LPDWORD pcbBuf, LPDWORD , LPDWORD ) { if (pcbBuf == NULL) return E_FAIL; HRESULT hr = S_OK; LPCWSTR szHeader = NULL; DWORD dwOpt = (dwOption & HTTP_QUERY_HEADER_MASK); DWORD dwLen = (m_strResponseHeader ? wcslen(m_strResponseHeader) : 0);
switch(dwOpt) { case HTTP_QUERY_RAW_HEADERS_CRLF: case HTTP_QUERY_RAW_HEADERS: if (m_strResponseHeader == NULL) return E_FAIL;
if (*pcbBuf < dwLen + 1) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } else { if (dwOpt == HTTP_QUERY_RAW_HEADERS_CRLF) { wcscpy((WCHAR *) pBuffer, m_strResponseHeader); } else { DWORD iPos = 0; for(DWORD iter=0; iter<dwLen; iter++) if (m_strResponseHeader[iter] == L'\r' && m_strResponseHeader[iter+1] == L'\n') { ((WCHAR *)pBuffer)[iPos++] = L'0'; iter++; } else { ((WCHAR *)pBuffer)[iPos++] = m_strResponseHeader[iter]; }
*pcbBuf = iPos; } } goto exit; case HTTP_QUERY_ACCEPT: szHeader = L"Accept:"; break; case HTTP_QUERY_ACCEPT_CHARSET: szHeader = L"Accept-Charset:"; break; case HTTP_QUERY_ACCEPT_ENCODING: szHeader = L"Accept-Encoding:"; break; case HTTP_QUERY_ACCEPT_LANGUAGE: szHeader = L"Accept-Language:"; break; case HTTP_QUERY_ACCEPT_RANGES: szHeader = L"Accept-Ranges:"; break; case HTTP_QUERY_AGE: szHeader = L"Age:"; break; case HTTP_QUERY_ALLOW: szHeader = L"Allow:"; break; case HTTP_QUERY_AUTHORIZATION: szHeader = L"Authorization:"; break; case HTTP_QUERY_CACHE_CONTROL: szHeader = L"Cache-Control:"; break; case HTTP_QUERY_CONNECTION: szHeader = L"Connection:"; break; case HTTP_QUERY_CONTENT_BASE: szHeader = L"Content-Base:"; break; case HTTP_QUERY_CONTENT_DESCRIPTION: szHeader = L"Content-Description:"; break; case HTTP_QUERY_CONTENT_DISPOSITION: szHeader = L"Content-Disposition:"; break; case HTTP_QUERY_CONTENT_ENCODING: szHeader = L"Content-encoding:"; break; case HTTP_QUERY_CONTENT_ID: szHeader = L"Content-ID:"; break; case HTTP_QUERY_CONTENT_LANGUAGE: szHeader = L"Content-Language:"; break; case HTTP_QUERY_CONTENT_LENGTH: szHeader = L"Content-Langth:"; break; case HTTP_QUERY_CONTENT_LOCATION: szHeader = L"Content-Location:"; break; case HTTP_QUERY_CONTENT_MD5: szHeader = L"Content-MD5:"; break; case HTTP_QUERY_CONTENT_TRANSFER_ENCODING: szHeader = L"Content-Transfer-Encoding:"; break; case HTTP_QUERY_CONTENT_TYPE: szHeader = L"Content-Type:"; break; case HTTP_QUERY_COOKIE: szHeader = L"Cookie:"; break; case HTTP_QUERY_COST: szHeader = L"Cost:"; break; case HTTP_QUERY_CUSTOM: szHeader = L"Custom:"; break; case HTTP_QUERY_DATE: szHeader = L"Date:"; break; case HTTP_QUERY_DERIVED_FROM: szHeader = L"Derived-From:"; break; case HTTP_QUERY_ECHO_HEADERS: szHeader = L"Echo-Headers:"; break; case HTTP_QUERY_ECHO_HEADERS_CRLF: szHeader = L"Echo-Headers-Crlf:"; break; case HTTP_QUERY_ECHO_REPLY: szHeader = L"Echo-Reply:"; break; case HTTP_QUERY_ECHO_REQUEST: szHeader = L"Echo-Request:"; break; case HTTP_QUERY_ETAG: szHeader = L"ETag:"; break; case HTTP_QUERY_EXPECT: szHeader = L"Expect:"; break; case HTTP_QUERY_EXPIRES: szHeader = L"Expires:"; break; case HTTP_QUERY_FORWARDED: szHeader = L"Forwarded:"; break; case HTTP_QUERY_FROM: szHeader = L"From:"; break; case HTTP_QUERY_HOST: szHeader = L"Host:"; break; case HTTP_QUERY_IF_MATCH: szHeader = L"If-Match:"; break; case HTTP_QUERY_IF_MODIFIED_SINCE: szHeader = L"If-Modified-Since:"; break; case HTTP_QUERY_IF_NONE_MATCH: szHeader = L"If-None-Match:"; break; case HTTP_QUERY_IF_RANGE: szHeader = L"If-Range:"; break; case HTTP_QUERY_IF_UNMODIFIED_SINCE: szHeader = L"If-Unmodified-since:"; break; case HTTP_QUERY_LINK: szHeader = L"Link:"; break; case HTTP_QUERY_LAST_MODIFIED: szHeader = L"Last-Modified:"; break; case HTTP_QUERY_LOCATION: szHeader = L"Location:"; break; case HTTP_QUERY_MAX_FORWARDS: szHeader = L"Max-Forwards:"; break; case HTTP_QUERY_MESSAGE_ID: szHeader = L"Message_Id:"; break; case HTTP_QUERY_MIME_VERSION: szHeader = L"Mime-Version:"; break; case HTTP_QUERY_ORIG_URI: szHeader = L"Orig-Uri:"; break; case HTTP_QUERY_PRAGMA: szHeader = L"Pragma:"; break; case HTTP_QUERY_PROXY_AUTHENTICATE: szHeader = L"Authenticate:"; break; case HTTP_QUERY_PROXY_AUTHORIZATION: szHeader = L"Proxy-Authorization:"; break; case HTTP_QUERY_PROXY_CONNECTION: szHeader = L"Proxy-Connection:"; break; case HTTP_QUERY_PUBLIC: szHeader = L"Public:"; break; case HTTP_QUERY_RANGE: szHeader = L"Range:"; break; case HTTP_QUERY_REFERER: szHeader = L"Referer:"; break; case HTTP_QUERY_REFRESH: szHeader = L"Refresh:"; break; case HTTP_QUERY_REQUEST_METHOD: szHeader = L"Request-Method:"; break; case HTTP_QUERY_RETRY_AFTER: szHeader = L"Retry-After:"; break; case HTTP_QUERY_SERVER: szHeader = L"Server:"; break; case HTTP_QUERY_SET_COOKIE: szHeader = L"Set-Cookie:"; break; case HTTP_QUERY_STATUS_CODE: szHeader = L"HTTP/1.1"; // Special!!!
break; case HTTP_QUERY_STATUS_TEXT: szHeader = L"HTTP/1.1"; // Special!!!
break; case HTTP_QUERY_TITLE: szHeader = L"Title:"; break; case HTTP_QUERY_TRANSFER_ENCODING: szHeader = L"Transfer-Encoding:"; break; case HTTP_QUERY_UNLESS_MODIFIED_SINCE: szHeader = L"Unless-Modified-Since:"; break; case HTTP_QUERY_UPGRADE: szHeader = L"Upgrade:"; break; case HTTP_QUERY_URI: szHeader = L"Uri:"; break; case HTTP_QUERY_USER_AGENT: szHeader = L"User-Agent:"; break; case HTTP_QUERY_VARY: szHeader = L"Vary:"; break; case HTTP_QUERY_VERSION: szHeader = L"Version:"; break; case HTTP_QUERY_VIA: szHeader = L"Via:"; break; case HTTP_QUERY_WARNING: szHeader = L"Warning:"; break; case HTTP_QUERY_WWW_AUTHENTICATE: szHeader = L"WWW-Authenticate:"; break; default: goto exit; }
if (dwOption & HTTP_QUERY_FLAG_SYSTEMTIME) { if (*pcbBuf < sizeof(SYSTEMTIME) || pBuffer == NULL) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); goto exit; } else { LPSYSTEMTIME pSys = (LPSYSTEMTIME) pBuffer; GetSystemTime(pSys); *pcbBuf = sizeof(SYSTEMTIME); goto exit; } }
if ((dwOption & HTTP_QUERY_FLAG_REQUEST_HEADERS) == 0) hr = DealWithBuffer(m_strResponseHeader, szHeader, dwOpt, dwOption, pBuffer, pcbBuf); if (hr == E_FAIL) hr = DealWithBuffer(m_extraHeaders, szHeader, dwOpt, dwOption, pBuffer, pcbBuf);
exit: return hr; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::DealWithBuffer( LPWSTR szHeaders, LPCWSTR szHeader, DWORD dwOpt, DWORD dwOption, LPVOID pBuffer, LPDWORD pcbBuf) { LPCWSTR szValue = wcsstr(szHeaders, (LPWSTR) szHeader); if (szValue == NULL) return E_FAIL;
DWORD dwStart = wcslen(szHeader); while(iswspace(szValue[dwStart]) && szValue[dwStart] != L'\r') dwStart++;
DWORD dwEnd = dwStart; switch(dwOpt) { case HTTP_QUERY_STATUS_CODE: dwEnd = dwStart + 3; break; case HTTP_QUERY_STATUS_TEXT: dwStart += 4;// Fall thru to default
dwEnd = dwStart; default: while(szValue[dwEnd] != NULL && szValue[dwEnd] != L'\r') dwEnd++; dwEnd--; }
DWORD dwReq = (dwEnd - dwStart + 1);
if ((dwOption & HTTP_QUERY_FLAG_NUMBER) && *pcbBuf < 4) { *pcbBuf = 4; return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } if ((dwOption & HTTP_QUERY_FLAG_NUMBER) == 0 && *pcbBuf < dwReq) { *pcbBuf = dwReq; return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); }
if (dwOption & HTTP_QUERY_FLAG_NUMBER) { LPDWORD lpD = (LPDWORD) pBuffer; *lpD = _wtoi(&szValue[dwStart]); *pcbBuf = 4; } else { memcpy(pBuffer, &szValue[dwStart], dwReq*sizeof(WCHAR)); ((WCHAR *) pBuffer)[dwReq] = NULL; } return S_OK; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT AppProtocol::ProcessAppManifest() { HRESULT hr = S_OK;
char *szManifest; HANDLE hFile; BYTE buffer[1024]; DWORD dwLength;
APPINFO aiApplication;
aiApplication._wzNewRef[0] = L'\0'; aiApplication._wzEntryAssemblyFileName[0] = L'\0'; aiApplication._pFileList = NULL;
// step 1: read the .manifest
hFile = CreateFile(m_localStoreFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastWin32Error(); goto exit; }
ZeroMemory(buffer, sizeof(buffer));
while ( ReadFile (hFile, buffer, sizeof(buffer), &dwLength, NULL) && dwLength ) { break; //BUGBUG: read once - only the 1st 1024 bytes
} if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
*(buffer + dwLength) = '\0'; szManifest = (char*) buffer;
// step 2: parsing
ParseManifest(szManifest, &aiApplication);
// step 3: do "the works"
// should take the base Uri, base appRoot, + file name
//*** if (FAILED(hr = InstallInternetFile2(wzSourceUri, m_appRootTranslated, filename, hash)))
// goto exit;
exit: return hr; }
void AppProtocol::ParseManifest(char* szManifest, APPINFO* pAppInfo) { char *token; char seps[] = " </>=\"\t\n\r"; FILEINFOLIST* pCurrent = NULL;
// WCHAR wzDummyPath[MAX_PATH];
WCHAR wzSourceUri[MAX_PATH];
BOOL fSkipNextToken = FALSE;
// parsing code - limitation: does not work w/ space in field, even if enclosed w/ quotes
// szManifest will be modified!
token = strtok( szManifest, seps ); while( token != NULL ) { // wzDummyPath[0] = L'\0';
// While there are tokens
if (!_stricmp(token, "file")) { // get around in spaced tag
token = strtok( NULL, seps ); if (!_stricmp(token, "name")) { token = strtok( NULL, seps );
/* lstrcpy(wzSourceUri, m_fullUri);
WCHAR* p = wcsrchr(wzSourceUri, L'/'); WCHAR* q = wcsrchr(wzSourceUri, L'.'); if (p && q && (p < q)) *p = L'\0'; else { hr = E_INVALIDARG; goto exit; } _snwprintf(wzSourceUri, MAX_PATH, L"%s/%S", wzSourceUri, token);*/
// init
if (pCurrent == NULL) { pAppInfo->_pFileList = new FILEINFOLIST; pCurrent = pAppInfo->_pFileList; } else { pCurrent->_pNext = new FILEINFOLIST; pCurrent = pCurrent->_pNext; }
pCurrent->_pNext = NULL; _snwprintf(pCurrent->_wzFilename, MAX_PATH, L"%S", token); // worry about total path len later
//no need m_pProtocolSink->ReportProgress(BINDSTATUS_BEGINDOWNLOADCOMPONENTS, L"downloading application files");
token = strtok( NULL, seps ); if (!_stricmp(token, "hash")) { _snwprintf(pCurrent->_wzHash, 33, L"%S", token);
// ???? should i reuse the file handle instead?
//* if (IsFileCorrupted(m_localStoreFilePath, token)) Integrity
//* ...
} else fSkipNextToken = TRUE; } } else if (!_stricmp(token, "newhref")) { // note, different handling... because '/' is one of seps
for (int i = 0; i < MAX_URL_LENGTH; i++) { if (*(token+8+i) == '<') { // BUGBUG: 8 == strlen("newhref>")
*(token+8+i) = '\0'; _snwprintf(pAppInfo->_wzNewRef, i, L"%S", token+8);
// BUGBUG? is this going to work?
token = strtok( token+i+9, seps); // now token == "newhref" && *(token-1) == '/'
} }
// BUGBUG: ignoring > MAX_URL_LENGTH case here... may mess up later if the URL contain a "keyword"
// <newhref></newhref> may be ok...
}
//else
// ignore others for now
// Get next token...
if(!fSkipNextToken) token = strtok( NULL, seps ); else fSkipNextToken = FALSE; } }
|