www.pudn.com > downloadingNet.rar > inet.cpp
/* Inet.cpp : implementation of the CInet class Implements the internet communication class responsible for downloading files from the web server. It is basically a wrapper class for the WinInet calls. Author: Steven E. Sipe */ #include "stdafx.h" #include#include #include #include "inet.h" // Filenames to create if a link just uses a directory for a reference -- // g_szDefPage is for HTML pages, g_szUnknown is for multimedia files (in which // case something fatal happened) // const char *g_szDefPage = "index.htm"; const char *g_szUnknown = "unknown.fil"; // 定义协议类型即HTTP类型 static const char *szHttp = "http://"; // Request flags for session initialization: // Use existing INET setup, don't redirect to other servers automatically, // don't save pages in the browser's cache, always reload a page from the // server (don't use the browser's cached copy) static DWORD dwHttpRequestFlags = INTERNET_FLAG_EXISTING_CONNECT| INTERNET_FLAG_NO_AUTO_REDIRECT| INTERNET_FLAG_DONT_CACHE| INTERNET_FLAG_RELOAD; // 能够处理的数据类型,下面的定义表示能够处理所有的类型 static const TCHAR szHeaders[] = // _T("Accept: */*\r\n"); _T("Accept: */* \r"); // 构造函数 CInet::CInet() { m_hSession = NULL; m_nUniqueCount = 0; } // 析构函数 CInet::~CInet() { } // 初始化一个新的WinInet 会话 CInet::RESULTS CInet::OpenSession(BOOL bUseProxy, CString& strProxyName) { CInet::RESULTS ret; // 打开 m_hSession = ::InternetOpen("SiteSnagger", bUseProxy?INTERNET_OPEN_TYPE_PROXY:INTERNET_OPEN_TYPE_PRECONFIG, bUseProxy?(LPCTSTR)strProxyName:(LPCTSTR)NULL, NULL,0); // 是否成功 if(m_hSession != NULL) { DWORD dwTimeout = 4000; ::InternetSetOption(m_hSession,INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout,sizeof(dwTimeout)); ret = SUCCESS; } else ret = BAD_URL; return(ret); } // Close the WinInet session void CInet::CloseSession() { ::InternetCloseHandle(m_hSession); } ////////////////////// // Private operations ////////////////////// // 从远程服务器获得指定的文件 CInet::RESULTS CInet::DoGet(CString& strURL, BYTE **pbyBuffer, int& nLen, BOOL bIsTextPage) { CInet::RESULTS nRetCode = UNKNOWN_ERROR; CString strTempURL = strURL; HINTERNET hConnect = NULL; HINTERNET hURL = NULL; try { // 初始化返回的数据大笑 nLen = 0; // 确保文件路径正确 strTempURL.MakeLower(); if(strTempURL.Find(szHttp) < 0) { strTempURL = szHttp+strURL; strURL = szHttp+strURL; } else strTempURL = strURL; // 确保文件路径合法 CString strServer,strObject,strUser,strPassword; INTERNET_PORT nPort; DWORD dwServiceType; // 文件路径修正 strTempURL.SpanExcluding("#"); if(!AfxParseURLEx(strTempURL,dwServiceType,strServer,strObject,nPort, strUser,strPassword,ICU_NO_ENCODE)) return(CInet::BAD_URL); // 建立服务器连接 hConnect = ::InternetConnect(m_hSession,strServer, INTERNET_INVALID_PORT_NUMBER, strUser, strPassword, INTERNET_SERVICE_HTTP, 0, 0) ; // 打开HTTP会话 strObject = strObject.SpanExcluding("#"); const char *szTempX[2] = {szHeaders,NULL}; hURL = ::HttpOpenRequest(hConnect,"GET",strObject, HTTP_VERSION,NULL, szTempX,dwHttpRequestFlags,0) ; // 发送请求 ::HttpSendRequest(hURL,NULL,0,0,0); // 如果失败,则返回 if(hURL == NULL) return(CInet::BAD_URL); // 检查返回码 DWORD dwRet, dwLen; char szTemp[500]; dwLen = sizeof(szTemp); ::HttpQueryInfo(hURL,HTTP_QUERY_STATUS_CODE,szTemp,&dwLen,NULL); dwRet = (DWORD) atoi(szTemp); dwLen = sizeof(szTemp); m_dwRet = dwRet; // 需要重定向该页面 if(dwRet == HTTP_STATUS_MOVED || dwRet == HTTP_STATUS_REDIRECT || dwRet == HTTP_STATUS_REDIRECT_METHOD) { // 获得新的地址 CString strNewLocation; ::HttpQueryInfo(hURL,HTTP_QUERY_LOCATION,NULL,&dwLen,0); ::HttpQueryInfo(hURL,HTTP_QUERY_LOCATION, strNewLocation.GetBufferSetLength(dwLen), &dwLen,0); strNewLocation.ReleaseBuffer(dwLen); // 确信新地址包含服务器名 CString strNewServer; AfxParseURLEx(strNewLocation,dwServiceType,strNewServer,strObject,nPort, strUser,strPassword,ICU_NO_ENCODE); // 如果不包含服务器名 if(strNewServer.IsEmpty()) { // 增加服务器名 CString strTempLocation = strServer; if(strNewLocation.Left(1) != "/") strTempLocation += "/"; strTempLocation += strNewLocation; strNewLocation = strTempLocation; } //保存新的地址 strURL = strNewLocation; ::InternetCloseHandle(hURL); ::InternetCloseHandle(hConnect); return(LOCATION_MOVED); } else if(dwRet == HTTP_STATUS_REQUEST_TIMEOUT || dwRet == HTTP_STATUS_GATEWAY_TIMEOUT || dwRet == HTTP_STATUS_NOT_FOUND) { Sleep(500L); ::InternetCloseHandle(hURL); ::InternetCloseHandle(hConnect); return(TIMEOUT); } else if(dwRet == HTTP_STATUS_OK) { // 获取文件 BYTE *pbyTempBuffer = *pbyBuffer; DWORD dwTotalBytes = 0; DWORD dwBytesRead; BOOL bOkay = TRUE; // 获得大小 dwLen = sizeof(szTemp); ::HttpQueryInfo(hURL,HTTP_QUERY_CONTENT_LENGTH,szTemp,&dwLen,NULL); dwLen = (DWORD) atol(szTemp); // 确保没有获得错误的文件长度 if(dwLen <= 0) dwLen = 10000; // 循环读取数据 while(bOkay) { // 读取数据 bOkay = ::InternetReadFile(hURL,pbyTempBuffer,dwLen,&dwBytesRead); // 增加总下载数据量 if(bOkay && dwBytesRead > 0 && dwTotalBytes < MAX_INET_BUFFER-1) { dwTotalBytes += dwBytesRead; pbyTempBuffer += dwBytesRead; } else break; } // 以NULL结束缓冲区 pbyTempBuffer[0] = '\0'; nLen = dwTotalBytes; // 关闭文件 ::InternetCloseHandle(hURL); ::InternetCloseHandle(hConnect); return(SUCCESS); } } catch(...) { // Fatal error, just get out if(hURL) ::InternetCloseHandle(hURL); if(hConnect) ::InternetCloseHandle(hConnect); return(UNKNOWN_ERROR); } } // 保存数据 CInet::RESULTS CInet::SaveFile(CString& strFileName, LPCTSTR lpszDirectory, BYTE *pbyBuffer, int nLen) { CFile fileOut; CFileException ex; CString strTempName = lpszDirectory+strFileName; strTempName = strTempName.SpanExcluding("#"); // 创建当地文件 if(fileOut.Open(strTempName,CFile::modeCreate|CFile::modeWrite,&ex)) { // 写入数据 fileOut.Write(pbyBuffer,nLen); // 关闭文件 fileOut.Close(); } else return(BAD_FILENAME); return(SUCCESS); } ///////////////////// // Public operations ///////////////////// // Retrieves a page from the web server by calling DoGet(). Also handles // redirection to other servers as well as retries. CInet::RESULTS CInet::GetPage(CString& strURL, BYTE **pbyBuffer, int& nLen, BOOL bRedirectOkay) { int nRetries = 2; CInet::RESULTS ret; do { // Get the page ret = DoGet(strURL,pbyBuffer,nLen,TRUE); } while(nRetries-- && ((ret == LOCATION_MOVED && bRedirectOkay) || ret == TIMEOUT)); return(ret); } // Retrieves a file from the web server by calling DoGet(). Handles // redirection to other web servers as well as retries. CInet::RESULTS CInet::GetFile(CString& strURL, BYTE **pbyBuffer, int& nLen) { int nRetries = 2; CInet::RESULTS ret; do { // Get the file ret = DoGet(strURL,pbyBuffer,nLen,FALSE); } while(nRetries-- && (ret == LOCATION_MOVED || ret == TIMEOUT)); return(ret); } // Reset the "tie breaker" filename counter used by GenerateUniqueFileName(). void CInet::ResetUniqueCount() { m_nUniqueCount = 0; } // 产生一个唯一的文件名,如果有相同的文件名,则在后面增加_x来表示新的文件名 // x表示是数量,即是第几个同名的 void CInet::GenerateUniqueFileName(CString& strName, CString& strFileName, MAP_FILES_ARRAY &arrNameMap, BOOL bIsText) { BOOL bFound = FALSE; MAP_FILES entry; CString strTempName = strName; strTempName.MakeLower(); CString strTempFileName; // 分离出URL CString strServer,strObject,strUser,strPassword; INTERNET_PORT nPort; DWORD dwServiceType; AfxParseURLEx(strName,dwServiceType,strServer,strObject,nPort,strUser, strPassword,ICU_NO_ENCODE); // 获得合法的文件名 strFileName = SplitFileName(strObject,CInet::FNAME|CInet::EXT); // 是否是一个文件名 if(strFileName.IsEmpty()) { // 如果不是,使用默认的文件名或者错误 if(bIsText) strFileName = g_szDefPage; else strFileName = g_szUnknown; } else { // 如果是HTML文件 if(bIsText) { // 确保文件名以html文件结尾,这样,即使是.asp文件也能够执行 CString strExt = SplitFileName(strFileName,CInet::EXT); strExt.MakeLower(); if(strExt.Find("#") < 0 && strExt != ".htm" && strExt != ".html") { strFileName += ".htm"; } } } // 获得新的文件名 strTempFileName = strFileName; strTempFileName.MakeLower(); strTempName.MakeLower(); MAP_FILES *pEntry; CString strPage; POSITION pos = arrNameMap.GetStartPosition(); // 判断是否存在 for(int nEntryNum = 0; nEntryNum < arrNameMap.GetCount(); nEntryNum++) { arrNameMap.GetNextAssoc(pos,strPage,(CObject *&) pEntry); if(pos == NULL || pEntry == NULL) break; // 如果该页已经存在 if(strPage == strTempName) { strName = strPage; strFileName = pEntry->strFileName; return; } // 如果找到一个重名的输出文件 //则产生一个唯一的 if(pEntry->strFileName == strTempFileName) { // 退出循环 bFound = TRUE; break; } } // 如果找到重名的,则创建一个新的 if(bFound) { CString strTemp; CString strNewFileName; // 寻找后缀名 int nIndex = strFileName.Find("."); if(nIndex >= 0) strNewFileName = strFileName.Left(nIndex); else strNewFileName = strFileName; // 加入到文件名中 strTemp.Format("__%d",++m_nUniqueCount); strNewFileName += strTemp; if(nIndex >= 0) strNewFileName += strFileName.Mid(nIndex); // 保存新文件名 strFileName = strNewFileName; } } // 分割文件名 CString CInet::SplitFileName(LPCTSTR lpszPath, int nSplit) { CString strResult; char szPath[800],szDrive[800],szFileName[800],szExt[800]; _splitpath(lpszPath,szDrive,szPath,szFileName,szExt); if(nSplit & CInet::DRIVE) strResult += szDrive; if(nSplit & CInet::PATH) strResult += szPath; if(nSplit & CInet::FNAME) strResult += szFileName; if(nSplit & CInet::EXT) strResult += szExt; return(strResult); } CString CInet::GetErrorText() { CString strError; switch(m_dwRet) { case HTTP_STATUS_MOVED: case HTTP_STATUS_REDIRECT: case HTTP_STATUS_REDIRECT_METHOD: strError = "Redirected, but not found"; break; case HTTP_STATUS_REQUEST_TIMEOUT: case HTTP_STATUS_GATEWAY_TIMEOUT: strError = "Timed out on request"; break; case HTTP_STATUS_NOT_FOUND: case HTTP_STATUS_BAD_REQUEST: case HTTP_STATUS_GONE: strError = "Page or file not found"; break; case HTTP_STATUS_DENIED: case HTTP_STATUS_PAYMENT_REQ: case HTTP_STATUS_FORBIDDEN: //case HTTP_STATUS_AUTH_REFUSED: // strError = "Access denied"; // break; case HTTP_STATUS_PROXY_AUTH_REQ: strError = "Proxy authentication required"; break; default: strError.Format("WinInet error %d",m_dwRet); break; } return(strError); }