Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

540 lines
17 KiB

/*****************************************************************************\
* MODULE: anycon.cxx
*
* The module contains the base class for connections
*
* Copyright (C) 1997-1998 Microsoft Corporation
*
* History:
* 07/31/98 Weihaic Created
*
\*****************************************************************************/
#include "precomp.h"
#include "priv.h"
/******************************************************************************
* Class Data Static Members
*****************************************************************************/
const DWORD CAnyConnection::gm_dwConnectTimeout = 30000; // Thirty second timeout on connect
const DWORD CAnyConnection::gm_dwSendTimeout = 30000; // Thirty timeout on send timeout
const DWORD CAnyConnection::gm_dwReceiveTimeout = 60000; // Thirty seconds on receive timeout
const DWORD CAnyConnection::gm_dwSendSize = 0x10000; // We use a 16K sections when sending
// data through WININET
extern BOOL Ping (LPTSTR pszServerName);
CAnyConnection::CAnyConnection (
BOOL bSecure,
INTERNET_PORT nServerPort,
BOOL bIgnoreSecurityDlg,
DWORD dwAuthMethod):
m_lpszPassword (NULL),
m_lpszUserName (NULL),
m_hSession (NULL),
m_hConnect (NULL),
m_dwAccessFlag (INTERNET_OPEN_TYPE_PRECONFIG),
m_bSecure (bSecure),
m_bShowSecDlg (FALSE),
m_dwAuthMethod (dwAuthMethod),
m_bIgnoreSecurityDlg (bIgnoreSecurityDlg),
m_bValid (FALSE)
{
if (!nServerPort) {
if (bSecure) {
m_nServerPort = INTERNET_DEFAULT_HTTPS_PORT;
}
else {
m_nServerPort = INTERNET_DEFAULT_HTTP_PORT;
}
}
else
m_nServerPort = nServerPort;
m_bValid = TRUE;
}
CAnyConnection::~CAnyConnection ()
{
if (m_hConnect) {
(void) CAnyConnection::Disconnect ();
}
if (m_hSession) {
(void) CAnyConnection::CloseSession ();
}
LocalFree (m_lpszPassword);
m_lpszPassword = NULL;
LocalFree (m_lpszUserName);
m_lpszUserName = NULL;
}
HINTERNET
CAnyConnection::OpenSession ()
{
m_hSession = InetInternetOpen(g_szUserAgent,
m_dwAccessFlag,
NULL,
NULL,
0);
if (m_hSession) { // Set up the callback function if successful
// Also set an internet connection timeout for the session for when we try the
// connection, should we do this instead of a ping?
DWORD dwTimeout = gm_dwConnectTimeout;
if (!InetInternetSetOption( m_hSession,
INTERNET_OPTION_CONNECT_TIMEOUT,
(LPVOID)&dwTimeout,
sizeof(dwTimeout)
))
goto Cleanup;
// Now set the Send and Receive Timeout values
dwTimeout = gm_dwSendTimeout;
if (!InetInternetSetOption( m_hSession,
INTERNET_OPTION_SEND_TIMEOUT,
(LPVOID)&dwTimeout,
sizeof(dwTimeout)
))
goto Cleanup;
dwTimeout = gm_dwReceiveTimeout;
if (!InetInternetSetOption( m_hSession,
INTERNET_OPTION_RECEIVE_TIMEOUT,
(LPVOID)&dwTimeout,
sizeof(dwTimeout)
))
goto Cleanup;
}
return m_hSession;
Cleanup:
if (m_hSession) {
InetInternetCloseHandle (m_hSession);
m_hSession = NULL;
}
return m_hSession;
}
BOOL CAnyConnection::CloseSession ()
{
BOOL bRet = InetInternetCloseHandle (m_hSession);
m_hSession = NULL;
return bRet;
}
HINTERNET
CAnyConnection::Connect(
LPTSTR lpszServerName)
{
if (m_hSession) {
// Ping the server if it is in the intranet to make sure that the server is online
if (lpszServerName &&
(_tcschr ( lpszServerName, TEXT ('.')) || Ping (lpszServerName) )) {
m_hConnect = InetInternetConnect(m_hSession,
lpszServerName,
m_nServerPort,
NULL,//m_lpszUserName,
NULL, //m_lpszPassword,
INTERNET_SERVICE_HTTP,
0,
0);
}
}
return m_hConnect;
}
BOOL
CAnyConnection::Disconnect ()
{
BOOL bRet = InetInternetCloseHandle (m_hConnect);
m_hConnect = NULL;
return bRet;
}
HINTERNET
CAnyConnection::OpenRequest (
LPTSTR lpszUrl)
{
HINTERNET hReq = NULL;
DWORD dwFlags;
if (m_hConnect) {
// We need to create an Asynchronous Context for the Rest of the operations to use,
// passing this in of course makes this request also asynchronous
hReq = InetHttpOpenRequest(m_hConnect,
g_szPOST,
lpszUrl,
g_szHttpVersion,
NULL,
NULL,
INETPP_REQ_FLAGS | (m_bSecure? INTERNET_FLAG_SECURE:0),
0);
}
return hReq;
}
BOOL
CAnyConnection::CloseRequest (HINTERNET hReq)
{
//
// We have to close the handle manually, since WININET seems not to be giving us
// an INTERNET_STATUS_HANDLE_CLOSING message
//
BOOL bSuccess;
bSuccess = InetInternetCloseHandle (hReq); // When this handle is closed, the context will be closed
return bSuccess;
}
BOOL
CAnyConnection::SendRequest(
HINTERNET hReq,
LPCTSTR lpszHdr,
DWORD cbData,
LPBYTE pidi)
{
BOOL bRet = FALSE;
CMemStream *pStream;
pStream = new CMemStream (pidi, cbData);
if (pStream && pStream->bValid ()){
bRet = SendRequest (hReq, lpszHdr, pStream);
}
if (pStream) {
delete pStream;
}
return bRet;
}
BOOL CAnyConnection::SendRequest(
HINTERNET hReq,
LPCTSTR lpszHdr,
CStream *pStream)
{
BOOL bRet = FALSE;
DWORD dwStatus;
DWORD cbStatus = sizeof(dwStatus);
BOOL bRetry = FALSE;
DWORD dwRetryCount = 0;
BOOL bShowUI = FALSE;
DWORD cbData;
PBYTE pBuf = NULL;
DWORD cbRead;
if (!pStream->GetTotalSize (&cbData))
return FALSE;
pBuf = new BYTE[gm_dwSendSize];
if (!pBuf)
return FALSE;
#define MAX_RETRY 3
do {
BOOL bSuccess = FALSE;
BOOL bLeave;
if (cbData < gm_dwSendSize) {
if (pStream->Reset() &&
pStream->Read (pBuf, cbData, &cbRead) && cbRead == cbData) {
// If what we want to send is small, we send it with HttpSendRequest and not
// HttpSendRequestEx, this is to wotk around a problem where we get timeouts on
// receive on very small data transactions
bSuccess = InetHttpSendRequest(hReq,
lpszHdr,
(lpszHdr ? (DWORD)-1 : 0),
pBuf,
cbData);
}
} else {
do {
BOOL bSuccessSend;
// The timeout value for the packets applies for an entire session, so, instead of sending in
// one chuck, we have to send in smaller chunks
INTERNET_BUFFERS BufferIn;
bLeave = TRUE;
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
BufferIn.Next = NULL;
BufferIn.lpcszHeader = lpszHdr;
if (lpszHdr)
BufferIn.dwHeadersLength = sizeof(TCHAR)*lstrlen(lpszHdr);
else
BufferIn.dwHeadersLength = 0;
BufferIn.dwHeadersTotal = 1; // There is one header to send
BufferIn.lpvBuffer = NULL; // We defer this to the multiple write side
BufferIn.dwBufferLength = 0; // The total buffer length
BufferIn.dwBufferTotal = cbData; // This is the size of the data we are about to send
BufferIn.dwOffsetLow = 0; // No offset into the buffers
BufferIn.dwOffsetHigh = 0;
// Since we will only ever be sending one request per hReq handle, we can associate
// the context with all of these operations
bSuccess = InetHttpSendRequestEx (hReq,
&BufferIn,
NULL,
0,
0);
if (bSuccess) {
bSuccess = pStream->Reset();
}
DWORD dwBufPos = 0; // This is our current point in the buffer
DWORD dwRemaining = cbData; // These are the number of bytes left to send
bSuccessSend = bSuccess;
while (bSuccess && dwRemaining) { // While we have data to send and the operations are
// successful
DWORD dwWrite = min( dwRemaining, gm_dwSendSize); // The amount to write
DWORD dwWritten; // The amount actually written
if (pStream->Read (pBuf, dwWrite, &cbRead) && cbRead == dwWrite) {
bSuccess = InetInternetWriteFile (hReq, pBuf, dwWrite, &dwWritten);
if (bSuccess) {
bSuccess = dwWritten ? TRUE : FALSE;
dwRemaining -= dwWritten; // Remaining amount decreases by this
dwBufPos += dwWritten; // Advance through the buffer
if (dwWritten != dwWrite) {
// We need to adjust the pointer, since not all the bytes are
// successfully sent to the server
//
bSuccess = pStream->SetPtr (dwBufPos);
}
}
}
else
bSuccess = FALSE;
}
BOOL bEndSuccess = FALSE;
if (bSuccessSend) { // We started the request successfully, so we can end it successfully
bEndSuccess = InetHttpEndRequest (hReq,
NULL,
0,
0);
}
if (!bEndSuccess && GetLastError() == ERROR_INTERNET_FORCE_RETRY)
bLeave = FALSE;
bSuccess = bSuccess && bEndSuccess && bSuccessSend;
} while (!bLeave);
}
if (bSuccess) {
if ( InetHttpQueryInfo(hReq,
HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
&dwStatus,
&cbStatus,
NULL) ) {
switch (dwStatus) {
case HTTP_STATUS_DENIED:
case HTTP_STATUS_PROXY_AUTH_REQ:
SetLastError (ERROR_ACCESS_DENIED);
break;
case HTTP_STATUS_FORBIDDEN:
SetLastError (HTTP_STATUS_FORBIDDEN);
break;
case HTTP_STATUS_OK:
bRet = TRUE;
break;
case HTTP_STATUS_SERVER_ERROR:
DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : HTTP_STATUS_SERVER_ERROR")));
SetLastError (ERROR_INVALID_PRINTER_NAME);
break;
default:
if ((dwStatus >= HTTP_STATUS_BAD_REQUEST) &&
(dwStatus < HTTP_STATUS_SERVER_ERROR)) {
SetLastError(ERROR_INVALID_PRINTER_NAME);
} else {
// We get some other errors, but don't know how to handle it
//
DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : Unknown Error (%d)"), dwStatus));
SetLastError (ERROR_INVALID_HANDLE);
}
break;
}
}
}
else {
if (m_bSecure) {
DWORD dwFlags = 0;
DWORD dwRet;
if (m_bShowSecDlg) {
bShowUI = TRUE;
dwRet = InetInternetErrorDlg (GetTopWindow (NULL),
hReq,
GetLastError(),
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);
if (dwRet == ERROR_SUCCESS || dwRet == ERROR_INTERNET_FORCE_RETRY) {
bRetry = TRUE;
}
}
else {
switch (GetLastError ()) {
case ERROR_INTERNET_INVALID_CA:
dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
break;
default:
// All other failure, try to ignore everything and retry
dwFlags = SECURITY_FLAG_IGNORE_REVOCATION |
SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_WRONG_USAGE |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID|
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS |
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP ;
break;
}
if (InetInternetSetOption(hReq,
INTERNET_OPTION_SECURITY_FLAGS,
&dwFlags,
sizeof (DWORD))) {
bRetry = TRUE;
}
}
}
}
}
while (bRetry && ++dwRetryCount < MAX_RETRY);
if (!bRet && GetLastError () == ERROR_INTERNET_LOGIN_FAILURE)
{
SetLastError (ERROR_ACCESS_DENIED);
}
if (bShowUI) {
// We only show the dialog once.
m_bShowSecDlg = FALSE;
}
if (pBuf) {
delete [] pBuf;
}
return bRet;
}
BOOL CAnyConnection::ReadFile (
HINTERNET hReq,
LPVOID lpvBuffer,
DWORD cbBuffer,
LPDWORD lpcbRd)
{
BOOL bSuccess;
bSuccess = InetInternetReadFile(hReq, lpvBuffer, cbBuffer, lpcbRd);
return bSuccess;
}
BOOL CAnyConnection::SetPassword (
HINTERNET hReq,
LPTSTR lpszUserName,
LPTSTR lpszPassword)
{
BOOL bRet = FALSE;
TCHAR szNULL[] = TEXT ("");
if (!lpszUserName) {
lpszUserName = szNULL;
}
if (!lpszPassword) {
lpszPassword = szNULL;
}
if ( InetInternetSetOption (hReq,
INTERNET_OPTION_USERNAME,
lpszUserName,
(DWORD) (lstrlen(lpszUserName) + 1)) &&
InetInternetSetOption (hReq,
INTERNET_OPTION_PASSWORD,
lpszPassword,
(DWORD) (lstrlen(lpszPassword) + 1)) ) {
bRet = TRUE;
}
return bRet;
}
BOOL CAnyConnection::GetAuthSchem (
HINTERNET hReq,
LPSTR lpszScheme,
DWORD dwSize)
{
DWORD dwIndex = 0;
return InetHttpQueryInfo(hReq, HTTP_QUERY_WWW_AUTHENTICATE, (LPVOID)lpszScheme, &dwSize, &dwIndex);
}
void CAnyConnection::SetShowSecurityDlg (
BOOL bShowSecDlg)
{
m_bShowSecDlg = bShowSecDlg;
}