text: //+---------------------------------------------------------------------------
  //
  //  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;
  }
  
  
  