Exemplo n.º 1
0
void CHttpDownloadDlg::DownloadThread()
{
	ENCODING_INIT;
	//Create the Internet session handle
	ASSERT(m_hInternetSession == NULL);
	m_hInternetSession = ::InternetOpen(AfxGetAppName(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
	if (m_hInternetSession == NULL)
	{
		TRACE(_T("Failed in call to InternetOpen, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_GENERIC_ERROR));
		return;
	}

	//Should we exit the thread
	if (m_bAbort)
	{
		PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
		return;
	}  

	//Setup the status callback function
	if (::InternetSetStatusCallback(m_hInternetSession, _OnStatusCallBack) == INTERNET_INVALID_STATUS_CALLBACK)
	{
		TRACE(_T("Failed in call to InternetSetStatusCallback, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_GENERIC_ERROR));
		return;
	}

	//Should we exit the thread
	if (m_bAbort)
	{
		PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
		return;
	}

	//Make the connection to the HTTP server
	ASSERT(m_hHttpConnection == NULL);
	if (m_sUserName.GetLength())
		// Elandal: Assumes sizeof(void*) == sizeof(unsigned long)
		m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_sUserName, 
                                          m_sPassword, m_dwServiceType, 0, (DWORD) this);
	else
		// Elandal: Assumes sizeof(void*) == sizeof(unsigned long)
		m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, NULL, 
                                          NULL, m_dwServiceType, 0, (DWORD) this);
	if (m_hHttpConnection == NULL)
	{
		TRACE(_T("Failed in call to InternetConnect, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER));
		return;
	}

	//Should we exit the thread
	if (m_bAbort)
	{
		PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
		return;
	}

	//Start the animation to signify that the download is taking place
	PlayAnimation();

	//Issue the request to read the file
	LPCTSTR ppszAcceptTypes[2];
	ppszAcceptTypes[0] = _T("*/*");  //We support accepting any mime file type since this is a simple download of a file
	ppszAcceptTypes[1] = NULL;
	ASSERT(m_hHttpFile == NULL);
	// Elandal: Assumes sizeof(void*) == sizeof(unsigned long)
	m_hHttpFile = HttpOpenRequest(m_hHttpConnection, NULL, m_sObject, NULL, NULL, ppszAcceptTypes, INTERNET_FLAG_RELOAD | 
								  INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_KEEP_CONNECTION, (DWORD)this);
	if (m_hHttpFile == NULL)
	{
		TRACE(_T("Failed in call to HttpOpenRequest, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER));
		return;
	}

	//Should we exit the thread
	if (m_bAbort)
	{
		PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
		return;
	}

	//fill in what encoding we support
	HttpAddRequestHeaders(m_hHttpFile, ACCEPT_ENCODING_HEADER, (DWORD)-1L, HTTP_ADDREQ_FLAG_ADD);

//label used to jump to if we need to resend the request
resend:

	//Issue the request
	BOOL bSend = ::HttpSendRequest(m_hHttpFile, NULL, 0, NULL, 0);
	if (!bSend)
	{
		TRACE(_T("Failed in call to HttpSendRequest, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER));
		return;
	}

	//Check the HTTP status code
	TCHAR szStatusCode[32];
	DWORD dwInfoSize = 32;
	if (!HttpQueryInfo(m_hHttpFile, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwInfoSize, NULL))
	{
		TRACE(_T("Failed in call to HttpQueryInfo for HTTP query status code, Error:%d\n"), ::GetLastError());
		HandleThreadError(GetResString(IDS_HTTPDOWNLOAD_INVALID_SERVER_RESPONSE));
		return;
	}
	else
	{
		long nStatusCode = _ttol(szStatusCode);

		//Handle any authentication errors
		if (nStatusCode == HTTP_STATUS_PROXY_AUTH_REQ || nStatusCode == HTTP_STATUS_DENIED)
		{
			// We have to read all outstanding data on the Internet handle
			// before we can resubmit request. Just discard the data.
			char szData[51];
			DWORD dwSize;
			do
			{
				::InternetReadFile(m_hHttpFile, (LPVOID)szData, 50, &dwSize);
			}
			while (dwSize != 0);

			//Bring up the standard authentication dialog
			if (::InternetErrorDlg(GetSafeHwnd(), m_hHttpFile, ERROR_INTERNET_INCORRECT_PASSWORD, FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
                             FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL) == ERROR_INTERNET_FORCE_RETRY)
				goto resend;
		}
		else if (nStatusCode != HTTP_STATUS_OK)
		{
			TRACE(_T("Failed to retrieve a HTTP 200 status, Status Code:%d\n"), nStatusCode);
			HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_INVALID_HTTP_RESPONSE), nStatusCode);
			return;
		}
	}

	//Check to see if any encodings are supported
	//  ENCODING_QUERY;
	TCHAR szContentEncoding[32];
	DWORD dwEncodeStringSize = 32;
	if(::HttpQueryInfo(m_hHttpFile, HTTP_QUERY_CONTENT_ENCODING, szContentEncoding, &dwEncodeStringSize, NULL))
	{
		if(!_tcsicmp(szContentEncoding, _T("gzip")) || !_tcsicmp(szContentEncoding, _T("x-gzip")))
			bEncodedWithGZIP = TRUE;
	}

	//Update the status control to reflect that we are getting the file information
	SetStatus(GetResString(IDS_HTTPDOWNLOAD_GETTING_FILE_INFORMATION));

	// Get the length of the file.
	TCHAR szContentLength[32];
	dwInfoSize = 32;
	DWORD dwFileSize = 0;
	BOOL bGotFileSize = FALSE;
	if (::HttpQueryInfo(m_hHttpFile, HTTP_QUERY_CONTENT_LENGTH, szContentLength, &dwInfoSize, NULL))
	{
		//Set the progress control range
		bGotFileSize = TRUE;
		dwFileSize = (DWORD) _ttol(szContentLength);
		SetProgressRange(dwFileSize);
	}

	//Update the status to say that we are now downloading the file
	SetStatus(GetResString(IDS_HTTPDOWNLOAD_RETREIVEING_FILE));

	//Now do the actual read of the file
	DWORD dwStartTicks = ::GetTickCount();
	DWORD dwCurrentTicks = dwStartTicks;
	DWORD dwBytesRead = 0;
	char szReadBuf[1024];
	DWORD dwBytesToRead = 1024;
	DWORD dwTotalBytesRead = 0;
	DWORD dwLastTotalBytes = 0;
	DWORD dwLastPercentage = 0;

	PREPARE_DECODER;
	do
	{
		if (!::InternetReadFile(m_hHttpFile, szReadBuf, dwBytesToRead, &dwBytesRead))
		{
			TRACE(_T("Failed in call to InternetReadFile, Error:%d\n"), ::GetLastError());
			HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_ERROR_READFILE));
			return;
		}
		else if (dwBytesRead && !m_bAbort)
		{
			//Write the data to file
			TRY
			{
				DECODE_DATA(m_FileToWrite, szReadBuf, dwBytesRead);
			}
			CATCH(CFileException, e);
			{
				TRACE(_T("An exception occured while writing to the download file\n"));
				HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_ERROR_READFILE), e->m_lOsError);
				e->Delete();
				//clean up any encoding data before we return
				ENCODING_CLEAN_UP;
				return;
			}
			END_CATCH

			//Increment the total number of bytes read
			dwTotalBytesRead += dwBytesRead;  

			UpdateControlsDuringTransfer(dwStartTicks, dwCurrentTicks, dwTotalBytesRead, dwLastTotalBytes, 
                                     dwLastPercentage, bGotFileSize, dwFileSize);
		}
	}
	while (dwBytesRead && !m_bAbort);

	//Delete the file being downloaded to if it is present and the download was aborted
	m_FileToWrite.Close();
	if (m_bAbort)
		::DeleteFile(m_sFileToDownloadInto);

	//clean up any encoding data before we return
	ENCODING_CLEAN_UP;;

	//We're finished
	PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
}
Exemplo n.º 2
0
void CFTPTransferDlg::TransferThread()
{
	//Create the Internet session handle (if needed)
	if (!m_bUsingAttached)
	{
		ASSERT(m_hInternetSession == NULL);
//		m_hInternetSession = ::InternetOpen(AfxGetAppName(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
		m_hInternetSession = InternetOpen("Ftp", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
		if (m_hInternetSession == NULL)
		{
			TRACE(_T("Failed in call to InternetOpen, Error:%d\n"), ::GetLastError());
			HandleThreadErrorWithLastError(IDS_FTPTRANSFER_GENERIC_ERROR);
			return;
		}
		
		//Should we exit the thread
		if (m_bAbort)
		{
			PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
			return;
		} 
	} 
	ASSERT(m_hInternetSession);  
	
	//Setup the status callback function on the Internet session handle
	INTERNET_STATUS_CALLBACK pOldCallback = ::InternetSetStatusCallback(m_hInternetSession, _OnStatusCallBack);
	if (pOldCallback == INTERNET_INVALID_STATUS_CALLBACK)
	{
		TRACE(_T("Failed in call to InternetSetStatusCallback, Error:%d\n"), ::GetLastError());
		HandleThreadErrorWithLastError(IDS_FTPTRANSFER_GENERIC_ERROR);
		return;
	}
	
	//Should we exit the thread
	if (m_bAbort)
	{
		if (pOldCallback)
			::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
		PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
		return;
	}  
	
	//Make the connection to the FTP server (if needed)
	if (!m_bUsingAttached)
	{
		ASSERT(m_hFTPConnection == NULL);
		ASSERT(m_sServer.GetLength());
		if (m_sUserName.GetLength())
//			m_hFTPConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_sUserName, 
//			m_sPassword, INTERNET_SERVICE_FTP, 0, (DWORD) this);
			
			m_hFTPConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_sUserName,
			m_sPassword, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
		else
			m_hFTPConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, NULL, 
			NULL, INTERNET_SERVICE_FTP, 0, (DWORD) this);
		if (m_hFTPConnection == NULL)
		{
			TRACE(_T("Failed in call to InternetConnect, Error:%d\n"), ::GetLastError());
			if (pOldCallback)
				::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
			HandleThreadErrorWithLastError(IDS_FTPTRANSFER_FAIL_CONNECT_SERVER);
			return;
		}
		
		//Should we exit the thread
		if (m_bAbort)
		{
			if (pOldCallback)
				::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
			PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
			return;
		} 
	}
	ASSERT(m_hFTPConnection); 
	
	//Start the animation to signify that the download is taking place
	PlayAnimation();
	
	//Update the status control to reflect that we are getting the file information
	SetStatus(IDS_FTPTRANSFER_GETTING_FILE_INFORMATION);
	
	// Get the length of the file to transfer		   
	DWORD dwFileSize = 0;
	BOOL bGotFileSize = FALSE;
	if (m_bDownload)
	{
		WIN32_FIND_DATA wfd;
		HINTERNET hFind = ::FtpFindFirstFile(m_hFTPConnection, m_sRemoteFile, &wfd, INTERNET_FLAG_RELOAD | 
			INTERNET_FLAG_DONT_CACHE, (DWORD) this); 
		if (hFind)
		{
			//Set the progress control range
			bGotFileSize = TRUE;
			dwFileSize = (DWORD) wfd.nFileSizeLow;
//			SetProgressRange(dwFileSize);
			SetProgressRange(0,100);
			
			//Destroy the enumeration handle now that we are finished with it
			InternetCloseHandle(hFind);
		}
	}
	else
	{
		bGotFileSize = TRUE;
		dwFileSize = m_LocalFile.GetLength();
//		SetProgressRange(dwFileSize);
		SetProgressRange(0, 100);
	}
	
	//Should we exit the thread
	if (m_bAbort)
	{
		if (pOldCallback)
			::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
		PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
		return;
	}  
	
	//check to see if the file already exists on the server  
	if (!m_bDownload)
	{
		WIN32_FIND_DATA wfd;
		HINTERNET hFind = ::FtpFindFirstFile(m_hFTPConnection, m_sRemoteFile, &wfd, INTERNET_FLAG_RELOAD | 
			INTERNET_FLAG_DONT_CACHE, (DWORD) this); 
		BOOL bFound = FALSE;
		if (hFind)
		{
			bFound = TRUE;
			
			//Destroy the enumeration handle now that we are finished with it
			InternetCloseHandle(hFind);
		}
		
		if (bFound && SendMessage(WM_FTPTRANSFER_ASK_OVERWRITE_FILE) == 0)	
		{
			if (pOldCallback)
				::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
			PostMessage(WM_FTPTRANSFER_THREAD_FINISHED, 1);
			return;
		}
	}
	
	//Should we exit the thread
	if (m_bAbort)
	{
		if (pOldCallback)
			::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
		PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
		return;
	}  
	
	//Open the remote file
	ASSERT(m_hFTPFile == NULL);
	if (m_bDownload)
	{
		if (m_bBinary)
			m_hFTPFile = FtpOpenFile(m_hFTPConnection, m_sRemoteFile, GENERIC_READ, FTP_TRANSFER_TYPE_BINARY | 
			INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, (DWORD) this);
		else
			m_hFTPFile = FtpOpenFile(m_hFTPConnection, m_sRemoteFile, GENERIC_READ, FTP_TRANSFER_TYPE_ASCII | 
			INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, (DWORD) this);
	}
	else
	{
		if (m_bBinary)	
			m_hFTPFile = FtpOpenFile(m_hFTPConnection, m_sRemoteFile, GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY | 
			INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, (DWORD) this);
		else
			m_hFTPFile = FtpOpenFile(m_hFTPConnection, m_sRemoteFile, GENERIC_WRITE, FTP_TRANSFER_TYPE_ASCII | 
			INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, (DWORD) this);
	}
	if (m_hFTPFile == NULL)
	{
		TRACE(_T("Failed in call to FtpOpenFile, Error:%d\n"), ::GetLastError());
		if (pOldCallback)
			::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
		HandleThreadErrorWithLastError(IDS_FTPTRANSFER_FAIL_OPEN_FILE);
		return;
	}
	
	//Should we exit the thread
	if (m_bAbort)
	{
		if (pOldCallback)
			::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
		PostMessage(WM_FTPTRANSFER_THREAD_FINISHED);
		return;
	}  
	
	//Update the status to say that we are now uploading / downloading the file
	if (m_bDownload)
		SetStatus(IDS_FTPTRANSFER_RETREIVEING_FILE);
	else
		SetStatus(IDS_FTPTRANSFER_UPLOADING_FILE);
	
	//Now do the actual reading / writing of the file
	DWORD dwStartTicks = ::GetTickCount();
	DWORD dwCurrentTicks = dwStartTicks;
	DWORD dwBytesRead = 0;
	DWORD dwBytesWritten = 0;
	char szReadBuf[1024];
	DWORD dwBytesToRead = 1024;
	DWORD dwTotalBytesRead = 0;
	DWORD dwTotalBytesWritten = 0;	
	DWORD dwLastTotalBytes = 0;
	DWORD dwLastPercentage = 0;
	do
	{
		if (m_bDownload)
		{
			//Read from the remote file
			if (!::InternetReadFile(m_hFTPFile, szReadBuf, dwBytesToRead, &dwBytesRead))
			{
				TRACE(_T("Failed in call to InternetReadFile, Error:%d\n"), ::GetLastError());
				if (pOldCallback)
					::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
				HandleThreadErrorWithLastError(IDS_FTPTRANSFER_ERROR_READFILE);
				return;
			}
			else if (dwBytesRead && !m_bAbort)
			{
				//Write the data to file
				TRY
				{
					m_LocalFile.Write(szReadBuf, dwBytesRead);
				}
				CATCH(CFileException, e);										   
				{
					TRACE(_T("An exception occured while writing to the download file\n"));
					if (pOldCallback)
						::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
					HandleThreadErrorWithLastError(IDS_FTPTRANSFER_ERROR_READFILE, e->m_lOsError);
					e->Delete();
					return;
				}
				END_CATCH
					
					//Increment the total number of bytes read
					dwTotalBytesRead += dwBytesRead;  
				
				UpdateControlsDuringTransfer(dwStartTicks, dwCurrentTicks, dwTotalBytesRead, dwLastTotalBytes, 
					dwLastPercentage, bGotFileSize, dwFileSize);
			}
		}
		else
		{
			//Read the data from the local file
			TRY
			{
				dwBytesRead = m_LocalFile.Read(szReadBuf, 1024);
			}
			CATCH(CFileException, e);										 
			{
				TRACE(_T("An exception occured while reading the local file\n"));
				if (pOldCallback)
					::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
				HandleThreadErrorWithLastError(IDS_FTPTRANSFER_ERROR_READFILE, e->m_lOsError);
				e->Delete();
				return;
			}
			END_CATCH
				
				//Write to the remote file
				if (dwBytesRead)
				{
					if (!::InternetWriteFile(m_hFTPFile, szReadBuf, dwBytesRead, &dwBytesWritten))
					{
						TRACE(_T("Failed in call to InternetWriteFile, Error:%d\n"), ::GetLastError());
						if (pOldCallback)
							::InternetSetStatusCallback(m_hInternetSession, pOldCallback);
						HandleThreadErrorWithLastError(IDS_FTPTRANSFER_ERROR_WRITEFILE);
						return;
					}
					else if (dwBytesWritten && !m_bAbort)
					{
						//Increment the total number of bytes read
						dwTotalBytesWritten += dwBytesWritten;	
						
						UpdateControlsDuringTransfer(dwStartTicks, dwCurrentTicks, dwTotalBytesWritten, dwLastTotalBytes, 
							dwLastPercentage, bGotFileSize, dwFileSize);
					}
				}
		}
	}