⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 download.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/**
 *  Download.cpp
 *
 *  Copyright (C) 2008  David Andrs <pda@jasnapaka.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#if defined PRSSR_APP
	#include "../StdAfx.h"
	#include "../prssr.h"
#endif

#include "Download.h"

//#include "..\share\defs.h"
#include "../Config.h"
#include "HttpConnection.h"
#include "../Site.h"
#include "../Feed.h"
//#include "..\FeedFile.h"

#include "../../share/helpers.h"
#include "../../share/fs.h"
#include "../../share/str.h"
#include "../base64/base64.h"

#include "Connection.h"
#if defined PRSSR_APP
	#include "../ctrls/CePropertySheet.h"
	#include "../AuthenticationDlg.h"
//	#include "..\MainFrm.h"
#endif
#include "../digest/digcalc.h"
//#include "SuspendKiller.h"

#ifdef MYDEBUG
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#include "../debug/crtdbg.h"
#define new MYDEBUG_NEW
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//#include <afxinet.h>
#define INITGUID
#include <connmgr.h>
#include <connmgr_proxy.h>


BOOL DownloadFavIcon(const CString &url, const CString &fileName) {
	LOG0(3, "DownloadFavIcon()");

	BOOL ret = FALSE;
	CDownloader downloader;

	// url of favicon
	DWORD serviceType;
	CString sServer, sObject;
	INTERNET_PORT nPort;
	ParseURL(url, serviceType, sServer, sObject, nPort);

	CString faviconURL;
	faviconURL.Format(_T("%s://%s/favicon.ico"),
		serviceType == INET_SERVICE_HTTPS ? _T("https") : _T("http"), sServer);

	// temp file name
	CString sTmpFileName;
	LPTSTR tmpFileName = sTmpFileName.GetBufferSetLength(MAX_PATH + 1);
	GetTempFileName(Config.CacheLocation, _T("rsr"), 0, tmpFileName);

	if (downloader.SaveHttpObject(faviconURL, tmpFileName)) {
		DeleteFile(fileName);
		CreatePath(fileName);
		if (MoveFile(tmpFileName, fileName))
			return TRUE;					// ok, we have got a favicon
		else {
			DeleteFile(tmpFileName);
			return FALSE;
		}
	}
	else {
		// no favicon => delete temp file
		DeleteFile(tmpFileName);
		return FALSE;
	}
}

// CDownloader /////////////////////////////////

CDownloader::CDownloader() {
	LOG0(3, "CDownloader::CDownloader()");

	HTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
	AuthSet = FALSE;
}

CDownloader::~CDownloader() {
	LOG0(5, "CDownloader::~CDownloader()");
	FreeAdditionalHeaders();
}

void CDownloader::Reset() {
	ETag.Empty();
	LastModified.Empty();
	Charset.Empty();
	Cookies.RemoveAll();
}

void CDownloader::SaveHeaders(CHttpResponse *res) {
	LOG0(5, "CDownloader::SaveHeaders()");

	CString value;

	if (res->GetHeader(_T("Content-Type"), value)) {
		value.MakeLower();
		int nPosCharset = value.Find(_T("charset="));
		if (nPosCharset != -1) {
			int nPosSemiColon = value.Find(';', nPosCharset);
			Charset = nPosSemiColon == -1 ? value.Mid(nPosCharset + 8) : value.Mid(nPosCharset + 8, nPosSemiColon - nPosCharset - 8);
		}

		int nPosSemiColon = value.Find(';');
		if (nPosSemiColon != -1) MimeType = value.Left(nPosSemiColon);
		else MimeType = value;
		value.TrimRight();
	}
}

void CDownloader::SetupProxy() {
	// setup proxy for connection
	if (Config.UseConnManager) {
		if (Connection.IsAvailable() && Connection.IsProxyRequired()) {
			PROXY_CONFIG *proxyInfo = Connection.GetProxyInfo();

			// TODO: other types of proxy?
			CProxy proxy;
			proxy.Type = PROXY_TYPE_HTTP;

			CString sProxyServer = proxyInfo->szProxyServer;
			int nColon = sProxyServer.Find(':');
			if (nColon != NULL) {
				proxy.HostName = sProxyServer.Left(nColon);
				swscanf(sProxyServer.Mid(nColon + 1), _T("%d"), &proxy.Port);
			}
			HttpConnection.SetProxy(&proxy);
		}
	}
	else {
		if (Config.ProxyProfileIdx != -1)
			HttpConnection.SetProxy(&(Config.ProxyProfiles[Config.ProxyProfileIdx]->ProxyConfig));
	}
}

void CDownloader::OnConnection(LPVOID context) {
	SetupProxy();
}

void CDownloader::OnFileDownloaded(LPVOID context) {
}

BOOL CDownloader::OnBeforeFileDownload(LPVOID context) {
	return TRUE;
}

BOOL CDownloader::OnAuthentication(LPVOID context) {
	LOG0(3, "CDownloader::OnAuthentication()");

	if (AuthSet) {
		State = DOWNLOAD_STATE_AUTHENTICATED;
		return TRUE;	// user predefined values
	}
	else {
#if defined PRSSR_APP
		// in pRSSreader main app, we ask user for auth details
		// get username/password
		CCePropertySheet sheet(IDS_AUTHENTICATION, theApp.m_pMainWnd);
		CAuthenticationPg pgAuth;
		sheet.SetMenu(IDR_DONE);
		sheet.AddPage(&pgAuth);

		pgAuth.m_strSite = ServerName;
		pgAuth.m_strRealm = Realm;
		if (sheet.DoModal()) {
			UserName = pgAuth.m_strUserName;
			Password = pgAuth.m_strPassword;
			SavePassword = pgAuth.m_bSavePassword;

			return TRUE;
		}
		else
			return FALSE;
#else
		return FALSE;
#endif
	}
}

///

BOOL CDownloader::DoBasicAuthentication(CHttpRequest *&req, CHttpResponse *&res, LPVOID context) {
	LOG0(5, "CDownloader::DoBasicAuthentication()");

	BOOL ret = FALSE;
	do {
		// force closing of the connection
		HttpConnection.Close();
		delete res; res = NULL;

		// ask for username and password
		if (OnAuthentication(context)) {
			// add authentication credentials to the original request
			CString userpass;
			userpass.Format(_T("%s:%s"), UserName, Password);
			CString authentication;
			authentication.Format(_T("Basic %s"), base64encode(userpass));
			req->SetHeader(AuthResponseHeader, authentication);

			// new connection with authentication credentials
			if (HttpConnection.Open(ServiceType, ServerName, Port)) {
				HttpConnection.SendRequest(req);
				res = HttpConnection.ReceiveResponse();
				if (res != NULL) {
					if (res->GetStatusCode() == HTTP_STATUS_OK) {
						State = DOWNLOAD_STATE_AUTHENTICATED;
						Updated = TRUE;
					}
					else {
						if (AuthSet) {
							// authorization failed
							Error = DOWNLOAD_ERROR_AUTHORIZATION_FAILED;
							break;
						}
						else {
							// try re-enter the user name and password
						}
					}
				}
				else {
					// response error
					Error = DOWNLOAD_ERROR_RESPONSE_ERROR;
					break;
				}
			}
			else {
				// can not connect
				Error = DOWNLOAD_ERROR_CONNECTION_ERROR;
				break;
			}
		}
		else {
			// auth canceled
			Error = DOWNLOAD_ERROR_AUTHENTICATION_ERROR;
			break;
		}
	} while (State != DOWNLOAD_STATE_AUTHENTICATED);

	return State == DOWNLOAD_STATE_AUTHENTICATED;
}

void CDownloader::PrepareAuthorizationHeader(int nc, const CString &uri, const CString &userName, const CString &password, CString &header) {
	LOG0(5, "CDownloader::PrepareAuthorizationHeader()");

	HASHHEX hhHA1;
	HASHHEX hhHA2 = "";
	HASHHEX hhResponse;

	char szNonceCount[9] = { 0 };
	sprintf(szNonceCount, "%08d", nc);

	char *pszAlg = WCharToChar(Algorithm);
	char *pszUser = WCharToChar(userName);
	char *pszRealm = WCharToChar(Realm);
	char *pszPass = WCharToChar(password);
	char *pszNonce = WCharToChar(Nonce);
	// FIXME: generate something
	char *pszCNonce = "0a4f113b";
	char *pszQop = NULL;
	char *pszMethod = "GET";					// we use always GET method
	char *pszURI = WCharToChar(uri);

	if (!Qop.IsEmpty()) {
		int nComma = Qop.Find(',');
		if (nComma != -1) {
			int nStart = 0;
			CString sItem;
			while (nComma != -1) {
				sItem = Qop.Mid(nStart, nComma - nStart);
				if (sItem.CompareNoCase(_T("auth")) == 0) {
					pszQop = new char [5];
					strcpy(pszQop, "auth");
					break;
				}
				else if (sItem.CompareNoCase(_T("auth-int")) == 0) {
					pszQop = new char [9];
					strcpy(pszQop, "auth-int");
					break;
				}
				nStart = nComma + 1;
				nComma = Qop.Find(nStart, ',');
			}
			sItem = Qop.Mid(nStart);
			if (pszQop == NULL)
				pszQop = WCharToChar(sItem);	// use the last value in the qop list
		}
		else
			pszQop = WCharToChar(Qop);
	}

	// calc response
	DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, pszCNonce, hhHA1);
	DigestCalcResponse(hhHA1, pszNonce, szNonceCount, pszCNonce, pszQop, pszMethod, pszURI, hhHA2, hhResponse);
	CString response = CharToWChar((char *) hhResponse);

	// format the header
	CString authorization;
	authorization.Format(
		_T("Digest username=\"%s\", ")
		_T("realm=\"%s\", ")
		_T("nonce=\"%s\", ")
		_T("uri=\"%s\", ")
		_T("response=\"%s\""),
		userName, Realm, Nonce, uri, response);

	if (!Opaque.IsEmpty()) {
		CString opaque;
		opaque.Format(_T(", opaque=\"%s\""), Opaque);
		authorization += opaque;
	}

	// if 'qop' is specified, other parameters must be sent
	if (!Qop.IsEmpty()) {
		CString sQop = CharToWChar(pszQop);
		CString sCNonce = CharToWChar(pszCNonce);
		CString sNonceCount = CharToWChar(szNonceCount);

		CString qopMust;
		qopMust.Format(
			_T(", qop=%s")
			_T(", cnonce=\"%s\"")
			_T(", nc=\"%08d\""),
			sQop, sCNonce, nc);

		authorization += qopMust;
	}

	delete [] pszAlg;
	delete [] pszUser;
	delete [] pszRealm;
	delete [] pszPass;
	delete [] pszNonce;
	delete [] pszURI;
	delete [] pszQop;

	header = authorization;
}

BOOL CDownloader::DoDigestAuthentication(CHttpRequest *&req, CHttpResponse *&res, LPVOID context) {
	LOG0(5, "CDownloader::DoDigestAuthentication()");

	int nc = 1;
	do {
		// force closing of the connection
		HttpConnection.Close();
		delete res; res = NULL;

		// ask for username and password
		if (OnAuthentication(context)) {
			// add authentication credentials to the original request
			CString authorization;
			PrepareAuthorizationHeader(nc, req->GetObject(), UserName, Password, authorization);
			req->SetHeader(AuthResponseHeader, authorization);

			// new connection with authentication credentials
			if (HttpConnection.Open(ServiceType, ServerName, Port)) {
				HttpConnection.SendRequest(req);
				res = HttpConnection.ReceiveResponse();
				if (res != NULL) {
					if (res->GetStatusCode() == HTTP_STATUS_OK) {
						State = DOWNLOAD_STATE_AUTHENTICATED;
						Updated = TRUE;
					}
					else {
						if (AuthSet) {
							// authorization failed
							Error = DOWNLOAD_ERROR_AUTHORIZATION_FAILED;
							break;
						}
						else {
							// try re-enter the user name and password
						}
					}
				}
				else {
					// response error
					Error = DOWNLOAD_ERROR_RESPONSE_ERROR;
					break;
				}
			}
			else {
				// can not connect
				Error = DOWNLOAD_ERROR_CONNECTION_ERROR;
				break;
			}
		}
		else {
			// auth canceled
			Error = DOWNLOAD_ERROR_AUTHENTICATION_ERROR;
			break;
		}
	} while (State != DOWNLOAD_STATE_AUTHENTICATED);

	return State = DOWNLOAD_STATE_AUTHENTICATED;
}

BOOL CDownloader::WWWAuthentication(CHttpRequest *&req, CHttpResponse *&res, LPVOID context) {
	LOG0(5, "CDownloader::WWWAuthentication()");

	CString authChallenge;
	if (!res->GetHeader(_T("WWW-Authenticate"), authChallenge)) {
		Error = DOWNLOAD_ERROR_AUTHENTICATION_RESPONSE;
		return FALSE;
	}

	AuthResponseHeader = _T("Authorization");
	return DoAuthentication(authChallenge, req, res, context);
}

BOOL CDownloader::ProxyAuthentication(CHttpRequest *&req, CHttpResponse *&res, LPVOID context) {
	LOG0(5, "CDownloader::ProxyAuthentication()");

	CString authChallenge;
	if (!res->GetHeader(_T("Proxy-Authenticate"), authChallenge)) {
		Error = DOWNLOAD_ERROR_AUTHENTICATION_RESPONSE;
		return FALSE;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -