00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
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
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
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
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
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 }