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.
3059 lines
89 KiB
3059 lines
89 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995.
|
|
//
|
|
// File: cnethttp.cxx
|
|
//
|
|
// Contents:
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <iapp.h>
|
|
#include "shlwapip.h"
|
|
#ifndef unix
|
|
#include "..\trans\transact.hxx"
|
|
#include "..\trans\oinet.hxx"
|
|
#else
|
|
#include "../trans/transact.hxx"
|
|
#include "../trans/oinet.hxx"
|
|
#endif /* unix */
|
|
|
|
PerfDbgTag(tagCINetHttp, "Urlmon", "Log CINetHttp", DEB_PROT);
|
|
|
|
extern LPSTR g_pszUAInfoString;
|
|
static CHAR gszAcceptEncHeaders[] = "Accept-Encoding: gzip, deflate";
|
|
|
|
// http specifics
|
|
static char vszGet[] = "GET";
|
|
static char vszPost[] = "POST";
|
|
static char vszPut[] = "PUT";
|
|
static char vszAttachment[] = "attachment";
|
|
static char vszFileName[] = "filename";
|
|
static DWORD dwLstError;
|
|
DWORD GetRedirectSetting();
|
|
|
|
// list of content-type we should not apply content-encoding onto it.
|
|
static LPSTR vszIgnoreContentEnc[] =
|
|
{
|
|
"application/x-tar"
|
|
,"x-world/x-vrml"
|
|
,"application/zip"
|
|
,"application/x-gzip"
|
|
,"application/x-zip-compressed"
|
|
,"application/x-compress"
|
|
,"application/x-compressed"
|
|
,"application/x-spoon"
|
|
, 0
|
|
};
|
|
|
|
BOOL IgnoreContentEncoding(LPSTR szContentType, LPSTR szEnc, LPSTR szAccept)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Bool,
|
|
"IgnoreContentEncoding",
|
|
"%.80q, %.80q, %.80q",
|
|
szContentType, szEnc, szAccept
|
|
));
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
if( szEnc && szAccept && !StrStrI(szAccept, szEnc) )
|
|
{
|
|
//
|
|
// some of the old web server will ignore the schemas indicated at
|
|
// Accept-Endocing: header, we need to add another check here
|
|
// to make sure the server returned content-encoding is the
|
|
// one we supported, otherwise, we will not init the decoder
|
|
//
|
|
bRet = TRUE;
|
|
}
|
|
|
|
if( !bRet )
|
|
{
|
|
for( int i = 0; vszIgnoreContentEnc[i]; i++)
|
|
{
|
|
if(!StrCmpI(szContentType, vszIgnoreContentEnc[i]) )
|
|
{
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(bRet);
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetRedirectSetting
|
|
//
|
|
// Synopsis: Reads the registry UrlMon Setting of Redirect
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns: 0 if redirect should be done by WinINet,
|
|
// 1 if should be done by UrlMon
|
|
//
|
|
// History: 4-22-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD GetRedirectSetting()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Dword,
|
|
"GetRedirectSetting",
|
|
NULL
|
|
));
|
|
|
|
HKEY hUrlMonKey = NULL;
|
|
DWORD dwType;
|
|
static DWORD dwValue = 0xffffffff;
|
|
|
|
if (dwValue == 0xffffffff)
|
|
{
|
|
DWORD dwValueLen = sizeof(DWORD);
|
|
dwValue = 0;
|
|
|
|
#define szUrlMonKey "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UrlMon Settings"
|
|
#define szRedirect "Redirect"
|
|
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szUrlMonKey, 0, KEY_QUERY_VALUE, &hUrlMonKey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(hUrlMonKey, szRedirect, NULL, &dwType, (LPBYTE)&dwValue, &dwValueLen) != ERROR_SUCCESS)
|
|
{
|
|
dwValue = 0;
|
|
}
|
|
RegCloseKey(hUrlMonKey);
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(dwValue);
|
|
return dwValue;
|
|
}
|
|
|
|
// max version strlen = (5)"HTTP/" + (4)digits + (1)'.' + (4)digits + (1)'\0'
|
|
#define MAXVERSIONLEN 15
|
|
BOOL RequestUsedHttp10(
|
|
IN HINTERNET hHttpRequest
|
|
)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Bool,
|
|
"RequestUsedHttp10",
|
|
"%#x",
|
|
hHttpRequest
|
|
));
|
|
|
|
char lpszHttpVersion[MAXVERSIONLEN];
|
|
DWORD dwLen = MAXVERSIONLEN;
|
|
BOOL fRet = FALSE;
|
|
|
|
if (HttpQueryInfo(
|
|
hHttpRequest,
|
|
HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_VERSION,
|
|
(LPVOID)lpszHttpVersion,
|
|
&dwLen,
|
|
NULL))
|
|
{
|
|
if (0 == StrCmpNI("HTTP/1.0", lpszHttpVersion, dwLen))
|
|
fRet = TRUE;
|
|
}
|
|
|
|
DEBUG_LEAVE(fRet);
|
|
return fRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::CINetHttp
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CINetHttp::CINetHttp(REFCLSID rclsid, IUnknown *pUnkOuter) : CINet(rclsid,pUnkOuter)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
None,
|
|
"CINetHttp::CINetHttp",
|
|
"this=%#x, %#x, %#x",
|
|
this, &rclsid, pUnkOuter
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::CINetHttp");
|
|
|
|
_pHttpNeg = NULL;
|
|
_pHttpNeg2 = NULL;
|
|
_dwIsA = DLD_PROTOCOL_HTTP;
|
|
_dwBufferSize = 0;
|
|
_pBuffer = 0;
|
|
_pszVerb = 0;
|
|
_f2ndCacheKeySet = FALSE;
|
|
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttp::CINetHttp");
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::~CINetHttp
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CINetHttp::~CINetHttp()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
None,
|
|
"CINetHttp::~CINetHttp",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::~CINetHttp");
|
|
PProtAssert(( !_hRequest ));
|
|
PProtAssert(( !_hServer ));
|
|
|
|
delete [] _pBuffer;
|
|
delete [] _pszHeader;
|
|
delete [] _pszSendHeader;
|
|
delete [] _pwzAddHeader;
|
|
delete [] _pszVerb;
|
|
if (_pbRootSecurityId != INVALID_P_ROOT_SECURITY_ID)
|
|
delete [] _pbRootSecurityId;
|
|
|
|
PProtAssert((_pHttpNeg == NULL));
|
|
PProtAssert((_pHttpNeg2 == NULL));
|
|
PProtAssert((_pWindow == NULL));
|
|
PProtAssert(( _pHttSecurity == NULL));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttp::~CINetHttp");
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::INetAsyncOpenRequest
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-27-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::INetAsyncOpenRequest()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::INetAsyncOpenRequest",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "+CINetHttp::INetAsyncOpenRequest (_szObject:%s)", GetObjectName());
|
|
HRESULT hr = NOERROR;
|
|
DWORD dwBindF = 0;
|
|
const ULONG culSize = 256;
|
|
ULONG ulSize = culSize;
|
|
LPCSTR rgszAcceptStr[culSize] = { 0 };
|
|
LPWSTR rgwzStr[culSize];
|
|
|
|
SetINetState(INetState_PROTOPEN_REQUEST);
|
|
PProtAssert((g_hSession != NULL));
|
|
PProtAssert((GetStatePending() == NOERROR));
|
|
|
|
if (_pOIBindInfo)
|
|
{
|
|
LPWSTR *pwzStr;
|
|
IEnumString *pEnumString = NULL;
|
|
ULONG ulCount = culSize;
|
|
|
|
hr = _pOIBindInfo->GetBindString(BINDSTRING_ACCEPT_MIMES, (LPWSTR *)rgwzStr, ulSize, &ulCount);
|
|
|
|
if (hr == NOERROR)
|
|
{
|
|
ULONG c = 0;
|
|
|
|
for (c = 0; c < ulCount; c++)
|
|
{
|
|
rgszAcceptStr[c] = (LPCSTR) DupW2A(rgwzStr[c]);
|
|
delete rgwzStr[c];
|
|
rgwzStr[c] = 0;
|
|
}
|
|
rgszAcceptStr[c] = 0;
|
|
}
|
|
else
|
|
if( hr == INET_E_USE_DEFAULT_SETTING )
|
|
{
|
|
rgszAcceptStr[0] = (LPCSTR) DupW2A(L"*/*");
|
|
rgszAcceptStr[1] = NULL;
|
|
hr = NOERROR;
|
|
}
|
|
|
|
}
|
|
if (hr != NOERROR)
|
|
{
|
|
hr = INET_E_NO_VALID_MEDIA;
|
|
_hrError = INET_E_NO_VALID_MEDIA;
|
|
}
|
|
else if (!_hServer)
|
|
{
|
|
// the download was probably aborted
|
|
if (_hrError == NOERROR)
|
|
{
|
|
SetBindResult(ERROR_INVALID_HANDLE, hr);
|
|
hr = _hrError = INET_E_CANNOT_CONNECT;
|
|
}
|
|
else
|
|
{
|
|
hr = _hrError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PProtAssert((_hServer));
|
|
|
|
//PProtAssert((ppszAcceptStr && *ppszAcceptStr));
|
|
|
|
#if DBG==1
|
|
{
|
|
LPSTR *pszMime = (LPSTR *) &rgszAcceptStr;
|
|
while (*pszMime)
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "=== CTransData::GetAcceptStr (szMime:%s)", *pszMime);
|
|
pszMime++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
dwBindF = GetBindFlags();
|
|
|
|
if (dwBindF & BINDF_IGNORESECURITYPROBLEM)
|
|
{
|
|
_dwOpenFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
|
|
_dwOpenFlags |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
|
|
_dwOpenFlags |= INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
|
|
_dwOpenFlags |= INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP;
|
|
}
|
|
|
|
if (dwBindF & BINDF_ENFORCERESTRICTED)
|
|
{
|
|
_dwOpenFlags |= INTERNET_FLAG_RESTRICTED_ZONE;
|
|
}
|
|
|
|
|
|
if (GetRedirectSetting() != 0)
|
|
{
|
|
DbgLog(tagCINetHttp, this, "=== CINet::INetAsyncOpenRequest redirect done by UrlMon!");
|
|
_dwOpenFlags |= INTERNET_FLAG_NO_AUTO_REDIRECT;
|
|
}
|
|
else
|
|
{
|
|
DbgLog(tagCINetHttp, this, "=== CINet::INetAsyncOpenRequest redirect done by WinINet!");
|
|
}
|
|
|
|
//
|
|
// we always request keep-alive
|
|
//
|
|
_dwOpenFlags |= INTERNET_FLAG_KEEP_CONNECTION;
|
|
|
|
//
|
|
// Notify wininet if this is a multipart upload so it doesn't
|
|
// add a terminating 0x0d 0x0a to the first send
|
|
//
|
|
BINDINFO *pBndInfo = GetBindInfo();
|
|
if (IsUpLoad()
|
|
// Add in extra check to make TYMED_ISTREAM work the same as
|
|
// TYMED_HGLOBAL for verbs that require a body, other than POST.
|
|
// We might consider doing away with this IF statement in the future:
|
|
&& (pBndInfo->dwBindVerb == BINDVERB_POST))
|
|
|
|
{
|
|
_dwOpenFlags |= INTERNET_FLAG_NO_AUTO_REDIRECT;
|
|
//BUGBUG: is the flag below needed?
|
|
//_dwOpenFlags |= INTERNET_FLAG_MULTIPART;
|
|
}
|
|
|
|
|
|
|
|
PrivAddRef(TRUE);
|
|
SetStatePending(E_PENDING);
|
|
|
|
_HandleStateRequest = HandleState_Pending;
|
|
HINTERNET hRequestTmp = HttpOpenRequest(
|
|
_hServer, // hHttpSession
|
|
GetVerb(), // lpszVerb
|
|
GetObjectName(), // lpszObjectName
|
|
NULL, //HTTP_VERSION, // lpszVersion
|
|
NULL, // lpszReferer
|
|
rgszAcceptStr, // lplpszAcceptTypes
|
|
_dwOpenFlags, // flag
|
|
(DWORD_PTR) this // context
|
|
);
|
|
if ( hRequestTmp == 0)
|
|
{
|
|
dwLstError = GetLastError();
|
|
if (dwLstError == ERROR_IO_PENDING)
|
|
{
|
|
// wait async for the handle
|
|
hr = E_PENDING;
|
|
}
|
|
else
|
|
{
|
|
PrivRelease(TRUE);
|
|
SetStatePending(NOERROR);
|
|
hr = _hrError = INET_E_RESOURCE_NOT_FOUND;
|
|
SetBindResult(dwLstError,hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_hRequest = hRequestTmp;
|
|
SetStatePending(NOERROR);
|
|
_HandleStateRequest = HandleState_Initialized;
|
|
|
|
if (_fUTF8hack)
|
|
{
|
|
DWORD dwSendUTF8 = 1;
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY, &dwSendUTF8, sizeof(DWORD));
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_CODEPAGE, &_dwServerCodePage, sizeof(DWORD));
|
|
}
|
|
|
|
hr = INetAsyncSendRequest();
|
|
}
|
|
|
|
{
|
|
LPSTR *pszMime = (LPSTR *) &rgszAcceptStr;
|
|
while (*pszMime)
|
|
{
|
|
LPSTR pszDel = *pszMime;
|
|
delete pszDel;
|
|
pszMime++;
|
|
}
|
|
}
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::INetAsyncOpenRequest (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::INetAsyncSendRequest
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-27-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::INetAsyncSendRequest()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::INetAsyncSendRequest",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::INetAsyncSendRequest");
|
|
|
|
HRESULT hr = NOERROR;
|
|
BOOL fRestarted;
|
|
BOOL fRet;
|
|
PProtAssert((GetStatePending() == NOERROR));
|
|
|
|
SetINetState(INetState_SEND_REQUEST);
|
|
|
|
LPVOID pBuffer = 0;
|
|
DWORD dwBufferSize = 0;
|
|
LPSTR szVerb = GetVerb();
|
|
|
|
//
|
|
// BUGBUG: move this into GetAdditionalHeader
|
|
//
|
|
if (_fRedirected == TRUE || (_cbProxyAuthenticate + _cbAuthenticate))
|
|
{
|
|
if (_pszSendHeader)
|
|
{
|
|
delete _pszSendHeader;
|
|
_pszSendHeader = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (_fRedirected == FALSE && !(_cbProxyAuthenticate + _cbAuthenticate))
|
|
{
|
|
GetAdditionalHeader();
|
|
}
|
|
|
|
if (_fRedirected == FALSE || _fP2PRedirected )
|
|
{
|
|
// Note: the buffer returned here will be freed
|
|
// by the destructor
|
|
GetDataToSend(&pBuffer, &dwBufferSize);
|
|
_fP2PRedirected = FALSE;
|
|
}
|
|
|
|
// Call HttpNeg only the first time in case of authentication
|
|
// i.e. both Auth counts == 0 ?
|
|
if (!(_cbAuthenticate || _cbProxyAuthenticate)) {
|
|
//BUGBUG: does BeginingTrans need to be called for
|
|
// redirect and authentication resends?
|
|
if (_fRedirected == FALSE)
|
|
hr = HttpNegBeginningTransaction();
|
|
// Note: the header is appended to the AddHeader
|
|
}
|
|
|
|
HttpNegGetRootSecurityId();
|
|
LONG lThirdParty;
|
|
if (IsThirdPartyUrl(GetUrl()))
|
|
{
|
|
lThirdParty = 1;
|
|
//MessageBoxW( 0, GetUrl(), L"cnethttp: THIRDPARTY!", 0 );
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_COOKIES_3RD_PARTY, &lThirdParty, sizeof(LONG));
|
|
}
|
|
else
|
|
{
|
|
lThirdParty = 0;
|
|
//MessageBoxW( 0, GetUrl(), L"cnethttp: NOT THIRDPARTY!", 0 );
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_COOKIES_3RD_PARTY, &lThirdParty, sizeof(LONG));
|
|
}
|
|
|
|
if (hr == E_ABORT)
|
|
{
|
|
_hrError = hr;
|
|
SetBindResult(ERROR_CANCELLED,hr);
|
|
}
|
|
else
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "+CINetHttp::INetAsyncSendRequest HttpSendRequest (_pszSendHeader:%s)", XDBG(_pszSendHeader,""));
|
|
|
|
if (GetBindInfo()->dwBindVerb == BINDVERB_POST && !_f2ndCacheKeySet)
|
|
{
|
|
// WININET request: send SECONDARY_CACHE_KEY only once
|
|
ULONG ulCount = 0;
|
|
LPWSTR pwzPostCookieStr = 0;
|
|
HRESULT hr1 = _pOIBindInfo->GetBindString(BINDSTRING_POST_COOKIE, (LPWSTR *)&pwzPostCookieStr, 1, &ulCount);
|
|
if ((hr1 == NOERROR) && pwzPostCookieStr)
|
|
{
|
|
// BUGBUG: trident return s_ok and no string
|
|
PProtAssert((pwzPostCookieStr));
|
|
LPSTR pszStr = DupW2A(pwzPostCookieStr);
|
|
if (pszStr)
|
|
{
|
|
_f2ndCacheKeySet = TRUE;
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_SECONDARY_CACHE_KEY, pszStr, strlen(pszStr));
|
|
delete pszStr;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_hrError = INET_E_DOWNLOAD_FAILURE;
|
|
SetBindResult(hr,hr);
|
|
}
|
|
delete pwzPostCookieStr;
|
|
}
|
|
|
|
}
|
|
|
|
/************ enable this after wininet sniff checked in *******
|
|
// set option for data sniff
|
|
DWORD dwDataSniff = 1;
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_DATASNIFF, &dwDataSniff, sizeof(DWORD));
|
|
****************************************************************/
|
|
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_REQUEST_PRIORITY, &_nPriority, sizeof(LONG));
|
|
|
|
if (_fRedirected || !_fUTF8hack)
|
|
{
|
|
/*
|
|
This is used in wininet now only to convert the MBCS servername supplied to UTF8
|
|
to send to the proxy if needed
|
|
*/
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_CODEPAGE, &_BndInfo.dwCodePage, sizeof(DWORD));
|
|
}
|
|
|
|
SetStatePending(E_PENDING);
|
|
|
|
if (hr == NOERROR)
|
|
{
|
|
if (IsUpLoad())
|
|
{
|
|
// post verb
|
|
// DWORD dwSendFlags = HSR_ASYNC | HSR_CHUNKED | HSR_INITIATE;
|
|
DWORD dwSendFlags = HSR_CHUNKED | HSR_INITIATE;
|
|
DWORD dwSendContext = 0;
|
|
|
|
if (!_pStm)
|
|
{
|
|
BINDINFO *pBI = GetBindInfo();
|
|
if (pBI && pBI->stgmedData.tymed == TYMED_ISTREAM)
|
|
{
|
|
_pStm = pBI->stgmedData.pstm;
|
|
}
|
|
}
|
|
if (_pStm)
|
|
{
|
|
hr = GetNextSendBuffer(&_inetBufferSend,_pStm, TRUE);
|
|
}
|
|
|
|
fRet = HttpSendRequestExA(
|
|
_hRequest // IN HINTERNET hRequest,
|
|
,&_inetBufferSend // IN LPINTERNET_BUFFERSA lpBuffersIn OPTIONAL,
|
|
, NULL // OUT lpBuffersOut not used
|
|
,dwSendFlags // IN DWORD dwFlags,
|
|
,dwSendContext // IN DWORD dwContext
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError;
|
|
|
|
// Allow ERROR_INTERNET_INSERT_CDROM to be returned from HttpSendRequest
|
|
#ifdef MSNJIT
|
|
DWORD dwErrorMask = INTERNET_ERROR_MASK_INSERT_CDROM | INTERNET_ERROR_MASK_COMBINED_SEC_CERT | INTERNET_ERROR_MASK_NEED_MSN_SSPI_PKG;
|
|
#else
|
|
DWORD dwErrorMask = INTERNET_ERROR_MASK_INSERT_CDROM | INTERNET_ERROR_MASK_COMBINED_SEC_CERT;
|
|
#endif
|
|
dwErrorMask = dwErrorMask | INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY;
|
|
|
|
InternetSetOption(_hRequest, INTERNET_OPTION_ERROR_MASK, &dwErrorMask, sizeof(DWORD));
|
|
|
|
fRet = HttpSendRequest(_hRequest,
|
|
_pszSendHeader, // additional headers
|
|
(_pszSendHeader) ? (ULONG)-1L : 0L, // size of additional headers data
|
|
pBuffer, // Optional data (POST or put)
|
|
dwBufferSize); // optional data length
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttp::INetAsyncSendRequest HttpSendRequest");
|
|
|
|
} // end else
|
|
|
|
if (fRet == FALSE)
|
|
{
|
|
dwLstError = GetLastError();
|
|
if (dwLstError == ERROR_IO_PENDING)
|
|
{
|
|
// wait async for the handle
|
|
hr = E_PENDING;
|
|
}
|
|
else if (dwLstError == ERROR_INTERNET_INSERT_CDROM)
|
|
{
|
|
_hrINet = INET_E_AUTHENTICATION_REQUIRED;
|
|
_dwSendRequestResult = ERROR_INTERNET_INSERT_CDROM;
|
|
_lpvExtraSendRequestResult = NULL;
|
|
TransitState(INetState_DISPLAY_UI, TRUE);
|
|
hr = E_PENDING;
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetStatePending(NOERROR);
|
|
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
|
|
SetBindResult(dwLstError,hr);
|
|
PerfDbgLog3(tagCINetHttp, this, "CINetHttp::INetAsyncSendRequest (fRet:%d, _hrError:%lx, LstError:%ld)", fRet, _hrError, dwLstError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetStatePending(NOERROR);
|
|
|
|
// in case of redirect, we need to reset all the
|
|
// _dwSendRequestResult from previous callback
|
|
_dwSendRequestResult = 0;
|
|
_lpvExtraSendRequestResult = NULL;
|
|
hr = INetQueryInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (_hrError != INET_E_OK)
|
|
{
|
|
// we need to terminate here
|
|
ReportResultAndStop(hr);
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::INetAsyncSendRequest (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::QueryStatusOnResponse
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::QueryStatusOnResponse()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::QueryStatusOnResponse",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::QueryStatusOnResponse");
|
|
HRESULT hr = NOERROR;
|
|
|
|
DWORD dwStatus;
|
|
char szBuffer[max(2 * MAX_URL_SIZE, 400)];
|
|
DWORD cbBufferLen = sizeof(szBuffer);
|
|
DWORD cbLen = cbBufferLen;
|
|
|
|
if (_dwSendRequestResult)
|
|
{
|
|
// handle the sendrequest result
|
|
// zone crossing
|
|
switch (_dwSendRequestResult)
|
|
{
|
|
case ERROR_INTERNET_SEC_CERT_DATE_INVALID :
|
|
case ERROR_INTERNET_SEC_CERT_CN_INVALID :
|
|
case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR :
|
|
case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR :
|
|
case ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR :
|
|
case ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION :
|
|
case ERROR_INTERNET_INVALID_CA :
|
|
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED :
|
|
case ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED :
|
|
case ERROR_INTERNET_SEC_CERT_ERRORS :
|
|
case ERROR_INTERNET_SEC_CERT_REV_FAILED :
|
|
case ERROR_INTERNET_SEC_CERT_REVOKED :
|
|
{
|
|
hr = HttpSecurity(_dwSendRequestResult);
|
|
|
|
if ((hr != NOERROR) && (hr != E_PENDING))
|
|
{
|
|
_hrError = INET_E_AUTHENTICATION_REQUIRED;
|
|
}
|
|
else
|
|
{
|
|
_hrError = INET_E_OK;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY :
|
|
{
|
|
_hrError = INET_E_OK;
|
|
hr = NOERROR;
|
|
}
|
|
break;
|
|
|
|
#ifdef MSNJIT
|
|
case ERROR_INTERNET_NEED_MSN_SSPI_PKG :
|
|
{
|
|
const GUID MSN_AUTH_GUID =
|
|
{ 0x6fab99d0, 0xbab8, 0x11d1, {0x99, 0x4a, 0x00, 0xc0, 0x4f, 0x98, 0xbb, 0xc9} };
|
|
|
|
HWND hWnd = NULL;
|
|
DWORD dwJITFlags = 0;
|
|
|
|
uCLSSPEC classpec;
|
|
classpec.tyspec=TYSPEC_TYPELIB;
|
|
classpec.tagged_union.typelibID = (GUID)MSN_AUTH_GUID;
|
|
|
|
QUERYCONTEXT qc;
|
|
memset(&qc, 0, sizeof(qc));
|
|
|
|
// fill in the minimum version number of the component you need
|
|
//qc.dwVersionHi =
|
|
//qc.dwVersionLo =
|
|
hr = FaultInIEFeature(hWnd, &classpec, &qc, dwJITFlags);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = INET_E_AUTHENTICATION_REQUIRED;
|
|
}
|
|
else
|
|
{
|
|
hr = E_ABORT;
|
|
}
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (HttpQueryInfo(_hRequest, HTTP_QUERY_STATUS_CODE, szBuffer,&cbLen, NULL))
|
|
{
|
|
dwStatus = atoi(szBuffer);
|
|
_fProxyAuth = FALSE;
|
|
switch (dwStatus)
|
|
{
|
|
case HTTP_STATUS_DENIED:
|
|
{
|
|
_hrINet = INET_E_AUTHENTICATION_REQUIRED;
|
|
TransitState(INetState_AUTHENTICATE, TRUE);
|
|
hr = E_PENDING;
|
|
}
|
|
break;
|
|
case HTTP_STATUS_PROXY_AUTH_REQ :
|
|
{
|
|
_hrINet = INET_E_AUTHENTICATION_REQUIRED;
|
|
TransitState(INetState_AUTHENTICATE, TRUE);
|
|
_fProxyAuth = TRUE;
|
|
hr = E_PENDING;
|
|
}
|
|
break;
|
|
case HTTP_STATUS_MOVED:
|
|
case HTTP_STATUS_REDIRECT:
|
|
case HTTP_STATUS_REDIRECT_METHOD:
|
|
case HTTP_STATUS_REDIRECT_KEEP_VERB:
|
|
{
|
|
cbLen = cbBufferLen;
|
|
hr = RedirectRequest(szBuffer, &cbLen, dwStatus);
|
|
if ((hr != S_FALSE) && (hr != NOERROR) && (hr != E_PENDING))
|
|
{
|
|
_hrError = INET_E_INVALID_URL;
|
|
}
|
|
else
|
|
{
|
|
_hrError = INET_E_OK;
|
|
hr = S_FALSE;
|
|
SetINetState(INetState_DONE);
|
|
}
|
|
}
|
|
break;
|
|
case HTTP_STATUS_NO_CONTENT:
|
|
{
|
|
BINDINFO *pBndInfo = GetBindInfo();
|
|
|
|
if (pBndInfo && pBndInfo->dwBindVerb != BINDVERB_CUSTOM)
|
|
{
|
|
hr = _hrError = E_ABORT;
|
|
SetBindResult(ERROR_CANCELLED, hr);
|
|
}
|
|
else
|
|
{
|
|
hr = QueryStatusOnResponseDefault(dwStatus);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
hr = QueryStatusOnResponseDefault(dwStatus);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_hrError != INET_E_OK)
|
|
{
|
|
SetINetState(INetState_DONE);
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::QueryStatusOnResponse (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::QueryStatusOnResponseDefault
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::QueryStatusOnResponseDefault(DWORD dwStat)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::QueryStatusOnResponseDefault",
|
|
"this=%#x, %#x",
|
|
this, dwStat
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::QueryStatusOnResponseDefault");
|
|
HRESULT hr = NOERROR;
|
|
|
|
DWORD dwStatus = 0;
|
|
char szBuffer[max(2 * MAX_URL_SIZE, 400)];
|
|
DWORD cbBufferLen = sizeof(szBuffer);
|
|
DWORD cbLen = cbBufferLen;
|
|
|
|
if( !dwStat )
|
|
{
|
|
if (HttpQueryInfo(_hRequest, HTTP_QUERY_STATUS_CODE, szBuffer,&cbLen, NULL))
|
|
{
|
|
dwStatus = atoi(szBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwStatus = dwStat;
|
|
}
|
|
|
|
if( dwStatus )
|
|
{
|
|
#if DBG==1
|
|
if ( !((dwStatus >= HTTP_STATUS_OK) && (dwStatus <= HTTP_STATUS_GATEWAY_TIMEOUT)) )
|
|
{
|
|
DbgLog1(DEB_PROT|DEB_TRACE, this, "CINetHttp::QueryStatusOnResponse (dwStatus:%lx)", dwStatus);
|
|
}
|
|
PProtAssert(( (dwStatus >= HTTP_STATUS_BEGIN) && (dwStatus <= HTTP_STATUS_END)
|
|
&& L"WinINet returned an invalid status code: please contact a WININET developer" ));
|
|
#endif //DBG==1
|
|
|
|
// check if we got redirected from a file to a directory
|
|
{
|
|
cbLen = cbBufferLen;
|
|
InternetQueryOption(_hRequest, INTERNET_OPTION_URL, szBuffer, &cbLen);
|
|
if (cbLen)
|
|
{
|
|
BOOL fRedirected;
|
|
fRedirected = strcmp(szBuffer, _pszFullURL);
|
|
|
|
if (fRedirected)
|
|
{
|
|
cbLen = cbBufferLen;
|
|
hr = RedirectRequest(szBuffer, &cbLen, dwStatus);
|
|
|
|
if ((hr != NOERROR) && (hr != E_PENDING))
|
|
{
|
|
if (hr != INET_E_DOWNLOAD_FAILURE)
|
|
{
|
|
_hrError = INET_E_INVALID_URL;
|
|
}
|
|
// else set nothing
|
|
}
|
|
else
|
|
{
|
|
_hrError = INET_E_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cbLen = cbBufferLen;
|
|
|
|
BOOL fRet = HttpQueryInfo(_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, szBuffer,&cbLen, NULL);
|
|
BOOL fDeleteBuffer = FALSE;
|
|
LPSTR lpszBuffer;
|
|
|
|
if (!fRet)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
|
|
if (dwError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
lpszBuffer = new char[cbLen];
|
|
if (!lpszBuffer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto End;
|
|
}
|
|
fDeleteBuffer = TRUE;
|
|
fRet = HttpQueryInfo(_hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, lpszBuffer, &cbLen, NULL);
|
|
}
|
|
}
|
|
else
|
|
lpszBuffer = szBuffer;
|
|
|
|
if (fRet)
|
|
{
|
|
if (IsStatusOk(dwStatus))
|
|
{
|
|
hr = HttpNegOnHeadersAvailable(dwStatus, lpszBuffer);
|
|
}
|
|
else
|
|
{
|
|
hr = ErrorHandlingRequest(dwStatus, lpszBuffer);
|
|
if ((hr != NOERROR) && (hr != E_PENDING))
|
|
{
|
|
_hrError = hr;
|
|
}
|
|
else
|
|
{
|
|
_hrError = INET_E_OK;
|
|
}
|
|
}
|
|
|
|
if (hr == E_ABORT)
|
|
{
|
|
SetBindResult(ERROR_CANCELLED,hr);
|
|
}
|
|
}
|
|
|
|
if (fDeleteBuffer)
|
|
delete lpszBuffer;
|
|
}
|
|
|
|
End:
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::QueryStatusOnResponseDefault (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::QueryHeaderOnResponse
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::QueryHeaderOnResponse()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::QueryHeaderOnResponse",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::QueryHeaderOnResponse");
|
|
HRESULT hr = NOERROR;
|
|
DWORD dwStatus;
|
|
char szBuffer[max(2 * MAX_URL_SIZE, 400)];
|
|
DWORD cbBufferLen = sizeof(szBuffer);
|
|
DWORD dwFlags;
|
|
char szMIMEType[SZMIMESIZE_MAX] = "";
|
|
char szENCType[SZMIMESIZE_MAX] = "";
|
|
BOOL fContentDisp = FALSE;
|
|
|
|
// Get file length
|
|
if(HttpQueryInfo(_hRequest, HTTP_QUERY_CONTENT_LENGTH, szBuffer,&cbBufferLen, NULL))
|
|
{
|
|
_cbDataSize = atoi(szBuffer);
|
|
}
|
|
|
|
// Get Content-Disposition
|
|
szBuffer[0] = '\0';
|
|
cbBufferLen = sizeof(szBuffer);
|
|
|
|
if(HttpQueryInfo(
|
|
_hRequest,
|
|
HTTP_QUERY_CONTENT_DISPOSITION,
|
|
szBuffer,
|
|
&cbBufferLen,
|
|
NULL) )
|
|
{
|
|
// Search for :Attachment, if found, report it
|
|
if( StrStrI(szBuffer, vszAttachment) )
|
|
{
|
|
char szName[MAX_PATH];
|
|
char *pName = NULL;
|
|
|
|
// propogate the filename if available
|
|
if( StrStrI(szBuffer, vszFileName) )
|
|
{
|
|
DWORD cbNameLen;
|
|
|
|
szName[0] = '\0';
|
|
cbNameLen = sizeof(szName);
|
|
|
|
if(InternetQueryOption(_hRequest, INTERNET_OPTION_DATAFILE_NAME, szName, &cbNameLen))
|
|
pName = PathFindFileName(szName);
|
|
}
|
|
|
|
ReportNotification(BINDSTATUS_CONTENTDISPOSITIONATTACH, (pName?pName:NULL));
|
|
}
|
|
|
|
if( StrStrI(szBuffer, vszFileName) )
|
|
{
|
|
fContentDisp = TRUE;
|
|
}
|
|
}
|
|
|
|
// Get Accept-Ranges
|
|
szBuffer[0] = '\0';
|
|
cbBufferLen = sizeof(szBuffer);
|
|
if(HttpQueryInfo(
|
|
_hRequest,
|
|
HTTP_QUERY_ACCEPT_RANGES,
|
|
szBuffer,
|
|
&cbBufferLen,
|
|
NULL) )
|
|
{
|
|
ReportNotification(BINDSTATUS_ACCEPTRANGES, NULL);
|
|
}
|
|
|
|
// mimetype
|
|
cbBufferLen = sizeof(szMIMEType);
|
|
szMIMEType[0] = 0;
|
|
HttpQueryInfo(_hRequest, HTTP_QUERY_CONTENT_TYPE, szMIMEType, &cbBufferLen, NULL);
|
|
if (cbBufferLen && (szMIMEType[0] != 0))
|
|
{
|
|
//BUG-WORK
|
|
//_pCTransData->SetMimeType(szMIMEType);
|
|
//_pCTrans->ReportProgress();
|
|
DbgLog1(DEB_PROT|DEB_TRACE, this,
|
|
"CINetHttp::QueryHeaderOnResponse MIME TYPE(szMime:%s)!",
|
|
szMIMEType);
|
|
|
|
// work around image display problem, turn off report mime type
|
|
// for direct binding
|
|
if( _grfBindF & BINDF_FROMURLMON)
|
|
{
|
|
ReportNotification(BINDSTATUS_MIMETYPEAVAILABLE,szMIMEType);
|
|
}
|
|
else
|
|
{
|
|
ReportNotification(BINDSTATUS_RAWMIMETYPE, szMIMEType);
|
|
}
|
|
|
|
/*** enable this block after wininet data sniff checked in ****
|
|
if( _cbDataSize )
|
|
{
|
|
|
|
// datasniff enabled ?
|
|
DWORD dwDataSniff = 0;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
|
|
if( InternetQueryOption(
|
|
_hRequest,
|
|
INTERNET_OPTION_DATASNIFF,
|
|
&dwDataSniff,
|
|
&dwSize ) )
|
|
|
|
{
|
|
char szVCType[SZMIMESIZE_MAX] = "";
|
|
cbBufferLen = SZMIMESIZE_MAX;
|
|
|
|
InternetQueryOption(
|
|
_hRequest,
|
|
INTERNET_OPTION_VERIFIED_CONTENT_TYPE,
|
|
szVCType,
|
|
&cbBufferLen );
|
|
|
|
}
|
|
}
|
|
****************************************************************/
|
|
}
|
|
else
|
|
{
|
|
DbgLog1(DEB_PROT|DEB_TRACE, this,
|
|
"CINetHttp::QueryHeaderOnResponse NO MIME TYPE (szUrl:%s)!",
|
|
GetBaseURL());
|
|
//BUGBUG: need data sniffing later on
|
|
//_pCTransData->SetMimeType("text/html");
|
|
// work around image display problem, turn off report mime type
|
|
// for direct binding
|
|
if( _grfBindF & BINDF_FROMURLMON)
|
|
{
|
|
ReportNotification(BINDSTATUS_MIMETYPEAVAILABLE,"text/html");
|
|
}
|
|
}
|
|
|
|
// content encoding
|
|
cbBufferLen = sizeof(szENCType);
|
|
HttpQueryInfo(_hRequest, HTTP_QUERY_CONTENT_ENCODING, szENCType, &cbBufferLen, NULL);
|
|
if (cbBufferLen && (szENCType[0] != 0))
|
|
{
|
|
DbgLog1(DEB_PROT|DEB_TRACE, this,
|
|
"CINetHttp::QueryHeaderOnResponse ENCODING TYPE(szEnc :%s)!",
|
|
szENCType);
|
|
//
|
|
// existing http servers may mishandle the content-encoding
|
|
// header, we have to taken care of the following cases:
|
|
//
|
|
// 1. we do not send Accept-Encoding header(http1.1 disabled),
|
|
// however, server sends back Content-Encoding: foo
|
|
// (_pszHeaders contains the accept-encoding info, so if
|
|
// this is null, we should not invoke the decoder )
|
|
//
|
|
// 2. we send Accept-Encoding: A, server sends back
|
|
// Content-Encoding: B, this is a protocol violation
|
|
// IgnoreContentEncoding() takes care of that, it compares
|
|
// the _pszHeader and szENCType, and we should not invoke
|
|
// the decoder if they are mis-matched
|
|
//
|
|
// 3. server sends out content-encoding, but what they really
|
|
// mean is that let the application (e.g. gunzip.exe) to
|
|
// handle the compressed file, we can add the check for
|
|
// content-type, for a list of content-type we do not
|
|
// understand (e.g. application/x-compress, x-world/x-vrml..)
|
|
// do not invoke the decoder
|
|
//
|
|
|
|
// Wininet changes http version if http1.1 over proxy is disabled.
|
|
// This happens only after httpSendRequest is called, which is when
|
|
// Urlmon might have passed in the Accept-Encoding headers.
|
|
// If we did pass in the headers, we need to make sure that they
|
|
// were not stripped out because wininet finally used Http 1.0.
|
|
|
|
if( _pszHeader && !RequestUsedHttp10(_hRequest) &&
|
|
!IgnoreContentEncoding(szMIMEType, szENCType, _pszHeader) )
|
|
{
|
|
ReportNotification(BINDSTATUS_ENCODING, szENCType);
|
|
|
|
// Load The decompression handler now...
|
|
COInetSession *pCOInetSession = NULL;
|
|
IOInetProtocol *pProtHandler = NULL;
|
|
IOInetProtocolSink *pProtSnkHandler = NULL;
|
|
IOInetBindInfo *pBindInfo = NULL;
|
|
LPWSTR pwzStr = DupA2W(szENCType);
|
|
CLSID clsid;
|
|
|
|
hr = GetCOInetSession(0,&pCOInetSession,0);
|
|
if( hr == NOERROR )
|
|
{
|
|
hr = pCOInetSession->CreateHandler(
|
|
pwzStr, 0, 0, &pProtHandler, &clsid);
|
|
|
|
if( hr == NOERROR )
|
|
{
|
|
hr = pProtHandler->QueryInterface(
|
|
IID_IOInetProtocolSink, (void **) &pProtSnkHandler);
|
|
|
|
|
|
//hr = QueryInterface(
|
|
// IID_IOInetBindInfo, (void **) &pBindInfo);
|
|
}
|
|
|
|
if( hr == NOERROR )
|
|
{
|
|
HRESULT hr2 = NOERROR;
|
|
hr2 = _pEmbdFilter->SwitchSink(pProtSnkHandler);
|
|
if( hr2 == NOERROR )
|
|
{
|
|
hr = _pEmbdFilter->StackFilter(
|
|
pwzStr, pProtHandler, pProtSnkHandler, _pOIBindInfo );
|
|
}
|
|
}
|
|
|
|
if( pBindInfo )
|
|
{
|
|
pBindInfo->Release();
|
|
}
|
|
}
|
|
|
|
if( szMIMEType[0] != '\0' )
|
|
{
|
|
ReportNotification(BINDSTATUS_MIMETYPEAVAILABLE,szMIMEType);
|
|
}
|
|
|
|
// Get Cache-Control
|
|
szBuffer[0] = '\0';
|
|
cbBufferLen = sizeof(szBuffer);
|
|
if(HttpQueryInfo(
|
|
_hRequest,
|
|
HTTP_QUERY_CACHE_CONTROL,
|
|
szBuffer,
|
|
&cbBufferLen,
|
|
NULL) )
|
|
{
|
|
ReportNotification(BINDSTATUS_CACHECONTROL, szBuffer);
|
|
}
|
|
|
|
|
|
if(fContentDisp)
|
|
{
|
|
// Get Content-Disposition
|
|
szBuffer[0] = '\0';
|
|
cbBufferLen = sizeof(szBuffer);
|
|
|
|
if(InternetQueryOption(_hRequest, INTERNET_OPTION_DATAFILE_NAME, szBuffer, &cbBufferLen))
|
|
{
|
|
ReportNotification(BINDSTATUS_CONTENTDISPOSITIONATTACH, PathFindFileName(szBuffer));
|
|
}
|
|
}
|
|
// urlmon will create a decompressed cache-file, so we should not
|
|
// report the compressed file name to the client.
|
|
_fFilenameReported = TRUE;
|
|
|
|
if (pwzStr)
|
|
{
|
|
delete pwzStr;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef TEST_STACK_FILTER_ONE
|
|
//test for stackable filter..
|
|
//need to include mft.hxx for sample implementation of the filter
|
|
{
|
|
IOInetProtocol* pFilter = (IOInetProtocol*) new CMft;
|
|
IOInetProtocolSink* pFilterSink = NULL;
|
|
pFilter->QueryInterface(
|
|
IID_IOInetProtocolSink, (void**)&pFilterSink);
|
|
|
|
// connect the last filter sink with pFilter's Sink
|
|
HRESULT hr2 = NOERROR;
|
|
hr2 = _pEmbdFilter->SwitchSink(pFilterSink);
|
|
|
|
if( hr2 == NOERROR )
|
|
{
|
|
hr = _pEmbdFilter->StackFilter(NULL, pFilter, NULL, NULL);
|
|
}
|
|
|
|
// this object gets created here, pFilter gets AddRef'd during
|
|
// the StackFilter(), we should release the additional Ref Count
|
|
// here
|
|
// this does not apply to the first filter stacked
|
|
if( _pEmbdFilter->FilterStacked() > 1 )
|
|
{
|
|
pFilter->Release();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef TEST_STACK_FILTER_TWO
|
|
{
|
|
// another one...
|
|
IOInetProtocol* pFilter_2 = (IOInetProtocol*) new CMft;
|
|
IOInetProtocolSink* pFilterSink_2 = NULL;
|
|
pFilter_2->QueryInterface(
|
|
IID_IOInetProtocolSink, (void**)&pFilterSink_2);
|
|
|
|
// connect the last filter sink with pFilter's Sink
|
|
HRESULT hr3 = NOERROR;
|
|
hr3 = _pEmbdFilter->SwitchSink(pFilterSink_2);
|
|
|
|
if( hr3 == NOERROR )
|
|
{
|
|
hr = _pEmbdFilter->StackFilter(NULL, pFilter_2, NULL, NULL);
|
|
}
|
|
|
|
// this object gets created here, pFilter gets AddRef'd during
|
|
// the StackFilter(), we should release the additional Ref Count
|
|
// here
|
|
// this does not apply to the first filter stacked
|
|
if( _pEmbdFilter->FilterStacked() > 1 )
|
|
{
|
|
pFilter_2->Release();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (_hrError != INET_E_OK)
|
|
{
|
|
SetINetState(INetState_DONE);
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
PerfDbgLog2(tagCINetHttp, this, "-CINetHttp::QueryHeaderOnResponse (hr:%lx, _cbDataSize:%ld)", hr, _cbDataSize);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::RedirectRequest
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [lpszBuffer] --
|
|
// [pdwBuffSize] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::RedirectRequest(LPSTR lpszBuffer, DWORD *pdwBuffSize, DWORD dwStatus)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::RedirectRequest",
|
|
"this=%#x, %#x, %#x, %d",
|
|
this, lpszBuffer, pdwBuffSize, dwStatus
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::RedirectRequest");
|
|
HRESULT hr = INET_E_DOWNLOAD_FAILURE;
|
|
|
|
char *pszHeader;
|
|
DWORD cbBufferLen;
|
|
BOOL fDeleteBuffer = FALSE;
|
|
BOOL fRet = FALSE;
|
|
|
|
// we assume when we get here that we have recieved a redirection
|
|
// now we are going to see where we need to do the next send
|
|
|
|
cbBufferLen = *pdwBuffSize;
|
|
|
|
if (cbBufferLen <= strlen(vszLocationTag))
|
|
{
|
|
goto End;
|
|
}
|
|
strcpy(lpszBuffer, vszLocationTag);
|
|
|
|
fRet = HttpQueryInfo(_hRequest, HTTP_QUERY_RAW_HEADERS, lpszBuffer,&cbBufferLen, NULL);
|
|
|
|
if (!fRet)
|
|
{
|
|
DWORD dwError = GetLastError();
|
|
|
|
if (dwError == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
lpszBuffer = new char[cbBufferLen];
|
|
if (!lpszBuffer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto End;
|
|
}
|
|
fDeleteBuffer = TRUE;
|
|
fRet = HttpQueryInfo(_hRequest, HTTP_QUERY_RAW_HEADERS, lpszBuffer, &cbBufferLen, NULL);
|
|
dwError = GetLastError();
|
|
}
|
|
}
|
|
|
|
if (fRet)
|
|
{
|
|
LPSTR pszRedirect = 0;
|
|
pszHeader = FindTagInHeader(lpszBuffer, vszLocationTag);
|
|
if (!pszHeader)
|
|
{
|
|
goto End;
|
|
}
|
|
|
|
//Bug 21294: 204 responses sometimes have Location: headers, which may not mean redirects.
|
|
//To prevent a bogus redirection message, ensure that the comparison with wininet's url
|
|
//is made after stripping username and password from the original url, since wininet returns
|
|
//the url without these.
|
|
//Don't make this check if it's one of the 3** or username/password not in url.
|
|
if ((dwStatus < HTTP_STATUS_AMBIGUOUS) &&
|
|
(_pszUserName[0] || _pszPassword[0]))
|
|
{
|
|
CHAR* szUrlmonUrl = new CHAR[INTERNET_MAX_URL_LENGTH];
|
|
CHAR* szWininetUrl = new CHAR[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dwUrlmonSize = INTERNET_MAX_URL_LENGTH;
|
|
DWORD dwWininetSize = INTERNET_MAX_URL_LENGTH;
|
|
BOOL bIdentical = FALSE;
|
|
URL_COMPONENTS url;
|
|
|
|
if (!szUrlmonUrl || !szWininetUrl)
|
|
goto deleteUrls;
|
|
|
|
memset(&url, 0, sizeof(URL_COMPONENTS));
|
|
|
|
url.dwStructSize = sizeof(url);
|
|
url.lpszScheme = _pszProtocol;
|
|
url.lpszHostName = _pszServerName;
|
|
url.lpszUrlPath = _pszObject;
|
|
url.nPort = _ipPort;
|
|
|
|
if (InternetCreateUrl(&url, 0, szUrlmonUrl, &dwUrlmonSize) &&
|
|
InternetQueryOption(_hRequest, INTERNET_OPTION_URL, szWininetUrl, &dwWininetSize))
|
|
{
|
|
if ((dwUrlmonSize == dwWininetSize)
|
|
&& !strcmp(szUrlmonUrl, szWininetUrl))
|
|
{
|
|
bIdentical = TRUE;
|
|
}
|
|
|
|
DEBUG_ENTER((DBG_APP,
|
|
Bool,
|
|
"CINetHttp::RedirectRequestComparison",
|
|
"this=%#x, %.80q, %d, %.80q, %d",
|
|
this, szUrlmonUrl, dwUrlmonSize, szWininetUrl, dwWininetSize
|
|
));
|
|
|
|
DEBUG_LEAVE(bIdentical);
|
|
}
|
|
|
|
deleteUrls:
|
|
if (szUrlmonUrl)
|
|
delete [] szUrlmonUrl;
|
|
if (szWininetUrl)
|
|
delete [] szWininetUrl;
|
|
|
|
if (bIdentical)
|
|
goto End;
|
|
}
|
|
|
|
if (dwStatus < HTTP_STATUS_AMBIGUOUS)
|
|
{
|
|
//Bug 33662: Location: headers are only allowed to be absolute URIs
|
|
//check for relative URI and, if found, pretend doesn't exist for 2** status codes.
|
|
|
|
char* pszHostname = new char[MAX_URL_SIZE];
|
|
DWORD dwHostname = MAX_URL_SIZE;
|
|
HRESULT hrTemp;
|
|
|
|
if (!pszHostname)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto End;
|
|
}
|
|
hrTemp = UrlGetPartA(pszHeader + strlen(vszLocationTag), pszHostname, &dwHostname, URL_PART_HOSTNAME, 0);
|
|
|
|
delete [] pszHostname;
|
|
|
|
if (FAILED(hrTemp))
|
|
{
|
|
//this is a relative URI since hostname couldn't be found.
|
|
//hr remains INET_E_DOWNLOAD_FAILURE
|
|
goto End;
|
|
}
|
|
}
|
|
|
|
//
|
|
// _pszPartURL get allocated here!
|
|
//
|
|
if( _pszPartURL )
|
|
{
|
|
delete [] _pszPartURL;
|
|
_pszPartURL = NULL;
|
|
}
|
|
|
|
DWORD dwPartUrlLen = strlen( (pszHeader + strlen(vszLocationTag) ) );
|
|
if( dwPartUrlLen > MAX_URL_SIZE)
|
|
{
|
|
hr = INET_E_DOWNLOAD_FAILURE;
|
|
goto End;
|
|
}
|
|
|
|
_pszPartURL = new char[dwPartUrlLen + 1];
|
|
if( !_pszPartURL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto End;
|
|
}
|
|
|
|
strcpy(_pszPartURL, pszHeader + strlen(vszLocationTag));
|
|
|
|
DbgLog1(DEB_PROT|DEB_TRACE, this, "=== CINetHttp::RedirectRequest (Location:%s)", _pszPartURL);
|
|
|
|
_fRedirected = TRUE;
|
|
hr = S_FALSE;
|
|
|
|
if (!ParseUrl())
|
|
{
|
|
pszRedirect = _pszPartURL;
|
|
}
|
|
else
|
|
{
|
|
pszRedirect = _pszFullURL;
|
|
}
|
|
|
|
PProtAssert((pszRedirect));
|
|
ReportResultAndStop(INET_E_REDIRECTING, 0, 0, DupA2W(pszRedirect));
|
|
}
|
|
End:
|
|
if (fDeleteBuffer)
|
|
delete lpszBuffer;
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::RedirectRequest(hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::ErrorHandlingRequest
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [dwstatus] --
|
|
// [szBuffer] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-28-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::ErrorHandlingRequest(DWORD dwStatus, LPSTR szBuffer)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::ErrorHandlingRequest",
|
|
"this=%#x, %#x, %.80q",
|
|
this, dwStatus, szBuffer
|
|
));
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "+CINetHttp::ErrorHandlingRequest (dwStatus:%ld)", dwStatus);
|
|
HRESULT hr = NOERROR;
|
|
|
|
PProtAssert((szBuffer));
|
|
hr = HttpNegOnError(dwStatus,szBuffer);
|
|
|
|
if (hr == E_RETRY)
|
|
{
|
|
_hrINet = NOERROR;
|
|
hr = INetAsyncSendRequest();
|
|
}
|
|
else if (hr == E_ABORT)
|
|
{
|
|
_hrINet = E_ABORT;
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
// the error was not handled - stop download
|
|
_hrINet = hr = HResultFromHttpStatus(dwStatus);
|
|
}
|
|
else
|
|
{
|
|
_hrINet = hr;
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::ErrorHandlingRequest(hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::GetVerb
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-05-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
LPSTR CINetHttp::GetVerb()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
String,
|
|
"CINetHttp::GetVerb",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::GetVerb");
|
|
LPSTR pszRes = vszGet;
|
|
|
|
if (_fRedirected == TRUE)
|
|
{
|
|
// for HTTP 1.1, we have to check if this is an POST->POST redirect
|
|
INTERNET_VERSION_INFO httpVersion;
|
|
DWORD dwBufferSize = sizeof(INTERNET_VERSION_INFO);
|
|
if( InternetQueryOption( _hRequest, INTERNET_OPTION_HTTP_VERSION, &httpVersion, &dwBufferSize )
|
|
&& httpVersion.dwMajorVersion >= 1
|
|
&& httpVersion.dwMinorVersion >= 1 )
|
|
{
|
|
CHAR szVerb[16];
|
|
DWORD dwIndex;
|
|
DWORD dwLength = sizeof(szVerb);
|
|
if( HttpQueryInfo(_hRequest, HTTP_QUERY_REQUEST_METHOD, szVerb, &dwLength, &dwIndex)
|
|
&& !lstrcmp(szVerb, vszPost) )
|
|
{
|
|
// HACK HACK HACK !!
|
|
// Double check the status code to see if this is a real POST
|
|
// there is a HttpQueryInfo() bug which will send verb=POST
|
|
// on a POST->GET Redirect
|
|
//
|
|
|
|
DWORD dwStatus = 0;
|
|
if ( HttpQueryInfo(
|
|
_hRequest,
|
|
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
|
|
&dwStatus ,&dwLength, NULL)
|
|
&& dwStatus == HTTP_STATUS_REDIRECT_KEEP_VERB )
|
|
{
|
|
_fP2PRedirected = TRUE;
|
|
pszRes = vszPost;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BINDINFO *pBndInfo = GetBindInfo();
|
|
|
|
if (pBndInfo)
|
|
{
|
|
switch (pBndInfo->dwBindVerb)
|
|
{
|
|
case BINDVERB_GET :
|
|
pszRes = vszGet;
|
|
break;
|
|
case BINDVERB_POST :
|
|
pszRes = vszPost;
|
|
break;
|
|
case BINDVERB_PUT :
|
|
pszRes = vszPut;
|
|
break;
|
|
case BINDVERB_CUSTOM :
|
|
{
|
|
//BUGBUG: custom verb support
|
|
if (!_pszVerb && pBndInfo->szCustomVerb)
|
|
{
|
|
pszRes = _pszVerb = DupW2A(pBndInfo->szCustomVerb);
|
|
}
|
|
else if(_pszVerb)
|
|
{
|
|
pszRes = _pszVerb;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::GetVerb (szRes:%s)", pszRes);
|
|
|
|
DEBUG_LEAVE(pszRes);
|
|
return pszRes;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::GetAdditionalHeader
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [ppszRes] --
|
|
// [pdwSize] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-05-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::GetAdditionalHeader()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::GetAdditionalHeader",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::GetAdditionalHeader");
|
|
|
|
DWORD dwSizeData = 0;
|
|
DWORD dwSizeHeader = 0;
|
|
LPSTR szLocal;
|
|
|
|
szLocal = g_pszUAInfoString;
|
|
|
|
dwSizeHeader += strlen(szLocal);
|
|
|
|
ULONG dwSizeEncHeader = 0;
|
|
|
|
PProtAssert((_pOIBindInfo));
|
|
// only send Accept-Encoding header with HTTP 1.1 or higher
|
|
INTERNET_VERSION_INFO httpVersion;
|
|
DWORD dwBufferSize = sizeof(INTERNET_VERSION_INFO);
|
|
if( _hRequest
|
|
&& _pOIBindInfo
|
|
&& InternetQueryOption( _hRequest, INTERNET_OPTION_HTTP_VERSION, &httpVersion, &dwBufferSize )
|
|
&& httpVersion.dwMajorVersion >= 1
|
|
&& httpVersion.dwMinorVersion >= 1 )
|
|
{
|
|
dwSizeEncHeader = 1;
|
|
dwSizeHeader += strlen(gszAcceptEncHeaders);
|
|
}
|
|
|
|
// delete the old header and allocate a new buffer
|
|
if (_pszHeader)
|
|
{
|
|
delete _pszHeader;
|
|
_pszHeader = 0;
|
|
}
|
|
|
|
if (dwSizeHeader || dwSizeEncHeader)
|
|
{
|
|
_pszHeader = new CHAR [dwSizeHeader + 1];
|
|
}
|
|
|
|
if (_pszHeader)
|
|
{
|
|
if (szLocal && szLocal[0] != 0)
|
|
{
|
|
strcat(_pszHeader, szLocal);
|
|
}
|
|
|
|
if( dwSizeEncHeader)
|
|
{
|
|
strcat(_pszHeader, gszAcceptEncHeaders);
|
|
}
|
|
}
|
|
|
|
PerfDbgLog2(tagCINetHttp, this, "-CINetHttp::GetAdditionalHeader (pStr:>%s<, hr:%lx)", XDBG(_pszHeader,""), NOERROR);
|
|
|
|
DEBUG_LEAVE(NOERROR);
|
|
return NOERROR;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::GetDataToSend
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [ppBuffer] --
|
|
// [pdwSize] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-05-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::GetDataToSend(LPVOID *ppBuffer, DWORD *pdwSize)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::GetDataToSend",
|
|
"this=%#x, %#x, %#x",
|
|
this, ppBuffer, pdwSize
|
|
));
|
|
|
|
HRESULT hr = INET_E_DOWNLOAD_FAILURE;
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::GetDataToSend");
|
|
|
|
*ppBuffer = NULL;
|
|
*pdwSize = 0;
|
|
BINDINFO *pBndInfo = GetBindInfo();
|
|
|
|
if (pBndInfo)
|
|
{
|
|
switch (pBndInfo->dwBindVerb)
|
|
{
|
|
default:
|
|
case BINDVERB_CUSTOM :
|
|
case BINDVERB_POST :
|
|
case BINDVERB_PUT :
|
|
{
|
|
if (pBndInfo->stgmedData.tymed == TYMED_HGLOBAL)
|
|
{
|
|
*ppBuffer = pBndInfo->stgmedData.hGlobal;
|
|
*pdwSize = pBndInfo->cbstgmedData;
|
|
hr = NOERROR;
|
|
}
|
|
}
|
|
break;
|
|
case BINDVERB_GET :
|
|
// nothing should be uploaded
|
|
break;
|
|
}
|
|
}
|
|
|
|
PerfDbgLog3(tagCINetHttp, this, "-CINetHttp::GetDataToSend (pBuffer:%lx, dwSize:%ld, hr:%lx)", *ppBuffer, *pdwSize, hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CINetHttp::HttpNegGetRootSecurityId()
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
BYTE bRootSID[MAX_SIZE_SECURITY_ID];
|
|
|
|
if (_pbRootSecurityId == NULL)
|
|
{
|
|
if (_pHttpNeg2 == NULL)
|
|
{
|
|
/*
|
|
if (_pHttpNeg == NULL)
|
|
hr = QueryService(IID_IHttpNegotiate, (void **) &_pHttpNeg);
|
|
|
|
if (!_pHttpNeg || (hr != NOERROR))
|
|
goto End;
|
|
*/
|
|
hr = QueryService(IID_IHttpNegotiate2, (void **) &_pHttpNeg2);
|
|
if (!_pHttpNeg2)
|
|
{
|
|
_pbRootSecurityId = INVALID_P_ROOT_SECURITY_ID;
|
|
goto End;
|
|
}
|
|
}
|
|
|
|
_cbRootSecurityId = MAX_SIZE_SECURITY_ID;
|
|
hr = _pHttpNeg2->GetRootSecurityId( bRootSID, &_cbRootSecurityId, 0 );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
_pbRootSecurityId = INVALID_P_ROOT_SECURITY_ID;
|
|
goto End;
|
|
}
|
|
|
|
if (_cbRootSecurityId <= 0)
|
|
goto End;
|
|
|
|
_pbRootSecurityId = new BYTE[_cbRootSecurityId];
|
|
if (!_pbRootSecurityId)
|
|
goto End;
|
|
|
|
memcpy (_pbRootSecurityId, bRootSID, _cbRootSecurityId);
|
|
}
|
|
|
|
End:
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::HttpNegBeginningTransaction
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [szURL] --
|
|
// [DWORD] --
|
|
// [dwReserved] --
|
|
// [pszAdditionalHeaders] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-08-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HttpNegBeginningTransaction()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HttpNegBeginningTransaction",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HttpNegBeginningTransaction");
|
|
HRESULT hr = NOERROR;
|
|
LPWSTR pwzAddHeaders = NULL;
|
|
|
|
if (_pHttpNeg == NULL)
|
|
{
|
|
hr = QueryService(IID_IHttpNegotiate, (void **) &_pHttpNeg);
|
|
}
|
|
if (_pHttpNeg && (hr == NOERROR))
|
|
{
|
|
LPWSTR pwzUrl = GetUrl();
|
|
LPWSTR pwzHeaders = NULL;
|
|
DWORD dwlen = 0;
|
|
if (_pszHeader)
|
|
{
|
|
dwlen = strlen(_pszHeader);
|
|
pwzHeaders = new WCHAR [dwlen +1];
|
|
if (pwzHeaders == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto End;
|
|
|
|
}
|
|
A2W(_pszHeader, pwzHeaders,dwlen + 1);
|
|
|
|
}
|
|
|
|
PProtAssert((pwzUrl));
|
|
hr = _pHttpNeg->BeginningTransaction(pwzUrl, pwzHeaders, NULL, &pwzAddHeaders);
|
|
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
if (pwzAddHeaders)
|
|
{
|
|
// add the additional length
|
|
dwlen += wcslen(pwzAddHeaders) * sizeof(WCHAR);
|
|
}
|
|
|
|
if (dwlen)
|
|
{
|
|
|
|
if (_pszSendHeader)
|
|
{
|
|
if (strlen(_pszSendHeader) < (dwlen + 1))
|
|
{
|
|
// delete the old header
|
|
delete _pszSendHeader;
|
|
// allocate a new one
|
|
_pszSendHeader = new CHAR [dwlen + 1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_pszSendHeader = new CHAR [dwlen + 1];
|
|
}
|
|
|
|
if (_pszSendHeader)
|
|
{
|
|
if ( pwzAddHeaders )
|
|
{
|
|
W2A(pwzAddHeaders, _pszSendHeader, dwlen + 1);
|
|
|
|
// append the original header
|
|
if (_pszHeader)
|
|
{
|
|
strcat(_pszSendHeader,_pszHeader);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no additional header
|
|
strcpy(_pszSendHeader, _pszHeader);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// delete the wchar header
|
|
if (pwzHeaders)
|
|
{
|
|
delete pwzHeaders;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
PProtAssert((_pHttpNeg == NULL));
|
|
}
|
|
|
|
End:
|
|
|
|
// delete this buffer
|
|
if (pwzAddHeaders)
|
|
{
|
|
delete pwzAddHeaders;
|
|
}
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttp::HttpNegBeginningTransaction");
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::HttpNegOnHeadersAvailable
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [dwResponseCode] --
|
|
// [szHeaders] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-08-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HttpNegOnHeadersAvailable(DWORD dwResponseCode, LPSTR szResponseHeader)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HttpNegOnHeadersAvailable",
|
|
"this=%#x, %#x, %.80q",
|
|
this, dwResponseCode, szResponseHeader
|
|
));
|
|
|
|
PerfDbgLog2(tagCINetHttp, this, "+CINetHttp::HttpNegOnHeadersAvailable (dwResponseCode:%lx) (szResponseHeader:%s)", dwResponseCode, XDBG(szResponseHeader,""));
|
|
HRESULT hr = NOERROR;
|
|
|
|
PProtAssert((szResponseHeader != NULL));
|
|
|
|
if (_pHttpNeg)
|
|
{
|
|
|
|
LPWSTR pwzResponseHeader;
|
|
DWORD dwlen = strlen(szResponseHeader);
|
|
|
|
pwzResponseHeader = new WCHAR [dwlen +1];
|
|
if (pwzResponseHeader == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
PProtAssert((pwzResponseHeader));
|
|
A2W(szResponseHeader, pwzResponseHeader, dwlen + 1);
|
|
if( _pHttpNeg )
|
|
{
|
|
hr = _pHttpNeg->OnResponse(dwResponseCode, pwzResponseHeader,NULL ,NULL);
|
|
}
|
|
|
|
// the only valid return code is NOERROR
|
|
PProtAssert((hr == NOERROR && "HttpNegotiate::OnHeaders returned ivalid hresult"));
|
|
PProtAssert((pwzResponseHeader));
|
|
|
|
delete pwzResponseHeader;
|
|
}
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::HttpNegOnHeadersAvailable (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::HttpNegOnError
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [dwResponseCode] --
|
|
// [szResponseHeaders] --
|
|
// [pszAdditionalRequestHeaders] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-08-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes: return S_FALSE as default - will stop download
|
|
// and map to INET_E hresult
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HttpNegOnError(DWORD dwResponseCode, LPSTR szResponseHeader)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HttpNegOnError",
|
|
"this=%#x, %#x, %.80q",
|
|
this, dwResponseCode, szResponseHeader
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HttpNegOnError");
|
|
HRESULT hr = S_FALSE;
|
|
|
|
PProtAssert((szResponseHeader != NULL));
|
|
|
|
if (_pHttpNeg)
|
|
{
|
|
LPWSTR pwzNewSendHeader = 0;
|
|
LPWSTR pwzSendHeader = 0;
|
|
LPWSTR pwzResponseHeader = 0;
|
|
DWORD dwLenSendHeader = 0;
|
|
DWORD dwLenResponseHeader = 0;
|
|
|
|
if (_pszSendHeader)
|
|
{
|
|
dwLenSendHeader = strlen(_pszSendHeader);
|
|
pwzSendHeader = new WCHAR [dwLenSendHeader + 1];
|
|
}
|
|
|
|
if (pwzSendHeader)
|
|
{
|
|
A2W(_pszSendHeader, pwzSendHeader, dwLenSendHeader + 1);
|
|
}
|
|
|
|
if (szResponseHeader)
|
|
{
|
|
dwLenResponseHeader = strlen(szResponseHeader);
|
|
pwzResponseHeader = new WCHAR [dwLenResponseHeader + 1];
|
|
}
|
|
|
|
if (pwzResponseHeader)
|
|
{
|
|
A2W(szResponseHeader, pwzResponseHeader, dwLenResponseHeader + 1);
|
|
}
|
|
|
|
if( _pHttpNeg )
|
|
{
|
|
hr = _pHttpNeg->OnResponse(dwResponseCode, pwzResponseHeader,pwzSendHeader ,&pwzNewSendHeader);
|
|
}
|
|
|
|
if (pwzSendHeader)
|
|
{
|
|
delete pwzSendHeader;
|
|
pwzSendHeader = 0;
|
|
}
|
|
|
|
if (pwzResponseHeader)
|
|
{
|
|
delete pwzResponseHeader;
|
|
pwzResponseHeader = 0;
|
|
}
|
|
|
|
if ((hr == NOERROR) && (pwzNewSendHeader != NULL))
|
|
{
|
|
LPSTR pszNewSendHeader = 0;
|
|
DWORD dwLen = wcslen(pwzNewSendHeader);
|
|
DWORD dwLen1 = 0;
|
|
if (_pszSendHeader)
|
|
{
|
|
dwLen1 = strlen(_pszSendHeader);
|
|
PProtAssert((dwLen + dwLen1));
|
|
|
|
pszNewSendHeader = new CHAR [dwLen + dwLen1 + 1];
|
|
|
|
if (pszNewSendHeader)
|
|
{
|
|
strcpy(pszNewSendHeader, _pszSendHeader);
|
|
W2A(pwzNewSendHeader,pszNewSendHeader + dwLen1, dwLen + 1);
|
|
|
|
// retry the call
|
|
hr = E_RETRY;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we should not have headers
|
|
PProtAssert((pwzNewSendHeader == NULL));
|
|
if (pwzNewSendHeader)
|
|
{
|
|
delete pwzNewSendHeader;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the error should be mapped to an INET_E hresult
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::HttpNegOnError (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINet::SecurityProblem
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [lpszBuffer] --
|
|
// [pdwBuffSize] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HttpSecurity(DWORD dwProblem)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HttpSecurity",
|
|
"this=%#x, %#x",
|
|
this, dwProblem
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HttpSecurity");
|
|
HRESULT hr = NOERROR;
|
|
HWND hwnd;
|
|
|
|
hr = HttpSecurityProblem(&hwnd, dwProblem);
|
|
|
|
if (hr == NOERROR)
|
|
{
|
|
if (hwnd)
|
|
{
|
|
DWORD dwBindF = GetBindFlags();
|
|
DWORD dwFlags = (FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA );
|
|
|
|
if ((dwBindF & BINDF_NO_UI) || (dwBindF & BINDF_SILENTOPERATION))
|
|
{
|
|
dwFlags |= FLAGS_ERROR_UI_FLAGS_NO_UI;
|
|
}
|
|
|
|
|
|
DWORD dwError;
|
|
|
|
if (SUCCEEDED(ZonesSecurityCheck(hwnd, dwProblem, &dwError)))
|
|
{
|
|
// dwError will be set by ZonesSecurityCheck.
|
|
}
|
|
else
|
|
{
|
|
dwError = InternetErrorDlg(hwnd, _hRequest, dwProblem, dwFlags,NULL);
|
|
}
|
|
|
|
switch (dwError)
|
|
{
|
|
case ERROR_CANCELLED :
|
|
_hrINet = hr = E_ABORT;
|
|
break;
|
|
|
|
case ERROR_SUCCESS :
|
|
_hrINet = hr = E_RETRY;
|
|
break;
|
|
|
|
default:
|
|
_hrINet = hr = E_ABORT;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = INET_E_SECURITY_PROBLEM;
|
|
}
|
|
}
|
|
else if (hr == E_ABORT)
|
|
{
|
|
_hrINet = E_ABORT;
|
|
}
|
|
|
|
if (hr == E_RETRY)
|
|
{
|
|
_hrINet = NOERROR;
|
|
hr = INetAsyncSendRequest();
|
|
}
|
|
else if (hr == E_ABORT)
|
|
{
|
|
_hrINet = E_ABORT;
|
|
}
|
|
else if (hr != NOERROR )
|
|
{
|
|
// set the error to access denied
|
|
_hrINet = hr = INET_E_SECURITY_PROBLEM;
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::HttpSecurity(hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINet::ZonesSecurityCheck
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [hwnd] --
|
|
// [dwProblem] --
|
|
// [pdwError] --
|
|
//
|
|
// Returns: SUCCESS if it was able to decide the action, INET_E_DEFAULT_ACTION otherwise.
|
|
//
|
|
// History: 8-14-97 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CINetHttp::ZonesSecurityCheck(HWND hWnd, DWORD dwProblem, DWORD *pdwError)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::ZonesSecurityCheck",
|
|
"this=%#x, %#x, %#x, %#x",
|
|
this, hWnd, dwProblem, pdwError
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HttpSecurity");
|
|
HRESULT hr = INET_E_DEFAULT_ACTION;
|
|
|
|
if (pdwError == NULL)
|
|
{
|
|
TransAssert(FALSE);
|
|
|
|
DEBUG_LEAVE(E_INVALIDARG);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Right now the only error we check for is the redirect confirmation error.
|
|
if (dwProblem == ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION ||
|
|
dwProblem == ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR)
|
|
{
|
|
IInternetSecurityManager *pSecMgr = NULL;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_InternetSecurityManager, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_IInternetSecurityManager, (void **)&pSecMgr)))
|
|
{
|
|
char szUrl[MAX_URL_SIZE];
|
|
WCHAR wzUrl[MAX_URL_SIZE];
|
|
DWORD cbLen = MAX_URL_SIZE;
|
|
DWORD dwPolicy;
|
|
|
|
TransAssert(pSecMgr != NULL);
|
|
|
|
InternetQueryOption(_hRequest, INTERNET_OPTION_URL, szUrl, &cbLen);
|
|
|
|
// First check if the redirect is to the same server. If that is the
|
|
// case we don't need to warn because we already did the first time around.
|
|
|
|
if (dwProblem == ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION)
|
|
{
|
|
URL_COMPONENTS uc = { 0 };
|
|
|
|
uc.dwStructSize = sizeof(uc);
|
|
uc.dwHostNameLength = 1; // So we get back the host name.
|
|
|
|
if ( InternetCrackUrl(szUrl, 0, 0, &uc) &&
|
|
(StrCmpNI(uc.lpszHostName, GetServerName(), uc.dwHostNameLength) == 0)
|
|
)
|
|
{
|
|
*pdwError = ERROR_SUCCESS;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if (hr == INET_E_DEFAULT_ACTION)
|
|
{
|
|
// Convert to widechar so we can call the security manager.
|
|
MultiByteToWideChar(CP_ACP, 0, szUrl, -1, wzUrl, MAX_URL_SIZE);
|
|
|
|
PARSEDURL pu;
|
|
pu.cbSize = sizeof(pu);
|
|
|
|
DWORD dwPUAflags = (GetBindFlags() & BINDF_ENFORCERESTRICTED) ? PUAF_ENFORCERESTRICTED : 0;
|
|
|
|
if (SUCCEEDED(ParseURLA(szUrl, &pu)) && pu.nScheme == URL_SCHEME_HTTPS)
|
|
{
|
|
// The forms submit zones policies are only supposed to apply to
|
|
// unencrypted posts. We will allow these to be posted silently.
|
|
*pdwError = ERROR_SUCCESS;
|
|
hr = S_OK ;
|
|
}
|
|
else if (SUCCEEDED(pSecMgr->ProcessUrlAction(wzUrl, URLACTION_HTML_SUBMIT_FORMS_TO,
|
|
(BYTE *)&dwPolicy, sizeof(dwPolicy), NULL, 0, dwPUAflags | PUAF_NOUI, 0)))
|
|
{
|
|
DWORD dwPermissions = GetUrlPolicyPermissions(dwPolicy);
|
|
// If it is allow or deny don't call InternetErrorDlg, unless it is a encrypted to
|
|
// unencrypted redir in which case we still need to warn the user..
|
|
if (dwPermissions == URLPOLICY_ALLOW && dwProblem != ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR)
|
|
{
|
|
*pdwError = ERROR_SUCCESS;
|
|
hr = S_OK;
|
|
}
|
|
else if (dwPermissions == URLPOLICY_DISALLOW)
|
|
{
|
|
*pdwError = ERROR_CANCELLED;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
pSecMgr->Release();
|
|
}
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::ZonesSecurityCheck(hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::HttpSecurityProblem
|
|
//
|
|
// Synopsis: QI's for HttpSecurity or IWindow
|
|
//
|
|
// Arguments: [phwnd] -- window handle for security dialog
|
|
//
|
|
// Returns: S_OK if dialog should be displayed
|
|
//
|
|
// History: 2-08-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HttpSecurityProblem(HWND* phwnd, DWORD dwProblem)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HttpSecurityProblem",
|
|
"this=%#x, %#x, %#x",
|
|
this, phwnd, dwProblem
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HttpSecurityProblem");
|
|
HRESULT hr = NOERROR;
|
|
*phwnd = 0;
|
|
|
|
if (_pHttSecurity == NULL)
|
|
{
|
|
hr = QueryService(IID_IHttpSecurity, (void **) &_pHttSecurity);
|
|
}
|
|
|
|
if ((hr == NOERROR) && _pHttSecurity)
|
|
{
|
|
hr = _pHttSecurity->OnSecurityProblem(dwProblem);
|
|
if (hr == S_OK)
|
|
{
|
|
// client wants to continue
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
// client does not care
|
|
hr = _pHttSecurity->GetWindow(IID_IHttpSecurity, phwnd);
|
|
UrlMkAssert(( ((hr == S_FALSE) && (*phwnd == NULL))
|
|
|| ((hr == NOERROR) && (*phwnd != NULL)) ));
|
|
}
|
|
else if (hr != E_ABORT)
|
|
{
|
|
UrlMkAssert((FALSE && "Invalid result on IHttSecurity->OnSecurityProblem"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_pWindow == NULL)
|
|
{
|
|
hr = QueryService(IID_IWindowForBindingUI, (void **) &_pWindow);
|
|
}
|
|
else
|
|
hr = NOERROR; //We need to reset this hr, since we cached _pWindow
|
|
|
|
if ((hr == NOERROR) && _pWindow)
|
|
{
|
|
hr = _pWindow->GetWindow(IID_IHttpSecurity, phwnd);
|
|
UrlMkAssert(( (hr == S_FALSE) && (*phwnd == NULL)
|
|
|| (hr == S_OK) && (*phwnd != NULL)));
|
|
}
|
|
}
|
|
|
|
PerfDbgLog2(tagCINetHttp, this, "-CINetHttp::HttpSecurityProblem (hr:%lx, hwnd:%lx)", hr, *phwnd);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::HResultFromInternetError
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [dwStatus] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 3-22-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::HResultFromHttpStatus(DWORD dwStatus)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::HResultFromHttpStatus",
|
|
"this=%#x, %#x",
|
|
this, dwStatus
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::HResultFromHttpStatus");
|
|
HRESULT hr = NOERROR;
|
|
switch(dwStatus)
|
|
{
|
|
case HTTP_STATUS_OK :
|
|
case HTTP_STATUS_NOT_MODIFIED :
|
|
case HTTP_STATUS_RETRY_WITH :
|
|
hr = NOERROR;
|
|
break;
|
|
|
|
case HTTP_STATUS_NOT_FOUND :
|
|
hr = INET_E_OBJECT_NOT_FOUND;
|
|
break;
|
|
|
|
case HTTP_STATUS_NONE_ACCEPTABLE :
|
|
// comes back if server can not handle mime type
|
|
hr = INET_E_NO_VALID_MEDIA;
|
|
break;
|
|
|
|
case HTTP_STATUS_SERVICE_UNAVAIL :
|
|
hr = INET_E_INVALID_REQUEST;
|
|
break;
|
|
|
|
case HTTP_STATUS_GATEWAY_TIMEOUT :
|
|
case HTTP_STATUS_REQUEST_TIMEOUT :
|
|
hr = INET_E_CONNECTION_TIMEOUT;
|
|
break;
|
|
|
|
case HTTP_STATUS_CREATED :
|
|
case HTTP_STATUS_ACCEPTED :
|
|
case HTTP_STATUS_PARTIAL :
|
|
case HTTP_STATUS_NO_CONTENT :
|
|
case HTTP_STATUS_AMBIGUOUS :
|
|
case HTTP_STATUS_MOVED :
|
|
case HTTP_STATUS_REDIRECT :
|
|
case HTTP_STATUS_REDIRECT_METHOD :
|
|
case HTTP_STATUS_REDIRECT_KEEP_VERB:
|
|
case HTTP_STATUS_BAD_REQUEST :
|
|
case HTTP_STATUS_DENIED :
|
|
case HTTP_STATUS_PAYMENT_REQ :
|
|
case HTTP_STATUS_FORBIDDEN :
|
|
case HTTP_STATUS_BAD_METHOD :
|
|
case HTTP_STATUS_PROXY_AUTH_REQ :
|
|
case HTTP_STATUS_CONFLICT :
|
|
case HTTP_STATUS_GONE :
|
|
case HTTP_STATUS_LENGTH_REQUIRED :
|
|
case HTTP_STATUS_SERVER_ERROR :
|
|
case HTTP_STATUS_NOT_SUPPORTED :
|
|
case HTTP_STATUS_BAD_GATEWAY :
|
|
default:
|
|
//PProtAssert((FALSE && "Mapping Ineternet error to generic hresult!"));
|
|
hr = INET_E_DOWNLOAD_FAILURE;
|
|
DbgLog2(DEB_PROT|DEB_TRACE, this, "=== Mapping Internet error to generic hresult!(dwStatus:%ld, hr:%lx)", dwStatus, hr);
|
|
break;
|
|
}
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::HResultFromHttpStatus (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::Terminate
|
|
//
|
|
// Synopsis: Close the server and request handle - wininet will make a
|
|
// callback on each handle closed
|
|
//
|
|
// Arguments: [dwOptions] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 07-27-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CINetHttp::Terminate(DWORD dwOptions)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::Terminate",
|
|
"this=%#x, %#x",
|
|
this, dwOptions
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttp::Terminate");
|
|
HRESULT hr = NOERROR;
|
|
//PProtAssert(( IsApartmentThread() ));
|
|
|
|
if (_pHttpNeg)
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "=== CINetHttp::Terminate Release on _pHttpNeg (%lx)", _pHttpNeg);
|
|
_pHttpNeg->Release();
|
|
_pHttpNeg = NULL;
|
|
}
|
|
|
|
if (_pHttpNeg2)
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "=== CINetHttp::Terminate Release on _pHttpNeg2 (%lx)", _pHttpNeg2);
|
|
_pHttpNeg2->Release();
|
|
_pHttpNeg2 = NULL;
|
|
}
|
|
|
|
if (_pWindow)
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "+CINetHttp::Terminate Release on _pWindow (%lx)", _pWindow);
|
|
_pWindow->Release();
|
|
_pWindow = NULL;
|
|
}
|
|
|
|
if (_pHttSecurity)
|
|
{
|
|
PerfDbgLog1(tagCINetHttp, this, "+CINetHttp::Terminate Release on _pHttSecurity (%lx)", _pHttSecurity);
|
|
_pHttSecurity->Release();
|
|
_pHttSecurity = NULL;
|
|
}
|
|
|
|
hr = CINet::Terminate(dwOptions);
|
|
|
|
PerfDbgLog1(tagCINetHttp, this, "-CINetHttp::Terminate (hr:%lx)", hr);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttpS::CINetHttpS
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CINetHttpS::CINetHttpS(REFCLSID rclsid, IUnknown *pUnkOuter) : CINetHttp(rclsid,pUnkOuter)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
None,
|
|
"CINetHttpS::CINetHttpS",
|
|
"this=%#x, %#x, %#x",
|
|
this, &rclsid, pUnkOuter
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttpS::CINetHttpS");
|
|
|
|
_dwIsA = DLD_PROTOCOL_HTTPS;
|
|
_dwConnectFlags = INTERNET_FLAG_SECURE;
|
|
_dwOpenFlags = INTERNET_FLAG_SECURE;
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttpS::CINetHttpS");
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttpS::~CINetHttpS
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-06-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CINetHttpS::~CINetHttpS()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
None,
|
|
"CINetHttpS::~CINetHttpS",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "+CINetHttpS::~CINetHttpS");
|
|
|
|
PerfDbgLog(tagCINetHttp, this, "-CINetHttpS::~CINetHttpS");
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::INetWrite
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 1-27-96 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::INetWrite()
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::INetWrite",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
TransDebugOut((DEB_PROT, "%p OUT CINetHttp::INetWrite\n", this));
|
|
HRESULT hr = NOERROR;
|
|
|
|
BOOL fRet;
|
|
DWORD dwSendFlags = HSR_CHUNKED | HSR_INITIATE;
|
|
DWORD dwSendContext = 0;
|
|
|
|
// If our caller gave us a TYMED_ISTREAM, then we need to pick it up
|
|
// now.
|
|
if (!_pStm)
|
|
{
|
|
BINDINFO *pBI = GetBindInfo();
|
|
if (pBI && pBI->stgmedData.tymed == TYMED_ISTREAM)
|
|
{
|
|
_pStm = pBI->stgmedData.pstm;
|
|
}
|
|
}
|
|
|
|
TransAssert((_pStm));
|
|
if( _fSendAgain && _pStm )
|
|
{
|
|
LARGE_INTEGER li;
|
|
li.LowPart = 0;
|
|
li.HighPart = 0;
|
|
hr = _pStm->Seek(li, STREAM_SEEK_SET, NULL);
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
_fSendEnd = FALSE;
|
|
}
|
|
else
|
|
{
|
|
_fCompleted = TRUE;
|
|
}
|
|
|
|
_fSendAgain = FALSE;
|
|
}
|
|
|
|
// loop until pending
|
|
if (_fSendEnd)
|
|
{
|
|
_hrError = INET_E_DONE;
|
|
}
|
|
else do
|
|
{
|
|
_dwBytesSent = 0;
|
|
|
|
SetStatePending(E_PENDING);
|
|
|
|
hr = GetNextSendBuffer(&_inetBufferSend,_pStm);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
// end of stream
|
|
_fCompleted = TRUE;
|
|
}
|
|
|
|
if (!_fCompleted)
|
|
{
|
|
if (_inetBufferSend.dwBufferLength)
|
|
{
|
|
fRet = InternetWriteFile(
|
|
_hRequest //IN HINTERNET hFile,
|
|
,_inetBufferSend.lpvBuffer //IN LPCVOID lpBuffer,
|
|
,_inetBufferSend.dwBufferLength //IN DWORD dwNumberOfBytesToWrite,
|
|
,&_dwBytesSent //OUT LPDWORD lpdwNumberOfBytesWritten
|
|
);
|
|
}
|
|
else
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fRet = HttpEndRequestA(
|
|
_hRequest //IN HINTERNET hRequest,
|
|
,NULL
|
|
,dwSendFlags //IN DWORD dwFlags,
|
|
,dwSendContext //IN DWORD dwContext
|
|
|
|
);
|
|
|
|
_fSendEnd = TRUE;
|
|
}
|
|
|
|
//PerfDbgLog(tagCINetHttp, this, "-CINetHttp::INetAsyncSendRequest HttpSendRequest");
|
|
|
|
if (fRet == FALSE)
|
|
{
|
|
DWORD dwLstError = GetLastError();
|
|
if (dwLstError == ERROR_IO_PENDING)
|
|
{
|
|
// wait async for the handle
|
|
hr = E_PENDING;
|
|
}
|
|
else
|
|
{
|
|
SetStatePending(NOERROR);
|
|
hr = _hrError = INET_E_DOWNLOAD_FAILURE;
|
|
SetBindResult(dwLstError,hr);
|
|
//PerfDbgLog3(tagCINetHttp, this, "CINetHttp::INetAsyncSendRequest (fRet:%d, _hrError:%lx, LstError:%ld)", fRet, _hrError, dwLstError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetStatePending(NOERROR);
|
|
}
|
|
|
|
} while ((fRet == TRUE) && (_fCompleted == FALSE));
|
|
|
|
if (_hrError != INET_E_OK)
|
|
{
|
|
// we need to terminate here
|
|
ReportResultAndStop((_hrError == INET_E_DONE) ? NOERROR : _hrError);
|
|
}
|
|
|
|
TransDebugOut((DEB_PROT, "%p OUT CINetHttp::INetWrite (hr:%lx)\n", this, hr));
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CINetHttp::GetNextSendBuffer
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pIB] --
|
|
// [pStm] --
|
|
// [fFirst] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 4-28-1997 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CINetHttp::GetNextSendBuffer(INTERNET_BUFFERS *pIB, IStream *pStm, BOOL fFirst)
|
|
{
|
|
DEBUG_ENTER((DBG_APP,
|
|
Hresult,
|
|
"CINetHttp::GetNextSendBuffer",
|
|
"this=%#x, %#x, %#x, %B",
|
|
this, pIB, pStm, fFirst
|
|
));
|
|
|
|
TransDebugOut((DEB_PROT, "%p OUT CINetHttp::GetNextSendBuffer\n", this));
|
|
HRESULT hr = NOERROR;
|
|
|
|
TransAssert(pIB);
|
|
|
|
do
|
|
{
|
|
BINDINFO *pBndInfo = GetBindInfo();
|
|
DWORD dwBufferFilled = 0;
|
|
|
|
if (!pStm)
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (!fFirst)
|
|
{
|
|
TransAssert((_pBuffer));
|
|
hr = pStm->Read(_pBuffer, _dwBufferSize, &dwBufferFilled);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
else if (!dwBufferFilled)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LARGE_INTEGER li;
|
|
li.LowPart = 0;
|
|
li.HighPart = 0;
|
|
|
|
// We do not need to addref this here
|
|
pStm->Seek(li, STREAM_SEEK_SET, NULL);
|
|
|
|
if( !_pBuffer )
|
|
{
|
|
_pBuffer = new char [SENDBUFFER_MAX];
|
|
|
|
if (!_pBuffer)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
_dwBufferSize = SENDBUFFER_MAX;
|
|
}
|
|
}
|
|
|
|
pIB->dwStructSize = sizeof (INTERNET_BUFFERSA);
|
|
pIB->Next = 0;
|
|
pIB->lpcszHeader = (fFirst) ? _pszSendHeader : 0;
|
|
pIB->dwHeadersLength = (fFirst) ? ((_pszSendHeader) ? (ULONG)-1L : 0L) : 0;
|
|
pIB->dwHeadersTotal = (fFirst) ? ((_pszSendHeader) ? (ULONG)-1L : 0L) : 0;
|
|
pIB->lpvBuffer = (fFirst) ? 0 : _pBuffer;
|
|
pIB->dwBufferLength = (fFirst) ? 0 : dwBufferFilled;
|
|
pIB->dwBufferTotal = (fFirst) ? pBndInfo->cbstgmedData : 0; // :_dwBufferSize;
|
|
pIB->dwOffsetLow = 0;
|
|
pIB->dwOffsetHigh = 0;
|
|
|
|
break;
|
|
} while (TRUE);
|
|
|
|
TransDebugOut((DEB_PROT, "%p OUT CINetHttp::GetNextSendBuffer (hr:%lx)\n", this, hr));
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
|