📄 downloadtransferhttp.cpp
字号:
//
// 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 + -