Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

DownloadTransferHTTP.cpp

Go to the documentation of this file.
00001 //
00002 // DownloadTransferHTTP.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Download.h"
00026 #include "Downloads.h"
00027 #include "DownloadSource.h"
00028 #include "DownloadTransfer.h"
00029 #include "DownloadTransferHTTP.h"
00030 #include "FragmentedFile.h"
00031 #include "Network.h"
00032 #include "Buffer.h"
00033 #include "SourceURL.h"
00034 #include "GProfile.h"
00035 #include "SHA.h"
00036 #include "ED2K.h"
00037 #include "TigerTree.h"
00038 #include "XML.h"
00039 
00040 #ifdef _DEBUG
00041 #undef THIS_FILE
00042 static char THIS_FILE[]=__FILE__;
00043 #define new DEBUG_NEW
00044 #endif
00045 
00046 
00048 // CDownloadTransferHTTP construction
00049 
00050 CDownloadTransferHTTP::CDownloadTransferHTTP(CDownloadSource* pSource) : CDownloadTransfer( pSource, PROTOCOL_HTTP )
00051 {
00052         m_nRequests             = 0;
00053         m_tContent              = 0;
00054         
00055         m_bBadResponse  = FALSE;
00056         m_bBusyFault    = FALSE;
00057         m_bRangeFault   = FALSE;
00058         m_bHashMatch    = FALSE;
00059         m_bTigerFetch   = FALSE;
00060         m_bTigerIgnore  = FALSE;
00061         m_bMetaFetch    = FALSE;
00062         m_bMetaIgnore   = FALSE;
00063         
00064         m_nRetryDelay   = Settings.Downloads.RetryDelay;
00065 }
00066 
00067 CDownloadTransferHTTP::~CDownloadTransferHTTP()
00068 {
00069 }
00070 
00072 // CDownloadTransferHTTP initiate connection
00073 
00074 BOOL CDownloadTransferHTTP::Initiate()
00075 {
00076         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTING,
00077                 (LPCTSTR)CString( inet_ntoa( m_pSource->m_pAddress ) ), m_pSource->m_nPort,
00078                 (LPCTSTR)m_pDownload->GetDisplayName() );
00079         
00080         if ( ConnectTo( &m_pSource->m_pAddress, m_pSource->m_nPort ) )
00081         {
00082                 SetState( dtsConnecting );
00083                 
00084                 if ( ! m_pDownload->IsBoosted() )
00085                         m_mInput.pLimit = m_mOutput.pLimit = &Downloads.m_nLimitGeneric;
00086                 
00087                 return TRUE;
00088         }
00089         else
00090         {
00091                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR, (LPCTSTR)m_sAddress );
00092                 Close( TS_UNKNOWN );
00093                 return FALSE;
00094         }
00095 }
00096 
00098 // CDownloadTransferHTTP accept push
00099 
00100 BOOL CDownloadTransferHTTP::AcceptPush(CConnection* pConnection)
00101 {
00102         AttachTo( pConnection );
00103         
00104         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_PUSHED, (LPCTSTR)m_sAddress,
00105                 (LPCTSTR)m_pDownload->GetDisplayName() );
00106         
00107         if ( ! m_pDownload->IsBoosted() )
00108                 m_mInput.pLimit = m_mOutput.pLimit = &Downloads.m_nLimitGeneric;
00109         
00110         if ( StartNextFragment() ) return TRUE;
00111         
00112         return FALSE;
00113 }
00114 
00116 // CDownloadTransferHTTP close
00117 
00118 void CDownloadTransferHTTP::Close(TRISTATE bKeepSource)
00119 {
00120         if ( m_pSource != NULL && m_nState == dtsDownloading && m_nPosition )
00121         {
00122                 if ( m_bRecvBackwards )
00123                 {
00124                         m_pSource->AddFragment( m_nOffset + m_nLength - m_nPosition, m_nPosition );
00125                 }
00126                 else
00127                 {
00128                         m_pSource->AddFragment( m_nOffset, m_nPosition );
00129                 }
00130         }
00131         
00132         CDownloadTransfer::Close( bKeepSource );
00133 }
00134 
00136 // CDownloadTransferHTTP speed controls
00137 
00138 void CDownloadTransferHTTP::Boost()
00139 {
00140         m_mInput.pLimit = m_mOutput.pLimit = NULL;
00141 }
00142 
00143 DWORD CDownloadTransferHTTP::GetAverageSpeed()
00144 {
00145         if ( m_nState == dtsDownloading )
00146         {
00147                 DWORD nTime = ( GetTickCount() - m_tContent ) / 1000;
00148                 if ( nTime > 0 ) m_pSource->m_nSpeed = (DWORD)( m_nPosition / nTime );
00149         }
00150         
00151         return m_pSource->m_nSpeed;
00152 }
00153 
00155 // CDownloadTransferHTTP connection handler
00156 
00157 BOOL CDownloadTransferHTTP::OnConnected()
00158 {
00159         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress );
00160         
00161         m_tConnected = GetTickCount();
00162         
00163         return StartNextFragment();
00164 }
00165 
00167 // CDownloadTransferHTTP fragment allocation
00168 
00169 bool VerifySelection(CDownloadTransferHTTP* pTransfer)
00170 {
00171         FF::SimpleFragment oFragment( pTransfer->m_nOffset, pTransfer->m_nOffset + pTransfer->m_nLength );
00172         FF::SimpleFragmentList::IteratorPair p = pTransfer->m_pSource->m_oAvailable.overlappingRange( oFragment );
00173         return pTransfer->m_pSource->m_oAvailable.empty()
00174                 || p.first != p.second && p.first->begin() <= pTransfer->m_nOffset
00175                         && p.first->end() >= pTransfer->m_nOffset + pTransfer->m_nLength;
00176 }
00177 
00178 BOOL CDownloadTransferHTTP::StartNextFragment()
00179 {
00180         ASSERT( this != NULL );
00181         if ( this == NULL ) return FALSE;
00182 
00183         m_nOffset                       = SIZE_UNKNOWN;
00184         m_nPosition                     = 0;
00185         m_bWantBackwards        = FALSE;
00186         m_bRecvBackwards        = FALSE;
00187         m_bTigerFetch           = FALSE;
00188         m_bMetaFetch            = FALSE;
00189         
00190         if ( m_pInput == NULL || m_pOutput == NULL /* ||
00191                  m_pDownload->GetTransferCount( dtsDownloading ) >= Settings.Downloads.MaxFileTransfers */ )
00192         {
00193                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CLOSING_EXTRA, (LPCTSTR)m_sAddress );
00194                 Close( TS_TRUE );
00195                 return FALSE;
00196         }
00197         
00198         // this needs to go for pipeline
00199         
00200         if ( m_pInput->m_nLength > 0 && m_nRequests > 0 )
00201         {
00202                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CLOSING_OVERFLOW, (LPCTSTR)m_sAddress );
00203                 Close( TS_TRUE );
00204                 return FALSE;
00205         }
00206         
00207         if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
00208         {
00209                 return SendRequest();
00210         }
00211         else if ( m_pDownload->NeedTigerTree() && m_sTigerTree.GetLength() )
00212         {
00213                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_TIGER_REQUEST,
00214                         (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
00215                 
00216                 m_bTigerFetch   = TRUE;
00217                 m_bTigerIgnore  = TRUE;
00218                 
00219                 return SendRequest();
00220         }
00221         else if ( m_pDownload->m_pXML == NULL && m_sMetadata.GetLength() )
00222         {
00223                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_METADATA_REQUEST,
00224                         (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
00225                 
00226                 m_bMetaFetch    = TRUE;
00227                 m_bMetaIgnore   = TRUE;
00228                 
00229                 return SendRequest();
00230         }
00231         else if ( m_pDownload->GetFragment( this ) )
00232         {
00233                 ASSERT( VerifySelection( this ) );
00234                 ChunkifyRequest( &m_nOffset, &m_nLength, Settings.Downloads.ChunkSize, TRUE );
00235                 ASSERT( VerifySelection( this ) );
00236                 
00237                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_REQUEST,
00238                         m_nOffset, m_nOffset + m_nLength - 1,
00239                         (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
00240                 
00241                 return SendRequest();
00242         }
00243         else
00244         {
00245                 if ( m_pSource != NULL ) m_pSource->SetAvailableRanges( NULL );
00246                 
00247                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress );
00248                 Close( TS_TRUE );
00249                 
00250                 return FALSE;
00251         }
00252 }
00253 
00255 // CDownloadTransferHTTP subtract pending requests
00256 
00257 BOOL CDownloadTransferHTTP::SubtractRequested(FF::SimpleFragmentList& ppFragments)
00258 {
00259         if ( m_nOffset < SIZE_UNKNOWN && m_nLength < SIZE_UNKNOWN )
00260         {
00261                 if ( m_nState == dtsRequesting || m_nState == dtsDownloading )
00262                 {
00263             ppFragments.erase( FF::SimpleFragment( m_nOffset, m_nOffset + m_nLength ) );
00264                         return TRUE;
00265                 }
00266         }
00267         
00268         return FALSE;
00269 }
00270 
00272 // CDownloadTransferHTTP send request
00273 
00274 BOOL CDownloadTransferHTTP::SendRequest()
00275 {
00276         CString strLine;
00277         
00278         CSourceURL pURL;
00279         if ( ! pURL.ParseHTTP( m_pSource->m_sURL, FALSE ) ) return FALSE;
00280         
00281         if ( m_bTigerFetch )
00282         {
00283                 pURL.m_sPath = m_sTigerTree;
00284                 m_sTigerTree.Empty();
00285         }
00286         else if ( m_bMetaFetch )
00287         {
00288                 pURL.m_sPath = m_sMetadata;
00289                 m_sMetadata.Empty();
00290         }
00291         
00292         if ( Settings.Downloads.RequestHTTP11 )
00293         {
00294                 strLine.Format( _T("GET %s HTTP/1.1\r\n"), (LPCTSTR)pURL.m_sPath );
00295                 m_pOutput->Print( strLine );
00296                 
00297                 strLine.Format( _T("Host: %s\r\n"), (LPCTSTR)pURL.m_sAddress );
00298                 m_pOutput->Print( strLine );
00299         }
00300         else
00301         {
00302                 strLine.Format( _T("GET %s HTTP/1.0\r\n"), (LPCTSTR)pURL.m_sPath );
00303         }
00304         
00305         theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD REQUEST: %s"),
00306                 (LPCTSTR)m_sAddress, (LPCTSTR)pURL.m_sPath );
00307         
00308         m_pOutput->Print( "Connection: Keep-Alive\r\n" ); //BearShare assumes close
00309 
00310         if ( Settings.Gnutella2.EnableToday ) m_pOutput->Print( "X-Features: g2/1.0\r\n" );
00311         
00312         if ( m_bTigerFetch )
00313         {
00314                 m_pOutput->Print( "Accept: application/dime, application/tigertree-breadthfirst\r\n" );
00315         }
00316         else if ( m_bMetaFetch )
00317         {
00318                 m_pOutput->Print( "Accept: text/xml\r\n" );
00319         }
00320         
00321         if ( m_nOffset != SIZE_UNKNOWN && ! m_bTigerFetch && ! m_bMetaFetch )
00322         {
00323                 if ( m_nOffset + m_nLength == m_pDownload->m_nSize )
00324                 {
00325                         strLine.Format( _T("Range: bytes=%I64i-\r\n"), m_nOffset );
00326                 }
00327                 else
00328                 {
00329                         strLine.Format( _T("Range: bytes=%I64i-%I64i\r\n"), m_nOffset, m_nOffset + m_nLength - 1 );
00330                 }
00331                 m_pOutput->Print( strLine );
00332         }
00333         else
00334         {
00335                 m_pOutput->Print( "Range: bytes=0-\r\n" );
00336         }
00337         
00338         if ( m_bWantBackwards && Settings.Downloads.AllowBackwards )
00339         {
00340                 m_pOutput->Print( "Accept-Encoding: backwards\r\n" );
00341         }
00342         
00343         strLine = Settings.SmartAgent();
00344         
00345         if ( strLine.GetLength() )
00346         {
00347                 strLine = _T("User-Agent: ") + strLine + _T("\r\n");
00348                 m_pOutput->Print( strLine );
00349         }
00350         
00351         if ( m_nRequests == 0 )
00352         {
00353                 if ( m_bInitiated ) SendMyAddress();
00354                 
00355                 strLine = MyProfile.GetNick().Left( 255 );
00356                 
00357                 if ( strLine.GetLength() > 0 )
00358                 {
00359                         strLine = _T("X-Nick: ") + URLEncode( strLine ) + _T("\r\n");
00360                         m_pOutput->Print( strLine );
00361                 }
00362         }
00363         
00364         if ( m_pSource->m_nPort == INTERNET_DEFAULT_HTTP_PORT )
00365         {
00366                 int nSlash = m_pSource->m_sURL.ReverseFind( '/' );
00367                 if ( nSlash > 0 )
00368                 {
00369                         strLine = _T("Referrer: ") + m_pSource->m_sURL.Left( nSlash + 1 ) + _T("\r\n");
00370                         m_pOutput->Print( strLine );
00371                 }
00372         }
00373         
00374         m_pOutput->Print( "X-Queue: 0.1\r\n" );
00375         
00376         if ( m_pSource->m_bSHA1 && Settings.Library.SourceMesh && ! m_bTigerFetch && ! m_bMetaFetch )
00377         {
00378                 CString strURN = CSHA::HashToString( &m_pDownload->m_pSHA1, TRUE );
00379                 
00380                 m_pOutput->Print( "X-Content-URN: " );
00381                 m_pOutput->Print( strURN + _T("\r\n") );
00382                 
00383                 if ( m_pSource->m_nGnutella == 1 )
00384                         strLine = m_pDownload->GetSourceURLs( &m_pSourcesSent, 15, PROTOCOL_G1, m_pSource );
00385                 else
00386                         strLine = m_pDownload->GetSourceURLs( &m_pSourcesSent, 15, PROTOCOL_HTTP, m_pSource );
00387                 
00388                 if ( strLine.GetLength() )
00389                 {
00390                         m_pOutput->Print( "Alt-Location: " );
00391                         m_pOutput->Print( strLine + _T("\r\n") );
00392                 }
00393                 
00394                 if ( m_pDownload->IsShared() && m_pDownload->IsStarted() && Network.IsStable() )
00395                 {
00396                         strLine.Format( _T("http://%s:%i/uri-res/N2R?%s "),
00397                                 (LPCTSTR)CString( inet_ntoa( Network.m_pHost.sin_addr ) ),
00398                                 htons( Network.m_pHost.sin_port ),
00399                                 (LPCTSTR)strURN );
00400                         strLine += TimeToString( time( NULL ) - 180 );
00401                         m_pOutput->Print( "Alt-Location: " );
00402                         m_pOutput->Print( strLine + _T("\r\n") );
00403                 }
00404         }
00405         
00406         m_pOutput->Print( "\r\n" );
00407         
00408         SetState( dtsRequesting );
00409         m_tRequest                      = GetTickCount();
00410         m_bBusyFault            = FALSE;
00411         m_bRangeFault           = FALSE;
00412         m_bKeepAlive            = FALSE;
00413         m_bHashMatch            = FALSE;
00414         m_bGotRange                     = FALSE;
00415         m_bGotRanges            = FALSE;
00416         m_bQueueFlag            = FALSE;
00417         m_nContentLength        = SIZE_UNKNOWN;
00418         m_sContentType.Empty();
00419         
00420         m_sTigerTree.Empty();
00421         m_nRequests++;
00422         
00423         m_pSource->SetLastSeen();
00424         
00425         CDownloadTransfer::OnWrite();
00426         
00427         return TRUE;
00428 }
00429 
00431 // CDownloadTransferHTTP run handler
00432 
00433 BOOL CDownloadTransferHTTP::OnRun()
00434 {
00435         CDownloadTransfer::OnRun();
00436         
00437         DWORD tNow = GetTickCount();
00438         
00439         switch ( m_nState )
00440         {
00441         case dtsConnecting:
00442                 if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
00443                 {
00444                         theApp.Message( MSG_ERROR, IDS_CONNECTION_TIMEOUT_CONNECT, (LPCTSTR)m_sAddress );
00445                         if ( m_pSource != NULL ) m_pSource->PushRequest();
00446                         Close( TS_UNKNOWN );
00447                         return FALSE;
00448                 }
00449                 break;
00450 
00451         case dtsRequesting:
00452         case dtsHeaders:
00453                 if ( tNow - m_tRequest > Settings.Connection.TimeoutHandshake )
00454                 {
00455                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_REQUEST_TIMEOUT, (LPCTSTR)m_sAddress );
00456                         Close( m_bBusyFault || m_bQueueFlag ? TS_TRUE : TS_UNKNOWN );
00457                         return FALSE;
00458                 }
00459                 break;
00460 
00461         case dtsDownloading:
00462         case dtsFlushing:
00463         case dtsTiger:
00464         case dtsMetadata:
00465                 if ( tNow - m_mInput.tLast > Settings.Connection.TimeoutTraffic * 2 )
00466                 {
00467                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_TRAFFIC_TIMEOUT, (LPCTSTR)m_sAddress );
00468                         Close( TS_TRUE );
00469                         return FALSE;
00470                 }
00471                 break;
00472 
00473         case dtsBusy:
00474                 if ( tNow - m_tRequest > 1000 )
00475                 {
00476                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_BUSY, (LPCTSTR)m_sAddress, Settings.Downloads.RetryDelay / 1000 );
00477                         Close( TS_TRUE );
00478                         return FALSE;
00479                 }
00480                 break;
00481 
00482         case dtsQueued:
00483                 if ( tNow >= m_tRequest )
00484                 {
00485                         return StartNextFragment();
00486                 }
00487                 break;
00488 
00489         }
00490 
00491         return TRUE;
00492 }
00493 
00495 // CDownloadTransferHTTP read handler
00496 
00497 BOOL CDownloadTransferHTTP::OnRead()
00498 {
00499         CDownloadTransfer::OnRead();
00500         
00501         switch ( m_nState )
00502         {
00503         case dtsRequesting:
00504                 if ( ! ReadResponseLine() ) return FALSE;
00505                 if ( m_nState != dtsHeaders ) break;
00506 
00507         case dtsHeaders:
00508                 if ( ! ReadHeaders() ) return FALSE;
00509                 if ( m_nState != dtsDownloading ) break;
00510 
00511         case dtsDownloading:
00512                 return ReadContent();
00513 
00514         case dtsTiger:
00515                 return ReadTiger();
00516 
00517         case dtsMetadata:
00518                 return ReadMetadata();
00519 
00520         case dtsFlushing:
00521                 return ReadFlush();
00522 
00523         }
00524 
00525         return TRUE;
00526 }
00527 
00529 // CDownloadTransferHTTP read response line
00530 
00531 BOOL CDownloadTransferHTTP::ReadResponseLine()
00532 {
00533         CString strLine, strCode, strMessage;
00534         
00535         if ( ! m_pInput->ReadLine( strLine ) ) return TRUE;
00536         if ( strLine.IsEmpty() ) return TRUE;
00537 
00538         if ( strLine.GetLength() > 512 ) strLine = _T("#LINE_TOO_LONG#");
00539         
00540         theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD RESPONSE: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strLine );
00541         
00542         if ( strLine.GetLength() >= 12 && strLine.Left( 9 ) == _T("HTTP/1.1 ") )
00543         {
00544                 strCode         = strLine.Mid( 9, 3 );
00545                 strMessage      = strLine.Mid( 12 );
00546         }
00547         else if ( strLine.GetLength() >= 12 && strLine.Left( 9 ) == _T("HTTP/1.0 ") )
00548         {
00549                 strCode         = strLine.Mid( 9, 3 );
00550                 strMessage      = strLine.Mid( 12 );
00551         }
00552         else if ( strLine.GetLength() >= 8 && strLine.Left( 4 ) == _T("HTTP") )
00553         {
00554                 strCode         = strLine.Mid( 5, 3 );
00555                 strMessage      = strLine.Mid( 8 );
00556         }
00557         else
00558         {
00559                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_NOHTTP, (LPCTSTR)m_sAddress );
00560                 Close( TS_FALSE );
00561                 return FALSE;
00562         }
00563         
00564         if ( strCode == _T("200") || strCode == _T("206") )
00565         {
00566                 SetState( dtsHeaders );
00567         }
00568         else if ( strCode == _T("503") )
00569         {
00570                 if ( _tcsistr( strMessage, _T("range") ) != NULL )
00571                 {
00572                         m_bRangeFault = TRUE;
00573                 }
00574                 else
00575                 {
00576                         m_bBusyFault = TRUE;
00577                 }
00578                 
00579                 SetState( dtsHeaders );
00580         }
00581         else if ( strCode == _T("416") )
00582         {
00583                 m_bRangeFault = TRUE;
00584                 SetState( dtsHeaders );
00585         }
00586         else if ( FALSE && ( strCode == _T("301") || strCode == _T("302") ) )
00587         {
00588                 // TODO: Read "Location:" header and re-request
00589         }
00590         else
00591         {
00592                 strMessage.TrimLeft();
00593                 if ( strMessage.GetLength() > 128 ) strMessage = _T("No Message");
00594                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_HTTPCODE, (LPCTSTR)m_sAddress,
00595                         (LPCTSTR)strCode, (LPCTSTR)strMessage );
00596                 SetState( dtsHeaders );
00597                 m_bBadResponse = TRUE;
00598         }
00599         
00600         m_pHeaderName.RemoveAll();
00601         m_pHeaderValue.RemoveAll();
00602         
00603         return TRUE;
00604 }
00605 
00607 // CDownloadTransferHTTP read header lines
00608 
00609 BOOL CDownloadTransferHTTP::OnHeaderLine(CString& strHeader, CString& strValue)
00610 {
00611         theApp.Message( MSG_DEBUG, _T("%s: DOWNLOAD HEADER: %s: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue );
00612         
00613         if ( strHeader.CompareNoCase( _T("Server") ) == 0 )
00614         {
00615                 m_sUserAgent = strValue;
00616                 
00617                 if ( IsAgentBlocked() )
00618                 {
00619                         Close( TS_FALSE );
00620                         return FALSE;
00621                 }
00622                 
00623                 m_pSource->m_sServer = strValue;
00624                 if ( strValue.GetLength() > 64 ) strValue = strValue.Left( 64 );
00625                 
00626                 if ( _tcsistr( m_sUserAgent, _T("shareaza") ) != NULL ) m_pSource->SetGnutella( 3 );
00627                 if ( _tcsistr( m_sUserAgent, _T("trustyfiles") ) != NULL ) m_pSource->SetGnutella( 3 );
00628                 if ( _tcsistr( m_sUserAgent, _T("gnucdna") ) != NULL ) m_pSource->SetGnutella( 3 );
00629                 if ( _tcsistr( m_sUserAgent, _T("vagaa") ) != NULL ) m_pSource->SetGnutella( 3 );
00630                 if ( _tcsistr( m_sUserAgent, _T("mxie") ) != NULL ) m_pSource->SetGnutella( 3 );
00631                 if ( _tcsistr( m_sUserAgent, _T("adagio") ) != NULL ) m_pSource->SetGnutella( 2 );
00632         }
00633         else if ( strHeader.CompareNoCase( _T("Connection") ) == 0 )
00634         {
00635                 if ( strValue.CompareNoCase( _T("Keep-Alive") ) == 0 ) m_bKeepAlive = TRUE;
00636         }
00637         else if ( strHeader.CompareNoCase( _T("Content-Length") ) == 0 )
00638         {
00639                 _stscanf( strValue, _T("%I64i"), &m_nContentLength );
00640         }
00641         else if ( strHeader.CompareNoCase( _T("Content-Range") ) == 0 )
00642         {
00643                 QWORD nFirst = 0, nLast = 0, nTotal = 0;
00644                 
00645                 if ( _stscanf( strValue, _T("bytes %I64i-%I64i/%I64i"), &nFirst, &nLast, &nTotal ) != 3 )
00646                         _stscanf( strValue, _T("bytes=%I64i-%I64i/%I64i"), &nFirst, &nLast, &nTotal );
00647                 
00648                 if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
00649                 {
00650                         m_pDownload->m_nSize = nTotal;
00651                 }
00652                 else if ( m_bTigerFetch || m_bMetaFetch )
00653                 {
00654                         m_nOffset = nFirst;
00655                         m_nLength = nLast + 1 - nFirst;
00656                         if ( m_nContentLength == SIZE_UNKNOWN ) m_nContentLength = m_nLength;
00657                         return TRUE;
00658                 }
00659                 else if ( m_pDownload->m_nSize != nTotal )
00660                 {
00661                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE, (LPCTSTR)m_sAddress,
00662                                 (LPCTSTR)m_pDownload->GetDisplayName() );
00663                         Close( TS_FALSE );
00664                         return FALSE;
00665                 }
00666                 
00667                 if ( m_nOffset == SIZE_UNKNOWN && ! m_pDownload->GetFragment( this ) )
00668                 {
00669                         Close( TS_TRUE );
00670                         return FALSE;
00671                 }
00672                 
00673                 BOOL bUseful = m_pDownload->IsPositionEmpty( nFirst );
00674                 // BOOL bUseful = m_pDownload->IsRangeUseful( nFirst, nLast - nFirst + 1 );
00675                 
00676                 if ( nFirst == m_nOffset && nLast == m_nOffset + m_nLength - 1 && bUseful )
00677                 {
00678                         // Perfect match, good
00679                 }
00680                 else if ( nFirst >= m_nOffset && nFirst < m_nOffset + m_nLength && bUseful )
00681                 {
00682                         m_nOffset = nFirst;
00683                         m_nLength = nLast - nFirst + 1;
00684                         
00685                         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_USEFUL_RANGE, (LPCTSTR)m_sAddress,
00686                                 m_nOffset, m_nOffset + m_nLength - 1, (LPCTSTR)m_pDownload->GetDisplayName() );
00687                 }
00688                 else
00689                 {
00690                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_RANGE, (LPCTSTR)m_sAddress,
00691                                 (LPCTSTR)m_pDownload->GetDisplayName() );
00692                         Close( TS_TRUE );
00693                         
00694                         return FALSE;
00695                 }
00696                 
00697                 if ( m_nContentLength == SIZE_UNKNOWN ) m_nContentLength = m_nLength;
00698                 m_bGotRange = TRUE;
00699         }
00700         else if ( strHeader.CompareNoCase( _T("Content-Type") ) == 0 )
00701         {
00702                 m_sContentType = strValue;
00703         }
00704         else if ( strHeader.CompareNoCase( _T("Content-Encoding") ) == 0 )
00705         {
00706                 if ( Settings.Downloads.AllowBackwards && _tcsistr( strValue, _T("backwards") ) ) m_bRecvBackwards = TRUE;
00707         }
00708         else if (       strHeader.CompareNoCase( _T("X-Gnutella-Content-URN") ) == 0 ||
00709                                 strHeader.CompareNoCase( _T("X-Content-URN") ) == 0 ||
00710                                 strHeader.CompareNoCase( _T("Content-URN") ) == 0 )
00711         {
00712                 for ( CString strURNs = strValue + ',' ; ; )
00713                 {
00714                         int nPos = strURNs.Find( ',' );
00715                         if ( nPos < 0 ) break;
00716                         
00717                         strValue        = strURNs.Left( nPos );
00718                         strURNs         = strURNs.Mid( nPos + 1 );
00719                         strValue.TrimLeft();
00720                         
00721                         SHA1 pSHA1;
00722                         if ( CSHA::HashFromURN( strValue, &pSHA1 ) )
00723                         {
00724                                 if ( m_pSource->CheckHash( &pSHA1 ) )
00725                                 {
00726                                         m_bHashMatch = TRUE;
00727                                 }
00728                                 else
00729                                 {
00730                                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
00731                                                 (LPCTSTR)m_pDownload->GetDisplayName() );
00732                                         Close( TS_FALSE );
00733                                         return FALSE;
00734                                 }
00735                         }
00736                         
00737                         // TODO: Remove " ! m_bHashMatch "
00738                         
00739                         TIGEROOT pTiger;
00740                         if ( ! m_bHashMatch && CTigerNode::HashFromURN( strValue, &pTiger ) )
00741                         {
00742                                 if ( m_pSource->CheckHash( &pTiger ) )
00743                                 {
00744                                         m_bHashMatch = TRUE;
00745                                 }
00746                                 else
00747                                 {
00748                                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
00749                                                 (LPCTSTR)m_pDownload->GetDisplayName() );
00750                                         Close( TS_FALSE );
00751                                         return FALSE;
00752                                 }
00753                         }
00754                         
00755                         MD4 pED2K;
00756                         if ( CED2K::HashFromURN( strValue, &pED2K ) )
00757                         {
00758                                 if ( m_pSource->CheckHash( &pED2K ) )
00759                                 {
00760                                         m_bHashMatch = TRUE;
00761                                 }
00762                                 else
00763                                 {
00764                                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_HASH, (LPCTSTR)m_sAddress,
00765                                                 (LPCTSTR)m_pDownload->GetDisplayName() );
00766                                         Close( TS_FALSE );
00767                                         return FALSE;
00768                                 }
00769                         }
00770                 }
00771                 m_pSource->SetGnutella( 1 );
00772         }
00773         else if ( strHeader.CompareNoCase( _T("X-Metadata-Path") ) == 0 )
00774         {
00775                 if ( ! m_bMetaIgnore && Settings.Downloads.Metadata ) m_sMetadata = strValue;
00776         }
00777         else if ( strHeader.CompareNoCase( _T("X-TigerTree-Path") ) == 0 )
00778         {
00779                 if ( Settings.Downloads.VerifyTiger && ! m_bTigerIgnore && m_sTigerTree.IsEmpty() )
00780                 {
00781                         if ( strValue.Find( _T("tigertree/v1") ) < 0 &&
00782                                  strValue.Find( _T("tigertree/v2") ) < 0 )
00783                         {
00784                                 m_sTigerTree = strValue;
00785                         }
00786                 }
00787         }
00788         else if ( strHeader.CompareNoCase( _T("X-Thex-URI") ) == 0 )
00789         {
00790                 if ( Settings.Downloads.VerifyTiger && ! m_bTigerIgnore )
00791                 {
00792                         if ( StartsWith( strValue, _T("/") ) )
00793                         {
00794                                 m_sTigerTree = strValue.SpanExcluding( _T("; ") );
00795                                 Replace( m_sTigerTree, _T("ed2k=0"), _T("ed2k=1") );
00796                         }
00797                 }
00798                 m_pSource->SetGnutella( 1 );
00799         }
00800         else if (       strHeader.CompareNoCase( _T("X-Gnutella-Alternate-Location") ) == 0 ||
00801                                 strHeader.CompareNoCase( _T("Alt-Location") ) == 0 ||
00802                                 strHeader.CompareNoCase( _T("X-Alt") ) == 0 )
00803         {
00804                 if ( Settings.Library.SourceMesh )
00805                 {
00806                         if ( strValue.Find( _T("Zhttp://") ) < 0 )
00807                         {
00808                                 m_pDownload->AddSourceURLs( strValue, m_bHashMatch );
00809                         }
00810                 }
00811                 m_pSource->SetGnutella( 1 );
00812         }
00813         else if ( strHeader.CompareNoCase( _T("X-Available-Ranges") ) == 0 )
00814         {
00815                 m_bGotRanges = TRUE;
00816                 m_pSource->SetAvailableRanges( strValue );
00817                 m_pSource->SetGnutella( 1 );
00818                 if ( m_pSource->m_oAvailable.empty() )
00819                 {
00820                         theApp.Message( MSG_DEBUG, _T( "header did not include valid ranges, dropping source..." ) );
00821                         Close( TS_FALSE );
00822                         return FALSE;
00823                 }
00824         }
00825         else if ( strHeader.CompareNoCase( _T("X-Queue") ) == 0 )
00826         {
00827                 m_pSource->SetGnutella( 1 );
00828                 
00829                 m_bQueueFlag = TRUE;
00830                 CharLower( strValue.GetBuffer() );
00831                 strValue.ReleaseBuffer();
00832                 
00833                 int nPos = strValue.Find( _T("position=") );
00834                 if ( nPos >= 0 ) _stscanf( strValue.Mid( nPos + 9 ), _T("%i"), &m_nQueuePos );
00835                 
00836                 nPos = strValue.Find( _T("length=") );
00837                 if ( nPos >= 0 ) _stscanf( strValue.Mid( nPos + 7 ), _T("%i"), &m_nQueueLen );
00838                 
00839                 DWORD nLimit;
00840                 
00841                 nPos = strValue.Find( _T("pollmin=") );
00842                 if ( nPos >= 0 && _stscanf( strValue.Mid( nPos + 8 ), _T("%u"), &nLimit ) == 1 )
00843                 {
00844                         m_nRetryDelay = max( m_nRetryDelay, nLimit * 1000 + 3000  );
00845                 }
00846                 
00847                 nPos = strValue.Find( _T("pollmax=") );
00848                 if ( nPos >= 0 && _stscanf( strValue.Mid( nPos + 8 ), _T("%u"), &nLimit ) == 1 )
00849                 {
00850                         m_nRetryDelay = min( m_nRetryDelay, nLimit * 1000 - 8000 );
00851                 }
00852 
00853                 nPos = strValue.Find( _T("id=") );
00854                 if ( nPos >= 0 )
00855                 {
00856                         m_sQueueName = strValue.Mid( nPos + 3 );
00857                         m_sQueueName.TrimLeft();
00858                         if ( m_sQueueName.Find( '\"' ) == 0 )
00859                         {
00860                                 m_sQueueName = m_sQueueName.Mid( 1 ).SpanExcluding( _T("\"") );
00861                         }
00862                         else
00863                         {
00864                                 m_sQueueName = m_sQueueName.SpanExcluding( _T("\" ") );
00865                         }
00866                         if ( m_sQueueName == _T("s") ) m_sQueueName = _T("Small Queue");
00867                         else if ( m_sQueueName == _T("l") ) m_sQueueName = _T("Large Queue");
00868                 }
00869         }
00870         else if (       strHeader.CompareNoCase( _T("X-PerHost") ) == 0 ||
00871                                 strHeader.CompareNoCase( _T("X-Gnutella-maxSlotsPerHost") ) == 0 )
00872         {
00873                 int nLimit = 0;
00874                 
00875                 if ( _stscanf( strValue, _T("%i"), &nLimit ) != 1 )
00876                 {
00877                         Downloads.SetPerHostLimit( &m_pHost.sin_addr, nLimit );
00878                 }
00879         }
00880         else if ( strHeader.CompareNoCase( _T("X-Delete-Source") ) == 0 )
00881         {
00882                 m_bBadResponse = TRUE;
00883         }
00884         else if (       strHeader.CompareNoCase( _T("X-Nick") ) == 0 ||
00885                                 strHeader.CompareNoCase( _T("X-Name") ) == 0 ||
00886                                 strHeader.CompareNoCase( _T("X-UserName") ) == 0 )
00887         {
00888                 m_pSource->m_sNick = URLDecode( strValue );
00889         }
00890         else if ( strHeader.CompareNoCase( _T("X-Features") ) == 0 )
00891         {
00892                 if ( _tcsistr( strValue, _T("g2/") ) != NULL ) m_pSource->SetGnutella( 2 );
00893                 if ( _tcsistr( strValue, _T("gnet2/") ) != NULL ) m_pSource->SetGnutella( 2 );
00894                 if ( _tcsistr( strValue, _T("gnutella2/") ) != NULL ) m_pSource->SetGnutella( 2 );
00895                 m_pSource->SetGnutella( 1 );
00896         }
00897         
00898         return CTransfer::OnHeaderLine( strHeader, strValue );
00899 }
00900 
00902 // CDownloadTransferHTTP end of headers
00903 
00904 BOOL CDownloadTransferHTTP::OnHeadersComplete()
00905 {
00906         if ( m_bBadResponse )
00907         {
00908                 Close( TS_FALSE );
00909                 return FALSE;
00910         }
00911         else if ( ! m_pSource->CanInitiate( TRUE, TRUE ) )
00912         {
00913                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_DISABLED,
00914                         (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent );
00915                 Close( TS_FALSE );
00916                 return FALSE;
00917         }
00918         else if ( m_bBusyFault )
00919         {
00920                 m_nOffset = SIZE_UNKNOWN;
00921                 
00922                 if ( Settings.Downloads.QueueLimit > 0 && m_nQueuePos > Settings.Downloads.QueueLimit )
00923                 {
00924                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_QUEUE_HUGE,
00925                                 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName(), m_nQueuePos );
00926                         Close( TS_FALSE );
00927                         return FALSE;
00928                 }
00929                 else if ( m_bQueueFlag && m_nRetryDelay >= 600000 )
00930                 {
00931                         m_pSource->m_tAttempt = GetTickCount() + m_nRetryDelay;
00932                         m_bQueueFlag = FALSE;
00933                 }
00934                 
00935                 if ( m_bQueueFlag )
00936                 {
00937                         SetState( dtsFlushing );
00938                         m_tContent = m_mInput.tLast = GetTickCount();
00939                         return ReadFlush();
00940                 }
00941                 else
00942                 {
00943                         SetState( dtsBusy );
00944                         m_tRequest = GetTickCount();
00945                         return TRUE;
00946                 }
00947         }
00948         else if ( ! m_bGotRanges && ! m_bTigerFetch && ! m_bMetaFetch )
00949         {
00950                 m_pSource->SetAvailableRanges( NULL );
00951         }
00952         
00953         if ( m_bRangeFault )
00954         {
00955                 if ( m_pHost.sin_addr.S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr )
00956                 {
00957                         Close( TS_FALSE );
00958                         return FALSE;
00959                 }
00960                 
00961                 m_nOffset = SIZE_UNKNOWN;
00962                 SetState( dtsFlushing );
00963                 m_tContent = m_mInput.tLast = GetTickCount();
00964                 
00965                 return ReadFlush();
00966         }
00967         else if ( m_nContentLength == SIZE_UNKNOWN )
00968         {
00969                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE, (LPCTSTR)m_sAddress,
00970                         (LPCTSTR)m_pDownload->GetDisplayName() );
00971                 Close( TS_FALSE );
00972                 return FALSE;
00973         }
00974         else if ( m_bTigerFetch )
00975         {
00976                 if ( ! m_bGotRange )
00977                 {
00978                         m_nOffset = 0;
00979                         m_nLength = m_nContentLength;
00980                 }
00981                 else if ( m_nOffset > 0 )
00982                 {
00983                         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_TIGER_RANGE, (LPCTSTR)m_sAddress );
00984                         Close( TS_FALSE );
00985                         return FALSE;
00986                 }
00987                 
00988                 if (    m_sContentType.CompareNoCase( _T("application/tigertree-breadthfirst") ) &&
00989                                 m_sContentType.CompareNoCase( _T("application/dime") ) )
00990                 {
00991                         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_TIGER_RANGE, (LPCTSTR)m_sAddress );
00992                         Close( TS_FALSE );
00993                         return FALSE;
00994                 }
00995                 
00996                 SetState( dtsTiger );
00997                 m_tContent = m_mInput.tLast = GetTickCount();
00998                 
00999                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_TIGER_RECV, (LPCTSTR)m_sAddress,
01000                         (LPCTSTR)m_pSource->m_sServer );
01001                 
01002                 return ReadTiger();
01003         }
01004         else if ( m_bMetaFetch )
01005         {
01006                 if ( ! m_bGotRange )
01007                 {
01008                         m_nOffset = 0;
01009                         m_nLength = m_nContentLength;
01010                 }
01011                 
01012                 SetState( dtsMetadata );
01013                 m_tContent = m_mInput.tLast = GetTickCount();
01014                 
01015                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_METADATA_RECV,
01016                         (LPCTSTR)m_sAddress, (LPCTSTR)m_pSource->m_sServer );
01017                 
01018                 return ReadMetadata();
01019         }
01020         else if ( ! m_bGotRange )
01021         {
01022                 if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
01023                 {
01024                         m_pDownload->m_nSize = m_nContentLength;
01025                 }
01026                 else if ( m_pDownload->m_nSize != m_nContentLength )
01027                 {
01028                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE, (LPCTSTR)m_sAddress,
01029                                 (LPCTSTR)m_pDownload->GetDisplayName() );
01030                         Close( TS_FALSE );
01031                         return FALSE;
01032                 }
01033                 
01034                 if ( m_nOffset == SIZE_UNKNOWN && ! m_pDownload->GetFragment( this ) )
01035                 {
01036                         Close( TS_TRUE );
01037                         return FALSE;
01038                 }
01039                 
01040                 if ( ! m_pDownload->IsPositionEmpty( 0 ) )
01041                 {
01042                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_RANGE, (LPCTSTR)m_sAddress,
01043                                 (LPCTSTR)m_pDownload->GetDisplayName() );
01044                         Close( TS_TRUE );
01045                         return FALSE;
01046                 }
01047                 
01048                 m_nOffset = 0;
01049                 m_nLength = m_nContentLength;
01050         }
01051         
01052         if ( m_nContentLength != m_nLength )
01053         {
01054                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_RANGE, (LPCTSTR)m_sAddress,
01055                         (LPCTSTR)m_pDownload->GetDisplayName() );
01056                 Close( TS_FALSE );
01057                 return FALSE;
01058         }
01059         
01060         if ( ! m_bKeepAlive ) m_pSource->m_bCloseConn = TRUE;
01061         
01062         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONTENT, (LPCTSTR)m_sAddress,
01063                 (LPCTSTR)m_pSource->m_sServer );
01064         
01065         SetState( dtsDownloading );
01066         m_nPosition = 0;
01067         m_tContent = m_mInput.tLast = GetTickCount();
01068         
01069         return TRUE;
01070 }
01071 
01073 // CDownloadTransferHTTP read content
01074 
01075 BOOL CDownloadTransferHTTP::ReadContent()
01076 {
01077         if ( m_pInput->m_nLength > 0 )
01078         {
01079                 m_pSource->SetValid();
01080                 
01081                 DWORD nLength   = (DWORD)min( (QWORD)m_pInput->m_nLength, m_nLength - m_nPosition );
01082                 BOOL bSubmit    = FALSE;
01083                 
01084                 if ( m_bRecvBackwards )
01085                 {
01086                         BYTE* pBuffer = new BYTE[ nLength ];
01087                         CBuffer::ReverseBuffer( m_pInput->m_pBuffer, pBuffer, nLength );
01088                         bSubmit = m_pDownload->SubmitData(
01089                                 m_nOffset + m_nLength - m_nPosition - nLength, pBuffer, nLength );
01090                         delete [] pBuffer;
01091                 }
01092                 else
01093                 {
01094                         bSubmit = m_pDownload->SubmitData(
01095                                                 m_nOffset + m_nPosition, m_pInput->m_pBuffer, nLength );
01096                 }
01097                 
01098                 m_pInput->Clear();      // Clear the buffer, we don't want any crap
01099                 m_nPosition += nLength;
01100                 m_nDownloaded += nLength;
01101                 
01102                 if ( ! bSubmit )
01103                 {
01104                         BOOL bUseful = m_pDownload->IsRangeUsefulEnough( this,
01105                                 m_bRecvBackwards ? m_nOffset : m_nOffset + m_nPosition,
01106                                 m_nLength - m_nPosition );
01107                         
01108                         if ( /* m_bInitiated || */ ! bUseful )
01109                         {
01110                                 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_OVERLAP, (LPCTSTR)m_sAddress );
01111                                 Close( TS_TRUE );
01112                                 return FALSE;
01113                         }
01114                 }
01115         }
01116         
01117         if ( m_nPosition >= m_nLength )
01118         {
01119                 m_pSource->AddFragment( m_nOffset, m_nLength );
01120                 return StartNextFragment();
01121         }
01122         
01123         return TRUE;
01124 }
01125 
01127 // CDownloadTransferHTTP read Metadata
01128 
01129 BOOL CDownloadTransferHTTP::ReadMetadata()
01130 {
01131         if ( m_pInput->m_nLength < m_nLength ) return TRUE;
01132         
01133         CString strXML = m_pInput->ReadString( (DWORD)m_nLength, CP_UTF8 );
01134         
01135         if ( CXMLElement* pXML = CXMLElement::FromString( strXML, TRUE ) )
01136         {
01137                 if ( m_pDownload->m_pXML == NULL )
01138                 {
01139                         m_pDownload->m_pXML = pXML;
01140                 }
01141                 else
01142                 {
01143                         delete pXML;
01144                 }
01145         }
01146         
01147         m_pInput->Remove( (DWORD)m_nLength );
01148         
01149         return StartNextFragment();
01150 }
01151 
01153 // CDownloadTransferHTTP read tiger tree
01154 
01155 BOOL CDownloadTransferHTTP::ReadTiger()
01156 {
01157         if ( m_pInput->m_nLength < m_nLength ) return TRUE;
01158         
01159         if ( m_sContentType.CompareNoCase( _T("application/tigertree-breadthfirst") ) == 0 )
01160         {
01161                 m_pDownload->SetTigerTree( m_pInput->m_pBuffer, (DWORD)m_nLength );
01162                 m_pInput->Remove( (DWORD)m_nLength );
01163         }
01164         else if ( m_sContentType.CompareNoCase( _T("application/dime") ) == 0 )
01165         {
01166                 CString strID, strType, strUUID = _T("x");
01167                 DWORD nFlags, nBody;
01168                 
01169                 while ( m_pInput->ReadDIME( &nFlags, &strID, &strType, &nBody ) )
01170                 {
01171                         theApp.Message( MSG_DEBUG, _T("THEX DIME: %i, '%s', '%s', %i"),
01172                                 nFlags, (LPCTSTR)strID, (LPCTSTR)strType, nBody );
01173                         
01174                         if ( ( nFlags & 1 ) && strType.CompareNoCase( _T("text/xml") ) == 0 && nBody < 1024*1024 )
01175                         {
01176                                 BOOL bSize = FALSE, bDigest = FALSE, bEncoding = FALSE;
01177                                 CString strXML;
01178                                 
01179                                 strXML = m_pInput->ReadString( nBody, CP_UTF8 );
01180                                 
01181                                 if ( CXMLElement* pXML = CXMLElement::FromString( strXML ) )
01182                                 {
01183                                         if ( pXML->IsNamed( _T("hashtree") ) )
01184                                         {
01185                                                 if ( CXMLElement* pxFile = pXML->GetElementByName( _T("file") ) )
01186                                                 {
01187                                                         QWORD nSize = 0;
01188                                                         _stscanf( pxFile->GetAttributeValue( _T("size") ), _T("%I64i"), &nSize );
01189                                                         bSize = ( nSize == m_pDownload->m_nSize );
01190                                                 }
01191                                                 if ( CXMLElement* pxDigest = pXML->GetElementByName( _T("digest") ) )
01192                                                 {
01193                                                         if ( pxDigest->GetAttributeValue( _T("algorithm") ).CompareNoCase( _T("http://open-content.net/spec/digest/tiger") ) == 0 )
01194                                                         {
01195                                                                 bDigest = ( pxDigest->GetAttributeValue( _T("outputsize") ) == _T("24") );
01196                                                         }
01197                                                 }
01198                                                 if ( CXMLElement* pxTree = pXML->GetElementByName( _T("serializedtree") ) )
01199                                                 {
01200                                                         bEncoding = ( pxTree->GetAttributeValue( _T("type") ).CompareNoCase( _T("http://open-content.net/spec/thex/breadthfirst") ) == 0 );
01201                                                         strUUID = pxTree->GetAttributeValue( _T("uri") );
01202                                                 }
01203                                         }
01204                                         delete pXML;
01205                                 }
01206                                 
01207                                 theApp.Message( MSG_DEBUG, _T("THEX XML: size=%i, digest=%i, encoding=%i"),
01208                                         bSize, bDigest, bEncoding );
01209                                 
01210                                 if ( ! bSize || ! bDigest || ! bEncoding ) break;
01211                         }
01212                         else if ( strID == strUUID && strType.CompareNoCase( _T("http://open-content.net/spec/thex/breadthfirst") ) == 0 )
01213                         {
01214                                 m_pDownload->SetTigerTree( m_pInput->m_pBuffer, nBody );
01215                         }
01216                         else if ( strType.CompareNoCase( _T("http://edonkey2000.com/spec/md4-hashset") ) == 0 )
01217                         {
01218                                 m_pDownload->SetHashset( m_pInput->m_pBuffer, nBody );
01219                         }
01220                         
01221                         m_pInput->Remove( ( nBody + 3 ) & ~3 );
01222                         if ( nFlags & 2 ) break;
01223                 }
01224                 
01225                 m_pInput->Clear();
01226         }
01227         
01228         return StartNextFragment();
01229 }
01230 
01232 // CDownloadTransferHTTP read flushing
01233 
01234 BOOL CDownloadTransferHTTP::ReadFlush()
01235 {
01236         if ( m_nContentLength == SIZE_UNKNOWN ) m_nContentLength = 0;
01237         
01238         DWORD nRemove = min( m_pInput->m_nLength, (DWORD)m_nContentLength );
01239         m_nContentLength -= nRemove;
01240         
01241         m_pInput->Remove( nRemove );
01242         
01243         if ( m_nContentLength == 0 )
01244         {
01245                 if ( m_bQueueFlag )
01246                 {
01247                         SetState( dtsQueued );
01248                         m_tRequest = GetTickCount() + m_nRetryDelay;
01249 
01250                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_QUEUED,
01251                                 (LPCTSTR)m_sAddress, m_nQueuePos, m_nQueueLen,
01252                                 (LPCTSTR)m_sQueueName );
01253                 }
01254                 else if ( m_bRangeFault && !m_bGotRanges )
01255         {
01256                         /* we got a "requested range unavailable" error but the source doesn't
01257                         advertise available ranges; don't start to guess, try again later */
01258                         theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_416_WITHOUT_RANGE, (LPCTSTR)m_sAddress );
01259                         Close( TS_TRUE );
01260                         return FALSE;
01261         }
01262                 else if ( m_bRangeFault && m_bGotRanges && m_nRequests >= 2 )
01263                 {
01264                         /* we made two requests already and the source does advertise available
01265             ranges, but we still managed to request a wrong one */
01266                         // TODO: find the reason why this is happening
01267                         theApp.Message( MSG_ERROR, _T("BUG: Shareaza requested a fragment from host %s, although it knew that the host doesn't have that fragment") , (LPCTSTR)m_sAddress );
01268                         Close( TS_TRUE );
01269                         return FALSE;
01270                 }
01271                 else
01272                 {
01273                         return StartNextFragment();
01274                 }
01275         }
01276         
01277         return TRUE;
01278 }
01279 
01281 // CDownloadTransferHTTP dropped connection handler
01282 
01283 void CDownloadTransferHTTP::OnDropped(BOOL bError)
01284 {
01285         if ( m_nState == dtsConnecting )
01286         {
01287                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR, (LPCTSTR)m_sAddress );
01288                 if ( m_pSource != NULL ) m_pSource->PushRequest();
01289                 Close( TS_UNKNOWN );
01290         }
01291         else if ( m_nState == dtsBusy )
01292         {
01293                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_BUSY, (LPCTSTR)m_sAddress, Settings.Downloads.RetryDelay / 1000 );
01294                 Close( TS_TRUE );
01295         }
01296         else
01297         {
01298 //              if ( m_nState == dtsDownloading && m_nLength && m_pSource )
01299 //                      m_pSource->m_bCloseConn = TRUE;
01300                 
01301                 if ( m_bBusyFault || m_bQueueFlag )
01302                 {
01303                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_BUSY, (LPCTSTR)m_sAddress, Settings.Downloads.RetryDelay / 1000 );
01304                         Close( TS_TRUE );
01305                 }
01306                 else
01307                 {
01308                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_DROPPED, (LPCTSTR)m_sAddress );
01309                         Close( m_nState >= dtsDownloading ? TS_TRUE : TS_UNKNOWN );
01310                 }
01311         }
01312 }
01313 

Generated on Thu Dec 15 10:39:41 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2