📄 download.cpp.svn-base
字号:
/**
* 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 + -