📄 downloadtransferhttp.cpp
字号:
{
theApp.Message( MSG_ERROR, IDS_CONNECTION_TIMEOUT_CONNECT, (LPCTSTR)m_sAddress );
if ( m_pSource != NULL ) m_pSource->PushRequest();
Close( TS_UNKNOWN );
return FALSE;
}
break;
case dtsRequesting:
case dtsHeaders:
if ( tNow - m_tRequest > Settings.Connection.TimeoutHandshake )
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_REQUEST_TIMEOUT, (LPCTSTR)m_sAddress );
Close( m_bBusyFault || m_bQueueFlag ? TS_TRUE : TS_UNKNOWN );
return FALSE;
}
break;
case dtsDownloading:
case dtsFlushing:
case dtsTiger:
case dtsMetadata:
if ( tNow - m_mInput.tLast > Settings.Connection.TimeoutTraffic * 2 )
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_TRAFFIC_TIMEOUT, (LPCTSTR)m_sAddress );
Close( TS_TRUE );
return FALSE;
}
break;
case dtsBusy:
if ( tNow - m_tRequest > 1000 )
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_BUSY, (LPCTSTR)m_sAddress, Settings.Downloads.RetryDelay / 1000 );
Close( TS_TRUE );
return FALSE;
}
break;
case dtsQueued:
if ( tNow >= m_tRequest )
{
return StartNextFragment();
}
break;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP read handler
BOOL CDownloadTransferHTTP::OnRead()
{
CDownloadTransfer::OnRead();
switch ( m_nState )
{
case dtsRequesting:
if ( ! ReadResponseLine() ) return FALSE;
if ( m_nState != dtsHeaders ) break;
case dtsHeaders:
if ( ! ReadHeaders() ) return FALSE;
if ( m_nState != dtsDownloading ) break;
case dtsDownloading:
return ReadContent();
case dtsTiger:
return ReadTiger();
case dtsMetadata:
return ReadMetadata();
case dtsFlushing:
return ReadFlush();
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP read response line
BOOL CDownloadTransferHTTP::ReadResponseLine()
{
CString strLine, strCode, strMessage;
if ( ! m_pInput->ReadLine( strLine ) ) return TRUE;
if ( strLine.IsEmpty() ) return TRUE;
if ( strLine.GetLength() > 512 ) strLine = _T("#LINE_TOO_LONG#");
theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD RESPONSE: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strLine );
if ( strLine.GetLength() >= 12 && strLine.Left( 9 ) == _T("HTTP/1.1 ") )
{
strCode = strLine.Mid( 9, 3 );
strMessage = strLine.Mid( 12 );
}
else if ( strLine.GetLength() >= 12 && strLine.Left( 9 ) == _T("HTTP/1.0 ") )
{
strCode = strLine.Mid( 9, 3 );
strMessage = strLine.Mid( 12 );
}
else if ( strLine.GetLength() >= 8 && strLine.Left( 4 ) == _T("HTTP") )
{
strCode = strLine.Mid( 5, 3 );
strMessage = strLine.Mid( 8 );
}
else
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_NOHTTP, (LPCTSTR)m_sAddress );
Close( TS_FALSE );
return FALSE;
}
if ( strCode == _T("200") || strCode == _T("206") )
{
SetState( dtsHeaders );
}
else if ( strCode == _T("503") )
{
if ( _tcsistr( strMessage, _T("range") ) != NULL )
{
m_bRangeFault = TRUE;
}
else
{
m_bBusyFault = TRUE;
}
SetState( dtsHeaders );
}
else if ( strCode == _T("416") )
{
m_bRangeFault = TRUE;
SetState( dtsHeaders );
}
else if ( FALSE && ( strCode == _T("301") || strCode == _T("302") ) )
{
// TODO: Read "Location:" header and re-request
}
else
{
strMessage.TrimLeft();
if ( strMessage.GetLength() > 128 ) strMessage = _T("No Message");
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_HTTPCODE, (LPCTSTR)m_sAddress,
(LPCTSTR)strCode, (LPCTSTR)strMessage );
SetState( dtsHeaders );
m_bBadResponse = TRUE;
}
m_pHeaderName.RemoveAll();
m_pHeaderValue.RemoveAll();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferHTTP read header lines
BOOL CDownloadTransferHTTP::OnHeaderLine(CString& strHeader, CString& strValue)
{
theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD HEADER: %s: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue );
if ( strHeader.CompareNoCase( _T("Server") ) == 0 )
{
m_sUserAgent = strValue;
if ( IsAgentBlocked() )
{
Close( TS_FALSE );
return FALSE;
}
m_pSource->m_sServer = strValue;
if ( strValue.GetLength() > 64 ) strValue = strValue.Left( 64 );
if ( _tcsistr( m_sUserAgent, _T("shareaza") ) != NULL ) m_pSource->SetGnutella( 3 );
if ( _tcsistr( m_sUserAgent, _T("trustyfiles") ) != NULL ) m_pSource->SetGnutella( 3 );
if ( _tcsistr( m_sUserAgent, _T("gnucdna") ) != NULL ) m_pSource->SetGnutella( 3 );
if ( _tcsistr( m_sUserAgent, _T("adagio") ) != NULL ) m_pSource->SetGnutella( 2 );
}
else if ( strHeader.CompareNoCase( _T("Connection") ) == 0 )
{
if ( strValue.CompareNoCase( _T("Keep-Alive") ) == 0 ) m_bKeepAlive = TRUE;
}
else if ( strHeader.CompareNoCase( _T("Content-Length") ) == 0 )
{
_stscanf( strValue, _T("%I64i"), &m_nContentLength );
}
else if ( strHeader.CompareNoCase( _T("Content-Range") ) == 0 )
{
QWORD nFirst = 0, nLast = 0, nTotal = 0;
if ( _stscanf( strValue, _T("bytes %I64i-%I64i/%I64i"), &nFirst, &nLast, &nTotal ) != 3 )
_stscanf( strValue, _T("bytes=%I64i-%I64i/%I64i"), &nFirst, &nLast, &nTotal );
if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
{
m_pDownload->m_nSize = nTotal;
}
else if ( m_bTigerFetch || m_bMetaFetch )
{
m_nOffset = nFirst;
m_nLength = nLast + 1 - nFirst;
if ( m_nContentLength == SIZE_UNKNOWN ) m_nContentLength = m_nLength;
return TRUE;
}
else if ( m_pDownload->m_nSize != nTotal )
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE, (LPCTSTR)m_sAddress,
(LPCTSTR)m_pDownload->GetDisplayName() );
Close( TS_FALSE );
return FALSE;
}
if ( m_nOffset == SIZE_UNKNOWN && ! m_pDownload->GetFragment( this ) )
{
Close( TS_TRUE );
return FALSE;
}
BOOL bUseful = m_pDownload->IsPositionEmpty( nFirst );
// BOOL bUseful = m_pDownload->IsRangeUseful( nFirst, nLast - nFirst + 1 );
if ( nFirst == m_nOffset && nLast == m_nOffset + m_nLength - 1 && bUseful )
{
// Perfect match, good
}
else if ( nFirst >= m_nOffset && nFirst < m_nOffset + m_nLength && bUseful )
{
m_nOffset = nFirst;
m_nLength = nLast - nFirst + 1;
theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_USEFUL_RANGE, (LPCTSTR)m_sAddress,
m_nOffset, m_nOffset + m_nLength - 1, (LPCTSTR)m_pDownload->GetDisplayName() );
}
else
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_RANGE, (LPCTSTR)m_sAddress,
(LPCTSTR)m_pDownload->GetDisplayName() );
Close( TS_TRUE );
return FALSE;
}
if ( m_nContentLength == SIZE_UNKNOWN ) m_nContentLength = m_nLength;
m_bGotRange = TRUE;
}
else if ( strHeader.CompareNoCase( _T("Content-Type") ) == 0 )
{
m_sContentType = strValue;
}
else if ( strHeader.CompareNoCase( _T("Content-Encoding") ) == 0 )
{
if ( Settings.Downloads.AllowBackwards && _tcsistr( strValue, _T("backwards") ) ) m_bRecvBackwards = TRUE;
}
else if ( strHeader.CompareNoCase( _T("X-Gnutella-Content-URN") ) == 0 ||
strHeader.CompareNoCase( _T("X-Content-URN") ) == 0 ||
strHeader.CompareNoCase( _T("Content-URN") ) == 0 )
{
for ( CString strURNs = strValue + ',' ; ; )
{
int nPos = strURNs.Find( ',' );
if ( nPos < 0 ) break;
strValue = strURNs.Left( nPos );
strURNs = strURNs.Mid( nPos + 1 );
strValue.TrimLeft();
SHA1 pSHA1;
if ( CSHA::HashFromURN( strValue, &pSHA1 ) )
{
if ( m_pSource->CheckHash( &pSHA1 ) )
{
m_bHashMatch = TRUE;
}
else
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
(LPCTSTR)m_pDownload->GetDisplayName() );
Close( TS_FALSE );
return FALSE;
}
}
// TODO: Remove " ! m_bHashMatch "
TIGEROOT pTiger;
if ( ! m_bHashMatch && CTigerNode::HashFromURN( strValue, &pTiger ) )
{
if ( m_pSource->CheckHash( &pTiger ) )
{
m_bHashMatch = TRUE;
}
else
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
(LPCTSTR)m_pDownload->GetDisplayName() );
Close( TS_FALSE );
return FALSE;
}
}
MD4 pED2K;
if ( CED2K::HashFromURN( strValue, &pED2K ) )
{
if ( m_pSource->CheckHash( &pED2K ) )
{
m_bHashMatch = TRUE;
}
else
{
theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
(LPCTSTR)m_pDownload->GetDisplayName() );
Close( TS_FALSE );
return FALSE;
}
}
}
m_pSource->SetGnutella( 1 );
}
else if ( strHeader.CompareNoCase( _T("X-Metadata-Path") ) == 0 )
{
if ( ! m_bMetaIgnore && Settings.Downloads.Metadata ) m_sMetadata = strValue;
}
else if ( strHeader.CompareNoCase( _T("X-TigerTree-Path") ) == 0 )
{
if ( Settings.Downloads.VerifyTiger && ! m_bTigerIgnore && m_sTigerTree.IsEmpty() )
{
if ( strValue.Find( _T("tigertree/v1") ) < 0 &&
strValue.Find( _T("tigertree/v2") ) < 0 )
{
m_sTigerTree = strValue;
}
}
}
else if ( strHeader.CompareNoCase( _T("X-Thex-URI") ) == 0 )
{
if ( Settings.Downloads.VerifyTiger && ! m_bTigerIgnore )
{
if ( StartsWith( strValue, _T("/") ) )
{
m_sTigerTree = strValue.SpanExcluding( _T("; ") );
Replace( m_sTigerTree, _T("ed2k=0"), _T("ed2k=1") );
}
}
m_pSource->SetGnutella( 1 );
}
else if ( strHeader.CompareNoCase( _T("X-Gnutella-Alternate-Location") ) == 0 ||
strHeader.CompareNoCase( _T("Alt-Location") ) == 0 ||
strHeader.CompareNoCase( _T("X-Alt") ) == 0 )
{
if ( Settings.Library.SourceMesh )
{
if ( strValue.Find( _T("Zhttp://") ) < 0 )
{
m_pDownload->AddSourceURLs( strValue, m_bHashMatch );
}
}
m_pSource->SetGnutella( 1 );
}
else if ( strHeader.CompareNoCase( _T("X-Available-Ranges") ) == 0 )
{
m_bGotRanges = TRUE;
m_pSource->SetAvailableRanges( strValue );
m_pSource->SetGnutella( 1 );
}
else if ( strHeader.CompareNoCase( _T("X-Queue") ) == 0 )
{
m_pSource->SetGnutella( 1 );
m_bQueueFlag = TRUE;
strValue.MakeLower();
int nPos = strValue.Find( _T("position=") );
if ( nPos >= 0 ) _stscanf( strValue.Mid( nPos + 9 ), _T("%i"), &m_nQueuePos );
nPos = strValue.Find( _T("length=") );
if ( nPos >= 0 ) _stscanf( strValue.Mid( nPos + 7 ), _T("%i"), &m_nQueueLen );
DWORD nLimit;
nPos = strValue.Find( _T("pollmin=") );
if ( nPos >= 0 && _stscanf( strValue.Mid( nPos + 8 ), _T("%lu"), &nLimit ) == 1 )
{
m_nRetryDelay = max( m_nRetryDelay, nLimit * 1000 + 3000 );
}
nPos = strValue.Find( _T("pollmax=") );
if ( nPos >= 0 && _stscanf( strValue.Mid( nPos + 8 ), _T("%lu"), &nLimit ) == 1 )
{
m_nRetryDelay = min( m_nRetryDelay, nLimit * 1000 - 8000 );
}
nPos = strValue.Find( _T("id=") );
if ( nPos >= 0 )
{
m_sQueueName = strValue.Mid( nPos + 3 );
m_sQueueName.TrimLeft();
if ( m_sQueueName.Find( '\"' ) == 0 )
{
m_sQueueName = m_sQueueName.Mid( 1 ).SpanExcluding( _T("\"") );
}
else
{
m_sQueueName = m_sQueueName.SpanExcluding( _T("\" ") );
}
if ( m_sQueueName == _T("s") ) m_sQueueName = _T("Small Queue");
else if ( m_sQueueName == _T("l") ) m_sQueueName = _T("Large Queue");
}
}
else if ( strHeader.CompareNoCase( _T("X-PerHost") ) == 0 ||
strHeader.CompareNoCase( _T("X-Gnutella-maxSlotsPerHost") ) == 0 )
{
int nLimit = 0;
if ( _stscanf( strValue, _T("%lu"), &nLimit ) != 1 )
{
Downloads.SetPerHostLimit( &m_pHost.sin_addr, nLimit );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -