⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httprequest.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// HttpRequest.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "HttpRequest.h"
#include "Network.h"
#include "Buffer.h"
#include "SourceURL.h"


//////////////////////////////////////////////////////////////////////
// CHttpRequest construction

CHttpRequest::CHttpRequest()
{
	m_sUserAgent	= Settings.SmartAgent( Settings.General.UserAgent );
	m_hThread		= NULL;
	m_hInternet		= NULL;
	m_nLimit		= 0;
	m_nStatusCode	= 0;
	m_pPost			= NULL;
	m_pResponse		= NULL;
	m_hNotifyWnd	= NULL;
}

CHttpRequest::~CHttpRequest()
{
	Clear();
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest clear

void CHttpRequest::Clear()
{
	Cancel();
	
	CSingleLock pLock( &m_pSection );
	
	m_sURL.Empty();
	m_sRequestHeaders.Empty();
	
	m_nLimit		= 0;
	m_nStatusCode	= 0;
	
	m_sStatusString.Empty();
	m_pResponseHeaders.RemoveAll();
	
	if ( m_pPost != NULL ) delete m_pPost;
	m_pPost = NULL;
	
	if ( m_pResponse != NULL ) delete m_pResponse;
	m_pResponse = NULL;
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest request attributes

BOOL CHttpRequest::SetURL(LPCTSTR pszURL)
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return FALSE;
	if ( pszURL == NULL || _tcsncmp( pszURL, _T("http"), 4 ) ) return FALSE;
	m_sURL = pszURL;
	return TRUE;
}

CString CHttpRequest::GetURL()
{
	CSingleLock pLock( &m_pSection );
	CString strURL = m_sURL;
	return strURL;
}

void CHttpRequest::AddHeader(LPCTSTR pszKey, LPCTSTR pszValue)
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return;
	
	m_sRequestHeaders += pszKey;
	m_sRequestHeaders += _T(": ");
	m_sRequestHeaders += pszValue;
	m_sRequestHeaders += _T("\r\n");
}

void CHttpRequest::SetPostData(LPCVOID pBody, DWORD nBody)
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return;
	
	if ( m_pPost != NULL ) delete m_pPost;
	m_pPost = NULL;
	
	if ( pBody != NULL && nBody > 0 )
	{
		m_pPost = new CBuffer();
		m_pPost->Add( pBody, nBody );
	}
}

void CHttpRequest::SetUserAgent(LPCTSTR pszUserAgent)
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return;
	m_sUserAgent = pszUserAgent;
}

void CHttpRequest::LimitContentLength(DWORD nLimit)
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return;
	m_nLimit = nLimit;
}

void CHttpRequest::SetNotify(HWND hWnd, UINT nMsg, WPARAM wParam)
{
	CSingleLock pLock( &m_pSection );
	m_hNotifyWnd	= hWnd;
	m_nNotifyMsg	= nMsg;
	m_nNotifyParam	= wParam;
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest response attributes

int CHttpRequest::GetStatusCode()
{
	CSingleLock pLock( &m_pSection );
	return IsPending() ? 0 : m_nStatusCode;
}

BOOL CHttpRequest::GetStatusSuccess()
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return FALSE;
	return m_nStatusCode >= 200 && m_nStatusCode < 300;
}

CString CHttpRequest::GetStatusString()
{
	CSingleLock pLock( &m_pSection );
	return m_sStatusString;
}

CString CHttpRequest::GetHeader(LPCTSTR pszName)
{
	CSingleLock pLock( &m_pSection );
	CString strIn, strOut;
	
	if ( IsPending() ) return strOut;
	
	strIn = pszName;
	strIn.MakeLower();
	m_pResponseHeaders.Lookup( strIn, strOut );
	
	return strOut;
}

CString CHttpRequest::GetResponseString(UINT nCodePage)
{
	CSingleLock pLock( &m_pSection );
	CString str;
	
	if ( ! IsPending() && m_pResponse != NULL )
	{
		str = m_pResponse->ReadString( m_pResponse->m_nLength, nCodePage );
	}
	
	return str;
}

CBuffer* CHttpRequest::GetResponseBuffer()
{
	CSingleLock pLock( &m_pSection );
	if ( IsPending() ) return NULL;
	return m_pResponse;
}

BOOL CHttpRequest::InflateResponse()
{
	CSingleLock pLock( &m_pSection, TRUE );
	
	if ( IsPending() || m_pResponse == NULL ) return FALSE;
	
	CString strEncoding = GetHeader( _T("Content-Encoding") );
	
	if ( strEncoding.CompareNoCase( _T("deflate") ) == 0 )
	{
		return m_pResponse->Inflate();
	}
	
	if ( strEncoding.CompareNoCase( _T("gzip") ) == 0 )
	{
		return m_pResponse->Ungzip();
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest process control

BOOL CHttpRequest::Execute(BOOL bBackground)
{
	if ( IsPending() ) return FALSE;
	Cancel();
	
	ASSERT( m_sURL.GetLength() > 0 );
	ASSERT( m_pPost == NULL );
	
	m_bCancel = FALSE;
	m_nStatusCode = 0;
	m_pResponseHeaders.RemoveAll();
	if ( m_pResponse != NULL ) delete m_pResponse;
	m_pResponse = NULL;
	
	if ( bBackground )
	{
		m_hThread = AfxBeginThread( (AFX_THREADPROC)ThreadStart, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL )->m_hThread;
		return TRUE;
	}
	else
	{
		Run();
		ASSERT( ! IsPending() );
		return ( m_nStatusCode >= 200 && m_nStatusCode < 300 );
	}
}

BOOL CHttpRequest::IsPending()
{
	return ( m_hInternet != NULL );
}

BOOL CHttpRequest::IsFinished()
{
	return ( m_hInternet == NULL ) && ( m_nStatusCode != 0 );
}

void CHttpRequest::Cancel()
{
	m_bCancel = TRUE;
	
	m_pSection.Lock();
	HINTERNET hInternet = m_hInternet;
	m_hInternet = NULL;
	m_pSection.Unlock();
	
	if ( hInternet != NULL ) InternetCloseHandle( hInternet );
	
	if ( m_hThread != NULL )
	{
		ASSERT( GetCurrentThread() != m_hThread );
		
		for ( int nAttempt = 100 ; nAttempt > 0 ; nAttempt-- )
		{
			DWORD nCode = 0;
			if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
			if ( nCode != STILL_ACTIVE ) break;
			Sleep( 100 );
		}
		
		if ( nAttempt == 0 )
		{
			TerminateThread( m_hThread, 0 );
			Sleep( 100 );
		}
	}
	
	m_hThread = NULL;
	m_bCancel = FALSE;
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest thread run

UINT CHttpRequest::ThreadStart(LPVOID lpParameter)
{
	CHttpRequest* pRequest = reinterpret_cast<CHttpRequest*>(lpParameter);
	return (DWORD)pRequest->Run();
}

int CHttpRequest::Run()
{
	CSingleLock pLock( &m_pSection, FALSE );
	
	HINTERNET hInternet = InternetOpen( m_sUserAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
	
	if ( hInternet != NULL )
	{
		m_hInternet = hInternet;
		
		RunRequest();
		// RunDebugRequest();
		
		pLock.Lock();
		if ( m_bCancel ) m_nStatusCode = 0;
		hInternet = m_hInternet;
		m_hInternet = NULL;
		pLock.Unlock();
		
		if ( hInternet != NULL ) InternetCloseHandle( hInternet );
	}
	
	pLock.Lock();
	if ( m_hNotifyWnd != NULL ) PostMessage( m_hNotifyWnd, m_nNotifyMsg, m_nNotifyParam, 0 );
	pLock.Unlock();
	
	return 0;
}

void CHttpRequest::RunRequest()
{
	HINTERNET hURL = InternetOpenUrl( m_hInternet, m_sURL, m_sRequestHeaders,
		m_sRequestHeaders.GetLength(), INTERNET_FLAG_KEEP_CONNECTION, NULL );
	
	if ( hURL != NULL )
	{
		RunResponse( hURL );
		InternetCloseHandle( hURL );
	}
}

void CHttpRequest::RunResponse(HINTERNET hURL)
{
	DWORD nLength = 255;
	BYTE nNull = 0;
	
	if ( ! HttpQueryInfo( hURL, HTTP_QUERY_STATUS_TEXT,
		m_sStatusString.GetBuffer( nLength ), &nLength, 0 ) ) nLength = 0;
	m_sStatusString.ReleaseBuffer( nLength );
	if ( m_sStatusString.IsEmpty() ) return;
	
	if ( m_pResponse != NULL ) delete m_pResponse;
	m_pResponse = new CBuffer();
	
	for ( DWORD nRemaining ; InternetQueryDataAvailable( hURL, &nRemaining, 0, 0 ) && nRemaining > 0 && ! m_bCancel ; )
	{
		m_pResponse->EnsureBuffer( nRemaining );
		if ( ! InternetReadFile( hURL, m_pResponse->m_pBuffer + m_pResponse->m_nLength,
			nRemaining, &nRemaining ) ) break;
		m_pResponse->m_nLength += nRemaining;
		if ( m_nLimit > 0 && m_pResponse->m_nLength > m_nLimit ) break;
	}
	
	if ( nRemaining > 0 ) return;
	
	nLength = 0;
	HttpQueryInfo( hURL, HTTP_QUERY_RAW_HEADERS, &nNull, &nLength, 0 );
	if ( nLength == 0 ) return;
	
	LPTSTR pszHeaders = new TCHAR[ nLength + 1 ];
	pszHeaders[0] = pszHeaders[1] = 0;
	HttpQueryInfo( hURL, HTTP_QUERY_RAW_HEADERS, pszHeaders, &nLength, 0 );
	
	for ( LPTSTR pszHeader = pszHeaders ; *pszHeader ; )
	{
		CString strHeader( pszHeader );
		pszHeader += strHeader.GetLength() + 1;
		
		int nColon = strHeader.Find( ':' );
		
		if ( nColon > 0 )
		{
			CString strValue, strName = strHeader.Left( nColon );
			strName.Trim(); strName.MakeLower();
			
			while ( m_pResponseHeaders.Lookup( strName, strValue ) ) strName += _T('_');

			strValue = strHeader.Mid( nColon + 1 );
			strValue.Trim();
			m_pResponseHeaders.SetAt( strName, strValue );
		}
	}
	
	delete [] pszHeaders;
	
	nLength = 4;
	m_nStatusCode = 0;
	HttpQueryInfo( hURL, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
		&m_nStatusCode, &nLength, 0 );
}

//////////////////////////////////////////////////////////////////////
// CHttpRequest clear

void CHttpRequest::CloseThread(HANDLE* phThread, LPCTSTR pszName)
{
	if ( *phThread == NULL ) return;
	
	for ( int nAttempt = 100 ; nAttempt > 0 ; nAttempt-- )
	{
		DWORD nCode;
		if ( ! GetExitCodeThread( *phThread, &nCode ) ) break;
		if ( nCode != STILL_ACTIVE ) break;
		Sleep( 100 );
	}
	
	if ( nAttempt == 0 )
	{
		TerminateThread( *phThread, 0 );
		if ( pszName != NULL )
		{
			theApp.Message( MSG_DEBUG,
				_T("WARNING: Terminating %s thread."), pszName );
		}
		Sleep( 100 );
	}
	
	*phThread = NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -