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

HttpRequest.cpp

Go to the documentation of this file.
00001 //
00002 // HttpRequest.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 "HttpRequest.h"
00026 #include "Network.h"
00027 #include "Buffer.h"
00028 #include "SourceURL.h"
00029 
00030 
00032 // CHttpRequest construction
00033 
00034 CHttpRequest::CHttpRequest()
00035 {
00036         m_sUserAgent    = Settings.SmartAgent();
00037         m_hThread               = NULL;
00038         m_hInternet             = NULL;
00039         m_nLimit                = 0;
00040         m_nStatusCode   = 0;
00041         m_pPost                 = NULL;
00042         m_pResponse             = NULL;
00043         m_hNotifyWnd    = NULL;
00044 }
00045 
00046 CHttpRequest::~CHttpRequest()
00047 {
00048         Clear();
00049 }
00050 
00052 // CHttpRequest clear
00053 
00054 void CHttpRequest::Clear()
00055 {
00056         Cancel();
00057         
00058         CSingleLock pLock( &m_pSection );
00059         
00060         m_sURL.Empty();
00061         m_sRequestHeaders.Empty();
00062         
00063         m_nLimit                = 0;
00064         m_nStatusCode   = 0;
00065         
00066         m_sStatusString.Empty();
00067         m_pResponseHeaders.RemoveAll();
00068         
00069         if ( m_pPost != NULL ) delete m_pPost;
00070         m_pPost = NULL;
00071         
00072         if ( m_pResponse != NULL ) delete m_pResponse;
00073         m_pResponse = NULL;
00074 }
00075 
00077 // CHttpRequest request attributes
00078 
00079 BOOL CHttpRequest::SetURL(LPCTSTR pszURL)
00080 {
00081         CSingleLock pLock( &m_pSection );
00082         if ( IsPending() ) return FALSE;
00083         if ( pszURL == NULL || _tcsncmp( pszURL, _T("http"), 4 ) ) return FALSE;
00084         m_sURL = pszURL;
00085         return TRUE;
00086 }
00087 
00088 CString CHttpRequest::GetURL()
00089 {
00090         CSingleLock pLock( &m_pSection );
00091         CString strURL = m_sURL;
00092         return strURL;
00093 }
00094 
00095 void CHttpRequest::AddHeader(LPCTSTR pszKey, LPCTSTR pszValue)
00096 {
00097         CSingleLock pLock( &m_pSection );
00098         if ( IsPending() ) return;
00099         
00100         m_sRequestHeaders += pszKey;
00101         m_sRequestHeaders += _T(": ");
00102         m_sRequestHeaders += pszValue;
00103         m_sRequestHeaders += _T("\r\n");
00104 }
00105 
00106 void CHttpRequest::SetPostData(LPCVOID pBody, DWORD nBody)
00107 {
00108         CSingleLock pLock( &m_pSection );
00109         if ( IsPending() ) return;
00110         
00111         if ( m_pPost != NULL ) delete m_pPost;
00112         m_pPost = NULL;
00113         
00114         if ( pBody != NULL && nBody > 0 )
00115         {
00116                 m_pPost = new CBuffer();
00117                 m_pPost->Add( pBody, nBody );
00118         }
00119 }
00120 
00121 void CHttpRequest::SetUserAgent(LPCTSTR pszUserAgent)
00122 {
00123         CSingleLock pLock( &m_pSection );
00124         if ( IsPending() ) return;
00125         m_sUserAgent = pszUserAgent;
00126 }
00127 
00128 void CHttpRequest::LimitContentLength(DWORD nLimit)
00129 {
00130         CSingleLock pLock( &m_pSection );
00131         if ( IsPending() ) return;
00132         m_nLimit = nLimit;
00133 }
00134 
00135 void CHttpRequest::SetNotify(HWND hWnd, UINT nMsg, WPARAM wParam)
00136 {
00137         CSingleLock pLock( &m_pSection );
00138         m_hNotifyWnd    = hWnd;
00139         m_nNotifyMsg    = nMsg;
00140         m_nNotifyParam  = wParam;
00141 }
00142 
00144 // CHttpRequest response attributes
00145 
00146 int CHttpRequest::GetStatusCode()
00147 {
00148         CSingleLock pLock( &m_pSection );
00149         return IsPending() ? 0 : m_nStatusCode;
00150 }
00151 
00152 BOOL CHttpRequest::GetStatusSuccess()
00153 {
00154         CSingleLock pLock( &m_pSection );
00155         if ( IsPending() ) return FALSE;
00156         return m_nStatusCode >= 200 && m_nStatusCode < 300;
00157 }
00158 
00159 CString CHttpRequest::GetStatusString()
00160 {
00161         CSingleLock pLock( &m_pSection );
00162         return m_sStatusString;
00163 }
00164 
00165 CString CHttpRequest::GetHeader(LPCTSTR pszName)
00166 {
00167         CSingleLock pLock( &m_pSection );
00168         CString strIn, strOut;
00169         
00170         if ( IsPending() ) return strOut;
00171         
00172         strIn = pszName;
00173         CharLower( strIn.GetBuffer() );
00174         strIn.ReleaseBuffer();
00175         m_pResponseHeaders.Lookup( strIn, strOut );
00176         
00177         return strOut;
00178 }
00179 
00180 CString CHttpRequest::GetResponseString(UINT nCodePage)
00181 {
00182         CSingleLock pLock( &m_pSection );
00183         CString str;
00184         
00185         if ( ! IsPending() && m_pResponse != NULL )
00186         {
00187                 str = m_pResponse->ReadString( m_pResponse->m_nLength, nCodePage );
00188         }
00189         
00190         return str;
00191 }
00192 
00193 CBuffer* CHttpRequest::GetResponseBuffer()
00194 {
00195         CSingleLock pLock( &m_pSection );
00196         if ( IsPending() ) return NULL;
00197         return m_pResponse;
00198 }
00199 
00200 BOOL CHttpRequest::InflateResponse()
00201 {
00202         CSingleLock pLock( &m_pSection, TRUE );
00203         
00204         if ( IsPending() || m_pResponse == NULL ) return FALSE;
00205         
00206         CString strEncoding = GetHeader( _T("Content-Encoding") );
00207         
00208         if ( strEncoding.CompareNoCase( _T("deflate") ) == 0 )
00209         {
00210                 return m_pResponse->Inflate();
00211         }
00212         
00213         if ( strEncoding.CompareNoCase( _T("gzip") ) == 0 )
00214         {
00215                 return m_pResponse->Ungzip();
00216         }
00217         
00218         return TRUE;
00219 }
00220 
00222 // CHttpRequest process control
00223 
00224 BOOL CHttpRequest::Execute(BOOL bBackground)
00225 {
00226         if ( IsPending() ) return FALSE;
00227         Cancel();
00228         
00229         ASSERT( m_sURL.GetLength() > 0 );
00230         ASSERT( m_pPost == NULL );
00231         
00232         m_bCancel = FALSE;
00233         m_nStatusCode = 0;
00234         m_pResponseHeaders.RemoveAll();
00235         if ( m_pResponse != NULL ) delete m_pResponse;
00236         m_pResponse = NULL;
00237         
00238         if ( bBackground )
00239         {
00240                 m_hThread = AfxBeginThread( (AFX_THREADPROC)ThreadStart, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL )->m_hThread;
00241                 return TRUE;
00242         }
00243         else
00244         {
00245                 Run();
00246                 ASSERT( ! IsPending() );
00247                 return ( m_nStatusCode >= 200 && m_nStatusCode < 300 );
00248         }
00249 }
00250 
00251 BOOL CHttpRequest::IsPending()
00252 {
00253         return ( m_hInternet != NULL );
00254 }
00255 
00256 BOOL CHttpRequest::IsFinished()
00257 {
00258         return ( m_hInternet == NULL ) && ( m_nStatusCode != 0 );
00259 }
00260 
00261 void CHttpRequest::Cancel()
00262 {
00263         m_bCancel = TRUE;
00264         
00265         m_pSection.Lock();
00266         HINTERNET hInternet = m_hInternet;
00267         m_hInternet = NULL;
00268         m_pSection.Unlock();
00269         
00270         if ( hInternet != NULL ) InternetCloseHandle( hInternet );
00271         
00272         if ( m_hThread != NULL )
00273         {
00274                 ASSERT( GetCurrentThread() != m_hThread );
00275                 
00276         int nAttempt = 100;
00277                 for ( ; nAttempt > 0 ; nAttempt-- )
00278                 {
00279                         DWORD nCode = 0;
00280                         if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00281                         if ( nCode != STILL_ACTIVE ) break;
00282                         Sleep( 100 );
00283                 }
00284                 
00285                 if ( nAttempt == 0 )
00286                 {
00287                         TerminateThread( m_hThread, 0 );
00288                         Sleep( 100 );
00289                 }
00290         }
00291         
00292         m_hThread = NULL;
00293         m_bCancel = FALSE;
00294 }
00295 
00297 // CHttpRequest thread run
00298 
00299 UINT CHttpRequest::ThreadStart(LPVOID lpParameter)
00300 {
00301         CHttpRequest* pRequest = reinterpret_cast<CHttpRequest*>(lpParameter);
00302         return (DWORD)pRequest->Run();
00303 }
00304 
00305 int CHttpRequest::Run()
00306 {
00307         CSingleLock pLock( &m_pSection, FALSE );
00308         
00309         HINTERNET hInternet = InternetOpen( m_sUserAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
00310         
00311         if ( hInternet != NULL )
00312         {
00313                 m_hInternet = hInternet;
00314                 
00315                 RunRequest();
00316                 // RunDebugRequest();
00317                 
00318                 pLock.Lock();
00319                 if ( m_bCancel ) m_nStatusCode = 0;
00320                 hInternet = m_hInternet;
00321                 m_hInternet = NULL;
00322                 pLock.Unlock();
00323                 
00324                 if ( hInternet != NULL ) InternetCloseHandle( hInternet );
00325         }
00326         
00327         pLock.Lock();
00328         if ( m_hNotifyWnd != NULL ) PostMessage( m_hNotifyWnd, m_nNotifyMsg, m_nNotifyParam, 0 );
00329         pLock.Unlock();
00330         
00331         return 0;
00332 }
00333 
00334 void CHttpRequest::RunRequest()
00335 {
00336         HINTERNET hURL = InternetOpenUrl( m_hInternet, m_sURL, m_sRequestHeaders,
00337                 m_sRequestHeaders.GetLength(), INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | 
00338                 INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE , NULL );
00339         
00340         if ( hURL != NULL )
00341         {
00342                 RunResponse( hURL );
00343                 InternetCloseHandle( hURL );
00344         }
00345 }
00346 
00347 void CHttpRequest::RunResponse(HINTERNET hURL)
00348 {
00349         DWORD nLength = 255;
00350         BYTE nNull = 0;
00351         
00352         if ( ! HttpQueryInfo( hURL, HTTP_QUERY_STATUS_TEXT,
00353                 m_sStatusString.GetBuffer( nLength ), &nLength, 0 ) ) nLength = 0;
00354         m_sStatusString.ReleaseBuffer( nLength );
00355         if ( m_sStatusString.IsEmpty() ) return;
00356         
00357         if ( m_pResponse != NULL ) delete m_pResponse;
00358         m_pResponse = new CBuffer();
00359         
00360     DWORD nRemaining;
00361         for ( ; InternetQueryDataAvailable( hURL, &nRemaining, 0, 0 ) && nRemaining > 0 && ! m_bCancel ; )
00362         {
00363                 m_pResponse->EnsureBuffer( nRemaining );
00364                 if ( ! InternetReadFile( hURL, m_pResponse->m_pBuffer + m_pResponse->m_nLength,
00365                         nRemaining, &nRemaining ) ) break;
00366                 m_pResponse->m_nLength += nRemaining;
00367                 if ( m_nLimit > 0 && m_pResponse->m_nLength > m_nLimit ) break;
00368         }
00369         
00370         if ( nRemaining > 0 ) return;
00371         
00372         nLength = 0;
00373         HttpQueryInfo( hURL, HTTP_QUERY_RAW_HEADERS, &nNull, &nLength, 0 );
00374         if ( nLength == 0 ) return;
00375         
00376         LPTSTR pszHeaders = new TCHAR[ nLength + 1 ];
00377         pszHeaders[0] = pszHeaders[1] = 0;
00378         HttpQueryInfo( hURL, HTTP_QUERY_RAW_HEADERS, pszHeaders, &nLength, 0 );
00379         
00380         for ( LPTSTR pszHeader = pszHeaders ; *pszHeader ; )
00381         {
00382                 CString strHeader( pszHeader );
00383                 pszHeader += strHeader.GetLength() + 1;
00384                 
00385                 int nColon = strHeader.Find( ':' );
00386                 
00387                 if ( nColon > 0 )
00388                 {
00389                         CString strValue, strName = strHeader.Left( nColon );
00390                         strName.Trim(); 
00391                         CharLower( strName.GetBuffer() );
00392                         strName.ReleaseBuffer();
00393                         
00394                         while ( m_pResponseHeaders.Lookup( strName, strValue ) ) strName += _T('_');
00395 
00396                         strValue = strHeader.Mid( nColon + 1 );
00397                         strValue.Trim();
00398                         m_pResponseHeaders.SetAt( strName, strValue );
00399                 }
00400         }
00401         
00402         delete [] pszHeaders;
00403         
00404         nLength = 4;
00405         m_nStatusCode = 0;
00406         HttpQueryInfo( hURL, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
00407                 &m_nStatusCode, &nLength, 0 );
00408 }
00409 
00411 // CHttpRequest clear
00412 
00413 void CHttpRequest::CloseThread(HANDLE* phThread, LPCTSTR pszName)
00414 {
00415         if ( *phThread == NULL ) return;
00416         
00417     int nAttempt = 100;
00418         for ( ; nAttempt > 0 ; nAttempt-- )
00419         {
00420                 DWORD nCode;
00421                 if ( ! GetExitCodeThread( *phThread, &nCode ) ) break;
00422                 if ( nCode != STILL_ACTIVE ) break;
00423                 Sleep( 100 );
00424         }
00425         
00426         if ( nAttempt == 0 )
00427         {
00428                 TerminateThread( *phThread, 0 );
00429                 if ( pszName != NULL )
00430                 {
00431                         theApp.Message( MSG_DEBUG,
00432                                 _T("WARNING: Terminating %s thread."), pszName );
00433                 }
00434                 Sleep( 100 );
00435         }
00436         
00437         *phThread = NULL;
00438 }

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