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

📄 downloadtransferhttp.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// DownloadTransferHTTP.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 "Download.h"
#include "Downloads.h"
#include "DownloadSource.h"
#include "DownloadTransfer.h"
#include "DownloadTransferHTTP.h"
#include "FragmentedFile.h"
#include "Network.h"
#include "Buffer.h"
#include "SourceURL.h"
#include "GProfile.h"
#include "SHA.h"
#include "ED2K.h"
#include "TigerTree.h"
#include "XML.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP construction

CDownloadTransferHTTP::CDownloadTransferHTTP(CDownloadSource* pSource) : CDownloadTransfer( pSource, PROTOCOL_HTTP )
{
	m_nRequests		= 0;
	m_tContent		= 0;
	
	m_bBadResponse	= FALSE;
	m_bBusyFault	= FALSE;
	m_bRangeFault	= FALSE;
	m_bHashMatch	= FALSE;
	m_bTigerFetch	= FALSE;
	m_bTigerIgnore	= FALSE;
	m_bMetaFetch	= FALSE;
	m_bMetaIgnore	= FALSE;
	
	m_nRetryDelay	= Settings.Downloads.RetryDelay;
}

CDownloadTransferHTTP::~CDownloadTransferHTTP()
{
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP initiate connection

BOOL CDownloadTransferHTTP::Initiate()
{
	theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTING,
		(LPCTSTR)CString( inet_ntoa( m_pSource->m_pAddress ) ), m_pSource->m_nPort,
		(LPCTSTR)m_pDownload->GetDisplayName() );
	
	if ( ConnectTo( &m_pSource->m_pAddress, m_pSource->m_nPort ) )
	{
		SetState( dtsConnecting );
		
		if ( ! m_pDownload->IsBoosted() )
			m_mInput.pLimit = m_mOutput.pLimit = &Downloads.m_nLimitGeneric;
		
		return TRUE;
	}
	else
	{
		theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR, (LPCTSTR)m_sAddress );
		Close( TS_UNKNOWN );
		return FALSE;
	}
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP accept push

BOOL CDownloadTransferHTTP::AcceptPush(CConnection* pConnection)
{
	AttachTo( pConnection );
	
	theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_PUSHED, (LPCTSTR)m_sAddress,
		(LPCTSTR)m_pDownload->GetDisplayName() );
	
	if ( ! m_pDownload->IsBoosted() )
		m_mInput.pLimit = m_mOutput.pLimit = &Downloads.m_nLimitGeneric;
	
	if ( StartNextFragment() ) return TRUE;
	
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP close

void CDownloadTransferHTTP::Close(TRISTATE bKeepSource)
{
	if ( m_pSource != NULL && m_nState == dtsDownloading )
	{
		if ( m_bRecvBackwards )
		{
			m_pSource->AddFragment( m_nOffset + m_nLength - m_nPosition, m_nPosition );
		}
		else
		{
			m_pSource->AddFragment( m_nOffset, m_nPosition );
		}
	}
	
	CDownloadTransfer::Close( bKeepSource );
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP speed controls

void CDownloadTransferHTTP::Boost()
{
	m_mInput.pLimit = m_mOutput.pLimit = NULL;
}

DWORD CDownloadTransferHTTP::GetAverageSpeed()
{
	if ( m_nState == dtsDownloading )
	{
		DWORD nTime = ( GetTickCount() - m_tContent ) / 1000;
		if ( nTime > 0 ) m_pSource->m_nSpeed = (DWORD)( m_nPosition / nTime );
	}
	
	return m_pSource->m_nSpeed;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP connection handler

BOOL CDownloadTransferHTTP::OnConnected()
{
	theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress );
	
	m_tConnected = GetTickCount();
	
	return StartNextFragment();
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP fragment allocation

BOOL CDownloadTransferHTTP::StartNextFragment()
{
	ASSERT( this != NULL );
	if ( this == NULL ) return FALSE;

	m_nOffset			= SIZE_UNKNOWN;
	m_nPosition			= 0;
	m_bWantBackwards	= FALSE;
	m_bRecvBackwards	= FALSE;
	m_bTigerFetch		= FALSE;
	m_bMetaFetch		= FALSE;
	
	if ( m_pInput == NULL || m_pOutput == NULL /* ||
		 m_pDownload->GetTransferCount( dtsDownloading ) >= Settings.Downloads.MaxFileTransfers */ )
	{
		theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CLOSING_EXTRA, (LPCTSTR)m_sAddress );
		Close( TS_TRUE );
		return FALSE;
	}
	
	// this needs to go for pipeline
	
	if ( m_pInput->m_nLength > 0 && m_nRequests > 0 )
	{
		theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CLOSING_OVERFLOW, (LPCTSTR)m_sAddress );
		Close( TS_TRUE );
		return FALSE;
	}
	
	if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
	{
		return SendRequest();
	}
	else if ( m_pDownload->NeedTigerTree() && m_sTigerTree.GetLength() )
	{
		theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_TIGER_REQUEST,
			(LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
		
		m_bTigerFetch	= TRUE;
		m_bTigerIgnore	= TRUE;
		
		return SendRequest();
	}
	else if ( m_pDownload->m_pXML == NULL && m_sMetadata.GetLength() )
	{
		theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_METADATA_REQUEST,
			(LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
		
		m_bMetaFetch	= TRUE;
		m_bMetaIgnore	= TRUE;
		
		return SendRequest();
	}
	else if ( m_pDownload->GetFragment( this ) )
	{
		ChunkifyRequest( &m_nOffset, &m_nLength, Settings.Downloads.ChunkSize, TRUE );
		
		theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_REQUEST,
			m_nOffset, m_nOffset + m_nLength - 1,
			(LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
		
		return SendRequest();
	}
	else
	{
		if ( m_pSource != NULL ) m_pSource->SetAvailableRanges( NULL );
		
		theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress );
		Close( TS_TRUE );
		
		return FALSE;
	}
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP subtract pending requests

BOOL CDownloadTransferHTTP::SubtractRequested(CFileFragment** ppFragments)
{
	if ( m_nOffset < SIZE_UNKNOWN && m_nLength < SIZE_UNKNOWN )
	{
		if ( m_nState == dtsRequesting || m_nState == dtsDownloading )
		{
			CFileFragment::Subtract( ppFragments, m_nOffset, m_nLength );
			return TRUE;
		}
	}
	
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP send request

BOOL CDownloadTransferHTTP::SendRequest()
{
	CString strLine;
	
	CSourceURL pURL;
	if ( ! pURL.ParseHTTP( m_pSource->m_sURL, FALSE ) ) return FALSE;
	
	if ( m_bTigerFetch )
	{
		pURL.m_sPath = m_sTigerTree;
		m_sTigerTree.Empty();
	}
	else if ( m_bMetaFetch )
	{
		pURL.m_sPath = m_sMetadata;
		m_sMetadata.Empty();
	}
	
	if ( Settings.Downloads.RequestHTTP11 )
	{
		strLine.Format( _T("GET %s HTTP/1.1\r\n"), (LPCTSTR)pURL.m_sPath );
		m_pOutput->Print( strLine );
		
		strLine.Format( _T("Host: %s\r\n"), (LPCTSTR)pURL.m_sAddress );
		m_pOutput->Print( strLine );
	}
	else
	{
		strLine.Format( _T("GET %s HTTP/1.0\r\n"), (LPCTSTR)pURL.m_sPath );
	}
	
	theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD REQUEST: %s"),
		(LPCTSTR)m_sAddress, (LPCTSTR)pURL.m_sPath );
	
	// m_pOutput->Print( "Connection: Keep-Alive\r\n" );
	if ( Settings.Gnutella2.EnableToday ) m_pOutput->Print( "X-Features: g2/1.0\r\n" );
	
	if ( m_bTigerFetch )
	{
		m_pOutput->Print( "Accept: application/dime, application/tigertree-breadthfirst\r\n" );
	}
	else if ( m_bMetaFetch )
	{
		m_pOutput->Print( "Accept: text/xml\r\n" );
	}
	
	if ( m_nOffset != SIZE_UNKNOWN && ! m_bTigerFetch && ! m_bMetaFetch )
	{
		if ( m_nOffset + m_nLength == m_pDownload->m_nSize )
		{
			strLine.Format( _T("Range: bytes=%I64i-\r\n"), m_nOffset );
		}
		else
		{
			strLine.Format( _T("Range: bytes=%I64i-%I64i\r\n"), m_nOffset, m_nOffset + m_nLength - 1 );
		}
		m_pOutput->Print( strLine );
	}
	else
	{
		m_pOutput->Print( "Range: bytes=0-\r\n" );
	}
	
	if ( m_bWantBackwards && Settings.Downloads.AllowBackwards )
	{
		m_pOutput->Print( "Accept-Encoding: backwards\r\n" );
	}
	
	strLine = Settings.SmartAgent( Settings.General.UserAgent );
	
	if ( strLine.GetLength() )
	{
		strLine = _T("User-Agent: ") + strLine + _T("\r\n");
		m_pOutput->Print( strLine );
	}
	
	if ( m_nRequests == 0 )
	{
		if ( m_bInitiated ) SendMyAddress();
		
		strLine = MyProfile.GetNick();
		
		if ( strLine.GetLength() > 0 )
		{
			strLine = _T("X-Nick: ") + URLEncode( strLine ) + _T("\r\n");
			m_pOutput->Print( strLine );
		}
	}
	
	if ( m_pSource->m_nPort == 80 )
	{
		int nSlash = m_pSource->m_sURL.ReverseFind( '/' );
		if ( nSlash > 0 )
		{
			strLine = _T("Referrer: ") + m_pSource->m_sURL.Left( nSlash + 1 ) + _T("\r\n");
			m_pOutput->Print( strLine );
		}
	}
	
	m_pOutput->Print( "X-Queue: 0.1\r\n" );
	
	if ( m_pSource->m_bSHA1 && Settings.Library.SourceMesh && ! m_bTigerFetch && ! m_bMetaFetch )
	{
		CString strURN = CSHA::HashToString( &m_pDownload->m_pSHA1, TRUE );
		
		m_pOutput->Print( "X-Content-URN: " );
		m_pOutput->Print( strURN + _T("\r\n") );
		
		strLine = m_pDownload->GetSourceURLs( &m_pSourcesSent, 15, TRUE, m_pSource );
		
		if ( strLine.GetLength() )
		{
			m_pOutput->Print( "Alt-Location: " );
			m_pOutput->Print( strLine + _T("\r\n") );
		}
		
		if ( m_pDownload->IsShared() && m_pDownload->IsStarted() && Network.IsStable() )
		{
			strLine.Format( _T("http://%s:%i/uri-res/N2R?%s "),
				(LPCTSTR)CString( inet_ntoa( Network.m_pHost.sin_addr ) ),
				htons( Network.m_pHost.sin_port ),
				(LPCTSTR)strURN );
			strLine += TimeToString( time( NULL ) - 180 );
			m_pOutput->Print( "Alt-Location: " );
			m_pOutput->Print( strLine + _T("\r\n") );
		}
	}
	
	m_pOutput->Print( "\r\n" );
	
	SetState( dtsRequesting );
	m_tRequest			= GetTickCount();
	m_bBusyFault		= FALSE;
	m_bRangeFault		= FALSE;
	m_bKeepAlive		= FALSE;
	m_bHashMatch		= FALSE;
	m_bGotRange			= FALSE;
	m_bGotRanges		= FALSE;
	m_bQueueFlag		= FALSE;
	m_nContentLength	= SIZE_UNKNOWN;
	m_sContentType.Empty();
	
	m_sTigerTree.Empty();
	m_nRequests++;
	
	m_pSource->SetLastSeen();
	
	CDownloadTransfer::OnWrite();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP run handler

BOOL CDownloadTransferHTTP::OnRun()
{
	CDownloadTransfer::OnRun();
	
	DWORD tNow = GetTickCount();
	
	switch ( m_nState )
	{
	case dtsConnecting:
		if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )

⌨️ 快捷键说明

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