Thread.cpp
上传用户:st5609838
上传日期:2013-03-29
资源大小:66k
文件大小:28k
源码类别:

搜索引擎

开发平台:

Visual C++

  1. // InetThread.cpp : implementation file
  2. //
  3. /*******************************************
  4. Pre-emptive Multithreading Web Spider
  5. Copyright (c) 1998 by Sim Ayers.
  6. *******************************************************************/
  7. #include "stdafx.h"
  8. #include "Spider.h"
  9. #include "ThreadParams.h"
  10. #include "Thread.h"
  11. #include "utily.h"
  12. #ifdef _DEBUG
  13. #define new DEBUG_NEW
  14. #undef THIS_FILE
  15. static char THIS_FILE[] = __FILE__;
  16. #endif
  17. extern  HANDLE hConnection;
  18. UINT g_nEntries = 0;
  19. CArray<CEntry*, CEntry*> g_entry;
  20. extern long lThreadCount;
  21. extern long lURLCount;
  22. static const TCHAR szHeaders[] = _T("Accept: text/*rn");
  23. static const TCHAR AgentName[] = _T("XYZ Spider");
  24. static DWORD dwHttpRequestFlags = INTERNET_FLAG_EXISTING_CONNECT |  INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE ; 
  25. static DWORD dwHttpRequestFlags2 = INTERNET_FLAG_EXISTING_CONNECT |  INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE |INTERNET_FLAG_NO_AUTO_REDIRECT;
  26. void CMyInternetSession::OnStatusCallback(DWORD  dwContext , DWORD dwInternetStatus,
  27. LPVOID  lpvStatusInformation , DWORD  dwStatusInformationLen )
  28. {
  29. CString strStatus= "";
  30. switch(dwInternetStatus)
  31. {
  32. case INTERNET_STATUS_STATE_CHANGE:
  33. strStatus="Busy";
  34. break;
  35. case INTERNET_STATUS_REQUEST_COMPLETE:
  36. strStatus="request complete";
  37. break;
  38. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  39. strStatus="Connecting to server...";
  40. break;
  41. case INTERNET_STATUS_RESOLVING_NAME:
  42. strStatus.Format("resolving name for %s", lpvStatusInformation);
  43. break;
  44. case INTERNET_STATUS_NAME_RESOLVED:
  45. strStatus.Format("resolved name for %s!", lpvStatusInformation);
  46. break;
  47. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  48. strStatus="Connected to server!";
  49. break;
  50. case INTERNET_STATUS_SENDING_REQUEST:
  51. strStatus="Sending request...";
  52. break;
  53. case INTERNET_STATUS_REQUEST_SENT:
  54. strStatus="Request sent";
  55. break;
  56. case INTERNET_STATUS_RECEIVING_RESPONSE:
  57. strStatus="Receiving response...";
  58. break;
  59. case INTERNET_STATUS_RESPONSE_RECEIVED:
  60. strStatus="Response received!";
  61. break;
  62. case INTERNET_STATUS_CLOSING_CONNECTION:
  63. strStatus="Closing connection...";
  64. break;
  65. case INTERNET_STATUS_CONNECTION_CLOSED:
  66. strStatus="Connection close!";
  67. break;
  68. case INTERNET_STATUS_HANDLE_CLOSING:
  69. strStatus="Closing Connection...";
  70. case INTERNET_STATUS_HANDLE_CREATED:
  71. strStatus="Connection created!";
  72. break;
  73. case INTERNET_STATUS_REDIRECT:
  74. strStatus ="Redirected to URL";
  75. break;
  76. case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
  77. default:
  78. strStatus.Format("Unknown status: %d", dwInternetStatus);
  79. break;
  80. }
  81. LPCSTR line = strStatus;
  82. if(m_pMainWnd !=NULL)
  83. {
  84. ::SendMessage (m_pMainWnd,WM_USER_SERVER_STATUS, 0,(LPARAM)line);
  85. LPCSTR lpstr = m_strHttpSite;
  86. ::SendMessage (m_pMainWnd,WM_USER_THREAD_STATUS, 0,(LPARAM)lpstr);
  87. }
  88. }
  89. // simple worker thread Proc function
  90. UINT CSpiderThread::ThreadFunc(LPVOID pParam)
  91. {
  92. ThreadParams * lpThreadParams = (ThreadParams*) pParam;
  93. CSpiderThread* lpThread = (CSpiderThread*) lpThreadParams->m_pThread;
  94. lpThread->ThreadRun(lpThreadParams);
  95. // Use  SendMessage instead of PostMessage here to keep the current thread count
  96. // Synchronizied. If the number of threads is greater than MAXIMUM_WAIT_OBJECTS (64)
  97. // the program will be come  unresponsive to user input
  98. ::SendMessage(lpThreadParams->m_hwndNotifyProgress,
  99. WM_USER_THREAD_DONE, 0, (LPARAM)lpThreadParams);  // deletes lpThreadParams and decrements the thread count
  100. return 0;
  101. }
  102. /////////////////////////////////////////////////////////////////////////////
  103. // CSpiderThread
  104. CSpiderThread::CSpiderThread(AFX_THREADPROC pfnThreadProc,ThreadParams *pThreadParams)
  105. :CWinThread(pfnThreadProc,pThreadParams)
  106. {
  107. m_pSession = NULL;
  108. m_pServer =NULL;
  109. m_pFile= NULL;
  110. m_strCurrentServer = "";
  111. m_bDone = FALSE;
  112. pThreadParams->m_pThread = this;
  113. }
  114. CSpiderThread::~CSpiderThread()
  115. {
  116. CleanUp();
  117. }
  118. void CSpiderThread::KillThread()
  119. {
  120. // Note: this function is called in the context of other threads,
  121. // not the thread itself.
  122. m_bDone = TRUE;
  123. CleanUp();
  124. }
  125. BOOL CSpiderThread::InitServer()
  126. {
  127. try{
  128. m_pSession = new CMyInternetSession(AgentName,m_nThreadID);
  129. int ntimeOut = 30;  // very important, can cause a Server time-out if set to low
  130. // or hang the thread if set to high.
  131. /*
  132. The time-out value in milliseconds to use for Internet connection requests. 
  133. If a connection request takes longer than this timeout, the request is canceled.
  134. The default timeout is infinite. */
  135. m_pSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000* ntimeOut);
  136. /* The delay value in milliseconds to wait between connection retries.*/
  137. m_pSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000);
  138. /* The retry count to use for Internet connection requests. If a connection 
  139. attempt still fails after the specified number of tries, the request is canceled.
  140. The default is five. */
  141. m_pSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,1);
  142.         m_pSession->EnableStatusCallback(TRUE);
  143. }
  144. catch (CInternetException* pEx)
  145. {
  146. // catch errors from WinINet
  147. //pEx->ReportError();
  148. m_pSession = NULL;
  149. pEx->Delete();
  150. return FALSE ;
  151. }
  152. return TRUE;
  153. }
  154. BEGIN_MESSAGE_MAP(CSpiderThread, CWinThread)
  155. //{{AFX_MSG_MAP(CSpiderThread)
  156. // NOTE - the ClassWizard will add and remove mapping macros here.
  157. //}}AFX_MSG_MAP
  158. END_MESSAGE_MAP()
  159. /////////////////////////////////////////////////////////////////////////////
  160. // CSpiderThread message handlers
  161. BOOL CSpiderThread::ThreadRun(ThreadParams *pThreadParams)
  162. {
  163. CString str;
  164. BOOL bRun = FALSE;
  165. bRun = InitServer();
  166. if (!bRun)
  167. return bRun;
  168. if(pThreadParams->m_pszURL.IsEmpty()) return FALSE;
  169. if (m_bDone)
  170. return 0;
  171. m_pSession->m_pMainWnd = pThreadParams->m_hwndNotifyProgress;
  172. if(!ParseURL(pThreadParams)) return FALSE;
  173. PrintStatus(pThreadParams,pThreadParams->m_pszURL);
  174. switch(pThreadParams->m_type)
  175. {
  176. case HTTP_GET_FILE:
  177. if(!GetHttpFile(pThreadParams->m_strServerName, 
  178.     pThreadParams->m_strObject,pThreadParams))
  179. {
  180. str.Format("Error in getting %s",(LPCTSTR)pThreadParams->m_pszURL);
  181. AfxMessageBox(str, MB_OK);
  182. }
  183. break;
  184. case HTTP_CHECK_URL_ROOT:
  185. if(GetHttpFile(pThreadParams->m_strServerName,pThreadParams->m_strObject, pThreadParams,FALSE))
  186. {
  187. if (m_bDone)
  188. return 0;
  189. CheckAllURLs(pThreadParams->m_strServerName,pThreadParams);
  190. }
  191. break;
  192. case HTTP_CHECK_URL:
  193. CheckURL(pThreadParams->m_strServerName, pThreadParams->m_strObject,pThreadParams);
  194. break;
  195. case HTTP_GET_HEADER:
  196. if(!GetServerHeader(pThreadParams->m_strServerName,pThreadParams->m_strObject,pThreadParams))
  197. {
  198. str.Format("Error in getting Server Response Header forn%s",(LPCTSTR)pThreadParams->m_pszURL);
  199. AfxMessageBox(str, MB_OK);
  200. }
  201. break;
  202. }
  203. return TRUE;
  204. }
  205. BOOL CSpiderThread::GetServerHeader(LPCTSTR ServerName, LPCTSTR strObject,ThreadParams *pThreadParams)
  206. {
  207. if(ServerName == NULL || strObject == NULL) return 0;
  208. DWORD dwRet = GetHttpStatus(ServerName, strObject);
  209. pThreadParams->m_Status = dwRet;
  210. if (m_bDone)
  211. return 0;
  212. if(dwRet <200  || dwRet > 400) return FALSE;
  213. if(m_pFile != NULL && m_pServer != NULL && m_pSession != NULL)
  214. {
  215. CString rString;
  216. m_pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF,rString);
  217. PrintLine(pThreadParams,rString);
  218. }
  219.   return TRUE;
  220. }
  221. BOOL CSpiderThread::GetHttpFile(LPCTSTR ServerName,LPCTSTR strObject,ThreadParams *pThreadParams,BOOL ViewFile)
  222. {
  223. CString rString;
  224. LPCTSTR lpsz;
  225. LPCTSTR lpszStop;
  226. int pdest,j=0;
  227. TCHAR sz[4096];
  228. memset(sz,'',sizeof(sz));
  229. pThreadParams->m_Contents = "";
  230. if(strObject  == NULL) return FALSE;
  231. if(GetHttpStatus(ServerName, strObject)!= 200)
  232. return FALSE;
  233. if(m_pFile != NULL && m_pServer != NULL)
  234. {
  235. m_pFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE,rString);
  236. pdest = rString.Find("text");
  237. if(pdest < 0 ) return FALSE;
  238. }
  239. if(m_pFile != NULL && m_pServer != NULL && m_pSession != NULL)
  240. {
  241. try
  242. {
  243. while (m_pFile->ReadString(sz, 4095))
  244. {
  245. rString = "";
  246. lpsz = sz;
  247. if(lpsz != NULL)
  248. {
  249. lpszStop = sz + lstrlen(sz);
  250. j=0;
  251. while (lpsz < lpszStop)
  252. {
  253. if(*lpsz =='n') rString += "rn";
  254. else rString += sz[j];
  255. ++lpsz;
  256. j++;
  257. }
  258. pThreadParams->m_Contents += rString;
  259. }
  260. }
  261. }
  262. catch (CInternetException* pEx)
  263. {
  264. // catch errors from WinINet
  265. //pEx->ReportError();
  266. m_pFile= NULL;
  267. pEx->Delete();
  268. return 0;
  269. }
  270. }
  271. if(ViewFile)
  272. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  273. WM_USER_THREAD_FILE, pThreadParams->m_threadID, (LPARAM)pThreadParams);
  274. return TRUE;
  275. }
  276. int LookUpEntry(LPCTSTR pszURL)
  277. {
  278. if(pszURL == NULL) return -1;
  279. CriticalSectionLock  plock;
  280. CString URL,strTemp;
  281. URL.Format("%s",(LPCTSTR)pszURL);
  282. int pdest = URL.Find(":");
  283. if(pdest>0)
  284. strTemp = URL.Right(URL.GetLength()-1 - pdest - 2);
  285. else
  286. strTemp = URL;
  287. int nRet = -1;
  288. for (UINT i = 0; i < g_nEntries; i ++)
  289. {
  290. if(strTemp.CompareNoCase(g_entry[i]->m_URL)==0)
  291. {
  292. nRet = i;
  293. break;
  294. }
  295. }
  296. return nRet;
  297. }
  298. int AddEntry(URLStatus * lpEntry)
  299. {
  300. CriticalSectionLock  plock;
  301. if(lpEntry->m_URL.IsEmpty())
  302. {
  303. return -1;
  304. }
  305. for (UINT i = 0; i < g_nEntries; i ++) { // only add entry once
  306. if(lpEntry->m_URL.Compare(g_entry[i]->m_URL)==0)
  307. {
  308. return -1;
  309. }
  310. }
  311. CEntry* newEntry = new CEntry;
  312. newEntry->m_URL = lpEntry->m_URL;
  313. newEntry->m_URLPage = lpEntry->m_URLPage;
  314. newEntry->m_Status = lpEntry->m_Status;
  315. newEntry->m_StatusString = lpEntry->m_StatusString;
  316. newEntry->m_LastModified = lpEntry->m_LastModified;
  317. newEntry->m_ContentType = lpEntry->m_ContentType;
  318. newEntry->m_ContentLength = lpEntry->m_ContentLength;
  319. g_nEntries++;
  320. // store in the array and get retVal to pass to the view for updating
  321. int retVal = g_entry.Add(newEntry);
  322. return retVal;
  323. }
  324. BOOL CSpiderThread::CheckURL(LPCTSTR ServerName, LPCTSTR strObject,ThreadParams *pThreadParams)
  325. {
  326. if(ServerName == NULL || strObject==NULL) return FALSE;
  327. DWORD dwRet;
  328. CString rString = "";
  329. rString.Format("%s%s",ServerName,strObject);
  330. int npos = LookUpEntry((LPCTSTR)rString);
  331. if (m_bDone) return 0;
  332. if(npos >= 0  && g_entry[npos]->m_Status != ERROR_INTERNET_TIMEOUT) // just print the status out to the view window if we have already visited the web page in question
  333. {
  334. pThreadParams->m_pStatus.m_URL = rString;
  335. pThreadParams->m_pStatus.m_URLPage = pThreadParams->m_pszURL;
  336. pThreadParams->m_pStatus.m_Status = g_entry[npos]->m_Status;
  337. pThreadParams->m_pStatus.m_ContentType = g_entry[npos]->m_ContentType;
  338. pThreadParams->m_pStatus.m_ContentLength = g_entry[npos]->m_ContentLength;
  339. pThreadParams->m_pStatus.m_LastModified = g_entry[npos]->m_LastModified;
  340. pThreadParams->m_pStatus.m_StatusString = g_entry[npos]->m_StatusString;
  341. }
  342. else
  343. {
  344. dwRet = GetHttpStatus(ServerName, strObject);
  345. pThreadParams->m_Status = dwRet;
  346. pThreadParams->m_pStatus.m_URL = rString;
  347. pThreadParams->m_pStatus.m_URLPage = pThreadParams->m_pszURL;
  348. pThreadParams->m_pStatus.m_Status = dwRet;
  349. pThreadParams->m_pStatus.m_ContentType ="";
  350. pThreadParams->m_pStatus.m_ContentLength = "";
  351. pThreadParams->m_pStatus.m_LastModified ="";
  352. if (m_bDone) return 0;
  353. if(m_pFile != NULL && m_pServer != NULL)
  354. {
  355. m_pFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE,pThreadParams->m_pStatus.m_ContentType);
  356. m_pFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,pThreadParams->m_pStatus.m_ContentLength);
  357. m_pFile->QueryInfo(HTTP_QUERY_LAST_MODIFIED,pThreadParams->m_pStatus.m_LastModified);
  358. }
  359. if (m_bDone) return 0;
  360. switch(dwRet)
  361. {
  362. case 200:
  363. pThreadParams->m_pStatus.m_StatusString = _T("ok");
  364. break;
  365. case 301:
  366. pThreadParams->m_pStatus.m_StatusString = _T("redirected to a new URL");
  367. break;
  368. case 302:
  369. pThreadParams->m_pStatus.m_StatusString = _T("resides under a different URL");
  370. break;
  371. case 401:
  372. pThreadParams->m_pStatus.m_StatusString = _T("auth required");
  373. break;
  374. case 402:
  375. pThreadParams->m_pStatus.m_StatusString = _T("payment required");
  376. break;
  377. case 403:
  378. pThreadParams->m_pStatus.m_StatusString = _T("forbidden");
  379. break;
  380. case 404:
  381. pThreadParams->m_pStatus.m_StatusString = _T("not found");
  382. break;
  383. case 400:
  384. pThreadParams->m_pStatus.m_StatusString = _T("Unintelligble request");
  385. break;
  386. case 405:
  387. pThreadParams->m_pStatus.m_StatusString = _T("requested method not supported");
  388. break;
  389. case 500:
  390. pThreadParams->m_pStatus.m_StatusString = _T("Unknown server error");
  391. break;
  392. case 501:
  393. pThreadParams->m_pStatus.m_StatusString = _T("Not implemented on Server");
  394. break;
  395. case 502:
  396. pThreadParams->m_pStatus.m_StatusString = _T("Server temporarily overloaded,busy");
  397. break;
  398. case 503:
  399. pThreadParams->m_pStatus.m_StatusString = _T("Server capacity reached, busy");
  400. break;
  401. case ERROR_INTERNET_TIMEOUT:
  402. pThreadParams->m_pStatus.m_StatusString = _T("Connection timed out");
  403. break;
  404. case ERROR_INTERNET_INVALID_URL:
  405. pThreadParams->m_pStatus.m_StatusString = _T("URL is invalid");
  406. break;
  407. case ERROR_INTERNET_NAME_NOT_RESOLVED:
  408. case 12029: // this seems to be the error for unresolved host names
  409. pThreadParams->m_pStatus.m_StatusString = _T("Could not resolve host name. Check it, and try again");
  410. break;
  411. case ERROR_INTERNET_SHUTDOWN:
  412. pThreadParams->m_pStatus.m_StatusString = _T("Win32 internet functions have been shut down");
  413. break;
  414. case ERROR_INTERNET_CONNECTION_ABORTED:
  415. pThreadParams->m_pStatus.m_StatusString = _T("Connection was aborted prematurely");
  416. break;
  417. case 0:
  418. case 1:
  419. case 2:
  420. default:
  421. pThreadParams->m_pStatus.m_StatusString = _T("no connection");
  422. break;
  423. }
  424. }
  425. AddEntry(&pThreadParams->m_pStatus);
  426. if (m_bDone) return 0;
  427. if(pThreadParams->m_hwndNotifyView != NULL)
  428. ::SendMessage(pThreadParams->m_hwndNotifyView,WM_USER_CHECK_DONE, 0, (LPARAM) &pThreadParams->m_pStatus);
  429. if(dwRet != 200) return FALSE;
  430. return TRUE;
  431. }
  432. DWORD CSpiderThread::NewConnection(LPCTSTR ServerName,LPCTSTR strObject)
  433. {
  434. if(ServerName  == NULL || strObject == NULL) return 0;
  435. DWORD dwRet =  HTTP_STATUS_OK;
  436.    INTERNET_PORT nPort = INTERNET_DEFAULT_HTTP_PORT;
  437.    try{
  438. m_pSession = new CMyInternetSession(ServerName,m_nThreadID);
  439. int ntimeOut = 30;
  440. /*
  441. The time-out value in milliseconds to use for Internet connection requests. 
  442. If a connection request takes longer than this timeout, the request is canceled.
  443. The default timeout is infinite. */
  444. m_pSession->SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,1000* ntimeOut);
  445. /* The delay value in milliseconds to wait between connection retries.*/
  446. m_pSession->SetOption(INTERNET_OPTION_CONNECT_BACKOFF,1000);
  447. /* The retry count to use for Internet connection requests. If a connection 
  448. attempt still fails after the specified number of tries, the request is canceled.
  449. The default is five. */
  450. m_pSession->SetOption(INTERNET_OPTION_CONNECT_RETRIES,2);
  451.      m_pSession->EnableStatusCallback(TRUE);
  452. m_pSession->m_strHttpSite.Format("%s%s",ServerName,strObject);
  453. }
  454. catch (CInternetException* pEx)
  455. {
  456. // catch errors from WinINet
  457. dwRet = pEx->m_dwError;
  458. m_pSession=NULL;
  459. pEx->Delete();
  460. return  dwRet;
  461. }
  462. try
  463. {
  464. m_pServer = m_pSession->GetHttpConnection(ServerName,nPort);
  465. }
  466. catch (CInternetException* pEx)
  467. {
  468. // catch errors from WinINet
  469. dwRet = pEx->m_dwError;
  470. m_pServer = NULL;
  471. pEx->Delete();
  472. CleanUp();
  473. return   dwRet;
  474. }
  475. m_strCurrentServer = ServerName;
  476. try
  477. {
  478. // This can never return NULL. The call may have failed, but it can
  479. // never be null.
  480. m_pFile = m_pServer->OpenRequest(_T("GET"),strObject,NULL, m_nThreadID, NULL, NULL, dwHttpRequestFlags);
  481. m_pFile->SendRequest();
  482. }
  483. catch (CInternetException* pEx)
  484. {
  485. // catch errors from WinINet
  486. dwRet = pEx->m_dwError;
  487. m_pFile = NULL;
  488. pEx->Delete();
  489. CleanUp();
  490. return dwRet;
  491. }
  492. return dwRet;
  493. }
  494. DWORD CSpiderThread::GetHttpStatus(LPCTSTR lpServerName,LPCTSTR strObject)
  495. {
  496. if(lpServerName  == NULL || strObject == NULL)return 0;
  497. INTERNET_PORT nPort = INTERNET_DEFAULT_HTTP_PORT;
  498. DWORD dwRet =  1;
  499. if (m_pSession == NULL) return dwRet;
  500. m_pSession->m_strHttpSite.Format("%s%s",lpServerName,strObject);
  501. dwRet =  2;
  502. if(m_pFile != NULL)
  503. {
  504. m_pFile->Close();
  505. delete m_pFile;
  506. m_pFile=NULL;
  507. }
  508. if (m_bDone) return 0;
  509. if (m_strCurrentServer != lpServerName)
  510. {
  511. // Picked a new server, close out connection and make a new one:
  512. if (m_pServer != NULL)
  513. {
  514. m_pServer->Close ();
  515. delete m_pServer;
  516. m_pServer = NULL;
  517. }
  518. }
  519. if (m_pServer == NULL)
  520. {
  521. try
  522. {
  523. m_pServer = m_pSession->GetHttpConnection(lpServerName,nPort);
  524. }
  525. catch (CInternetException* pEx)
  526. {
  527. // catch errors from WinINet
  528. //pEx->ReportError();
  529. dwRet = pEx->m_dwError;
  530. m_pServer = NULL;
  531. pEx->Delete();
  532. if(!CleanUp()) return FALSE;
  533. return dwRet;
  534. }
  535. if (m_bDone) return 0;
  536. m_strCurrentServer = lpServerName;
  537. }
  538. if (m_bDone)
  539. return 0;
  540. if (m_pServer == NULL) return dwRet;
  541.   
  542. try
  543. {
  544. // This can never return NULL. The call may have failed, but it can
  545. // never be null.
  546. m_pFile = m_pServer->OpenRequest(_T("GET"),strObject,NULL, m_nThreadID, NULL, NULL, dwHttpRequestFlags);
  547. m_pFile->SendRequest();
  548. }
  549. catch (CInternetException* pEx)
  550. {
  551. // catch errors from WinINet
  552. //pEx->ReportError();
  553. dwRet = pEx->m_dwError;
  554. m_pFile = NULL;
  555. pEx->Delete();
  556. if(!CleanUp()) return FALSE;
  557. if(dwRet == ERROR_INTERNET_TIMEOUT ) Sleep(1000);  // Connection timed out, try again on new connection
  558. dwRet = NewConnection(lpServerName,strObject);
  559. if(dwRet != HTTP_STATUS_OK) return dwRet;
  560. }
  561. if (m_bDone) return 0;
  562. if(m_pFile != NULL)
  563. m_pFile->QueryInfoStatusCode(dwRet);
  564.   return dwRet;
  565. }
  566. BOOL CSpiderThread::CheckAllURLs(LPCTSTR ServerName,ThreadParams *pThreadParams)
  567. {    
  568. if(ServerName == NULL) return FALSE;
  569. if(pThreadParams->m_pszURL.IsEmpty()) return FALSE;
  570. CString strMainURL = pThreadParams->m_pszURL;
  571. CStringList list;
  572. POSITION pos=NULL;
  573. CString strObject,strSub;
  574. CString strServer,strURL,strTemp;
  575. DWORD dwServiceType;
  576. INTERNET_PORT nPort;
  577. LPCTSTR lpszText =     pThreadParams->m_Contents.LockBuffer();
  578. if(lpszText == NULL) return FALSE;
  579. if(!GetHref(lpszText,_T("href"),list))
  580. return FALSE;
  581. pThreadParams->m_Contents.UnlockBuffer();
  582. if (m_bDone)
  583. return 0;
  584. int count = GetServerList(pThreadParams->m_pszURL,list,strSub);
  585. int pdest;
  586. int i;
  587. CriticalSectionLock  plock;
  588. lURLCount += count;
  589. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  590. WM_USER_URL_STATUS, 0, (LONG)lURLCount);
  591. if (m_bDone) return 0;
  592. if(count>0)
  593. {
  594. for(i=0; i<count; i++)
  595. {
  596. if( ( pos = list.FindIndex( i)) != NULL )
  597. {
  598. strObject = list.GetAt( pos );
  599. pdest = strObject.Find(ServerName);   // external link check
  600. if( pdest < 0 )
  601.     GetStatus(pThreadParams,HTTP_CHECK_URL,strObject); // create new threads for each URL
  602. if (m_bDone) return 0;
  603. if(lThreadCount >= MAXIMUM_WAIT_OBJECTS) 
  604. WaitForSingleObject(hConnection,INFINITE);
  605. }
  606. }
  607. for(i=0; i<count; i++)
  608. {
  609. if( ( pos = list.FindIndex( i)) != NULL )
  610. {
  611. strObject = list.GetAt( pos );
  612. pdest = strObject.Find(ServerName);  
  613. if( pdest > 0 )
  614. {
  615. if(AfxParseURL(strObject,dwServiceType,strServer,strURL,nPort))
  616. {
  617. if(!strURL.IsEmpty())
  618. CheckURL(ServerName,strURL,pThreadParams);  // check root links in the current file
  619. }
  620. }
  621. if (m_bDone) return 0;
  622. }
  623. }
  624. if(pThreadParams->m_RootLinks)
  625. {
  626. for(i=0; i<count; i++)
  627. {
  628. if( ( pos = list.FindIndex( i)) != NULL )
  629. {
  630. strObject = list.GetAt( pos );
  631. pdest = strObject.Find(ServerName);  // get root files and check the links in those files 
  632. if ( pdest > 0)
  633. {
  634. pdest = strObject.Find(strSub);
  635. if(( pdest > 0 ) && (strMainURL.Compare(strObject)!=0))
  636. GetStatus(pThreadParams,HTTP_CHECK_URL_ROOT,strObject);  // create new thread
  637. }
  638. if (m_bDone) return 0;
  639. if(lThreadCount >= MAXIMUM_WAIT_OBJECTS) 
  640. WaitForSingleObject(hConnection,INFINITE);
  641. }
  642. }
  643. }
  644. }
  645. return TRUE;
  646. }
  647. BOOL CSpiderThread::PrintLine(ThreadParams *pThreadParams,LPCSTR line)
  648. {
  649. pThreadParams->m_string = line;
  650. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  651. WM_USER_THREAD_PRINT, 0, (LPARAM)pThreadParams);
  652. return TRUE;
  653. }
  654. BOOL CSpiderThread::PrintFile(ThreadParams *pThreadParams,
  655. LPCSTR line)
  656. {
  657. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  658. WM_USER_THREAD_FILE, 0, (LPARAM)line);
  659. return TRUE;
  660. }
  661. BOOL CSpiderThread::PrintStatus(ThreadParams *pThreadParams,
  662. LPCSTR line)
  663. {
  664. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  665. WM_USER_THREAD_STATUS, 0, (LPARAM)line);
  666. return TRUE;
  667. }
  668. BOOL CSpiderThread::GetStatus(ThreadParams *pThreadParams,UINT ntype,LPCSTR line)
  669. {
  670. pThreadParams->m_checkURLName.Format("%s",(LPCSTR)line);
  671. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  672. WM_USER_THREAD_GETSTATUS, (UINT)ntype, (LPARAM)pThreadParams);
  673. return TRUE;
  674. }
  675. BOOL CSpiderThread::GetNewFile(ThreadParams *pThreadParams,UINT ntype,LPCSTR line)
  676. {
  677. pThreadParams->m_checkURLName.Format("%s",(LPCSTR)line);
  678. ::SendMessage(pThreadParams->m_hwndNotifyProgress,
  679. WM_USER_THREAD_GETNEWFILE, (UINT)ntype, (LPARAM)pThreadParams);
  680. return TRUE;
  681. }
  682. BOOL CSpiderThread::CleanUp()
  683. {
  684. m_strCurrentServer.Empty();
  685. try
  686. {
  687. if(m_pFile != NULL)
  688. { m_pFile->Close();
  689. delete m_pFile;
  690. m_pFile= NULL;
  691. }
  692. if (m_pServer!= NULL)
  693. {
  694. m_pServer->Close();
  695. delete m_pServer;
  696. m_pServer = NULL;
  697. }
  698. if (m_pSession != NULL)
  699. {
  700. m_pSession->Close();
  701. delete m_pSession;
  702. m_pSession = NULL;
  703. }
  704. }
  705. catch (CInternetException* pEx)
  706. {
  707. // catch errors from WinINet
  708. pEx->Delete();
  709. return FALSE;
  710. }
  711. if (m_bDone) return 0;
  712. return TRUE;
  713. }
  714. BOOL CSpiderThread::ParseURL(ThreadParams *pThreadParams)
  715. {
  716. BOOL bRet = FALSE;
  717. if(pThreadParams->m_pszURL.IsEmpty()) return bRet;
  718. LPCTSTR lpsz = pThreadParams->m_pszURL;
  719. if(lpsz  == NULL) return bRet;
  720. int nLen = lstrlen(lpsz);
  721. int i=0;
  722. while (nLen)
  723. {
  724. if( *lpsz == '/') i++;
  725. ++lpsz;
  726. nLen--;
  727. }
  728. if( i< 3) pThreadParams->m_pszURL += "/";
  729. try
  730. {
  731. AfxParseURL(pThreadParams->m_pszURL,pThreadParams->m_dwServiceType,pThreadParams->m_strServerName,pThreadParams->m_strObject,pThreadParams->m_nPort);
  732. }
  733. catch (CInternetException* pEx)
  734. {
  735. // catch errors from WinINet
  736. //pEx->ReportError();
  737. pEx->Delete();
  738. return bRet;
  739. }
  740. lpsz = pThreadParams->m_strObject;
  741. if(lpsz  == NULL) return bRet;
  742. bRet = TRUE;
  743. nLen = lstrlen(lpsz);
  744. BOOL bdot = FALSE;
  745. while (nLen)
  746. {
  747. if( *lpsz == '.') bdot = TRUE;
  748. ++lpsz;
  749. nLen--;
  750. }
  751. if(pThreadParams->m_strObject.GetLength()-1 > 0)
  752. {
  753. if( bdot == FALSE && pThreadParams->m_strObject[pThreadParams->m_strObject.GetLength()-1] != '/')
  754. pThreadParams->m_strObject += "/";
  755. }
  756. return bRet;
  757. }
  758. int CSpiderThread::GetServerList(LPCTSTR pszURL,CStringList& list, CString& lpSub)
  759. {
  760. if(pszURL  == NULL) return FALSE;
  761. CStringList Tlist;
  762. CString strObject,strTemp,str="";
  763. CString strSub,strServer,strURL,strServerName;
  764. POSITION pos=NULL;
  765. POSITION Tpos=NULL;
  766. LPCTSTR lpsz;
  767. int nLen;
  768. int count = 0;
  769. int pdest2;
  770. count = list.GetCount();
  771. int Tcount,i,ti,pdest,j,k;
  772. for(i=0; i<count; i++)
  773. {
  774. if( ( pos = list.FindIndex( i)) != NULL )
  775. {
  776. strObject = list.GetAt( pos );
  777. if(strObject.GetLength() -1 > 0)
  778. {
  779. k=0; j= 0;
  780. lpsz = strObject;
  781. if(lpsz  != NULL)
  782. {
  783. nLen = lstrlen(lpsz);
  784. while (nLen)
  785. {
  786. if( *lpsz == ':') k=j;
  787. ++lpsz;
  788. nLen--;
  789. j++;
  790. }
  791. }
  792. if(k > 6)
  793. {
  794. if(strObject[k-4] == 'h' )
  795. {
  796. strURL =  strObject.Right(strObject.GetLength() - k+4 );
  797. strObject = strURL;
  798. }
  799. }
  800. pdest = strObject.FindOneOf("# %");     // don't check   /index.html#new
  801. pdest2 = strObject.Find("ftp:");     // don't check   ftp://somefile.zip
  802. if(pdest<0 &&  pdest2 < 0  &&  strObject[0] != '.')   // don't check      ../somedirectory
  803. {
  804. Tcount = Tlist.GetCount();
  805. for(ti=0; ti<Tcount; ti++)
  806. {
  807. if( ( Tpos = Tlist.FindIndex( ti)) != NULL ) // remove duplicate URLs
  808. {
  809. strTemp = Tlist.GetAt( Tpos );
  810. if (strObject.Compare(strTemp) == 0)
  811. Tlist.RemoveAt(Tpos);
  812. }
  813. }
  814. if(!strObject.IsEmpty()) Tlist.AddTail(strObject);
  815. }
  816. }
  817. }
  818. }
  819. list.RemoveAll();
  820. Tcount = Tlist.GetCount();
  821. for(ti=0; ti<Tcount; ti++) // get rid of /  in  /directory/somefile.html
  822. {
  823. if( ( Tpos = Tlist.FindIndex( ti)) != NULL )
  824. {
  825. strTemp = Tlist.GetAt( Tpos );
  826. if(strTemp.GetLength()-1 > 0)
  827. {
  828. if (strTemp[0] != '/' )
  829. str = strTemp;
  830. else
  831. str = strTemp.Right(strTemp.GetLength()-1);
  832. list.AddTail(str);
  833. }
  834. }
  835. }
  836. strURL = pszURL;
  837. strSub = "";
  838. strServer = "";
  839. strTemp = "";
  840. CString strDirectory="";
  841. lpsz = pszURL;
  842. if(lpsz  != NULL)
  843. {
  844. nLen = lstrlen(lpsz);
  845. i=0;
  846. while (nLen)
  847. {
  848. if( *lpsz == '/') i++;
  849. ++lpsz;
  850. nLen--;
  851. }
  852. if( i<=2) strURL += "/";
  853. }
  854. if(!strURL.IsEmpty()){
  855. pdest = strURL.Find("//");
  856. if (pdest >= 0)
  857. {
  858. strTemp = strURL.Mid(pdest +2);  // get rid of http://
  859. }
  860. }
  861. if(!strTemp.IsEmpty()){
  862. pdest = strTemp.Find( '/');
  863. if (pdest >= 0)
  864. strServer = strTemp.Left(pdest);  // find server name
  865. }
  866. if(!strURL.IsEmpty()){
  867. pdest = strURL.ReverseFind('/');  // get rid of URL Object
  868. if (pdest >= 0)
  869. strSub =  strURL.Left(pdest);
  870. }
  871. if(!strSub.IsEmpty()){ // find directory on server 
  872. pdest = strSub.Find(strServer);
  873. if (pdest >= 0)
  874. strDirectory =  strSub.Right(strSub.GetLength()-1 - pdest - strServer.GetLength());
  875. }
  876. strSub ="";
  877. if(strDirectory.GetLength()-1 > 0){
  878. if (strDirectory[0] != '/' )
  879. strSub += "/" + strDirectory;
  880. else strSub = strDirectory;
  881. if(strSub.GetLength()-1 > 0){
  882. if (strDirectory[strDirectory.GetLength()-1] != '/'  &&  strSub[strSub.GetLength()-1] != '/')
  883. strSub += "/" ;
  884. }
  885. }
  886. if(strSub.IsEmpty()) strSub = "/" ;
  887. lpSub = strSub;
  888. Tlist.RemoveAll();
  889. count = list.GetCount();
  890. for(i=0; i<count; i++) //  add the server name and directory to the URL
  891. {
  892. if( ( pos = list.FindIndex( i)) != NULL )
  893. {
  894. strObject = list.GetAt( pos );
  895. if(!strObject.IsEmpty())
  896. {
  897. pdest = strObject.Find( _T("http"));
  898. if( pdest < 0 )
  899. strURL =  _T("http://") + strServer + strSub + strObject;  // need to fix for https
  900. else
  901. strURL = strObject;
  902. Tlist.AddTail(strURL);
  903. }
  904. }
  905. }
  906. list.RemoveAll();
  907. count = Tlist.GetCount(); // rewrite the CStringList list 
  908. for(i=0; i<count; i++)
  909. {
  910. if( ( pos = Tlist.FindIndex( i)) != NULL )
  911. {
  912. strObject = Tlist.GetAt( pos );
  913. if(!strObject.IsEmpty())
  914. {
  915. pdest = strObject.Find("amp;");     // fix  /index.cgi?&amp;file=....#new
  916. if(pdest>0)
  917. {
  918. strURL = strObject.Left(pdest);
  919. strTemp =  strObject.Right(strObject.GetLength() - pdest - 1 -3);
  920. strObject = strURL + strTemp + '';
  921. }
  922. int npos = LookUpEntry((LPCTSTR)strObject);
  923. if(npos < 0  )
  924. list.AddTail(strObject);
  925. }
  926. }
  927. }
  928. return count;
  929. }