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

📄 download.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
	AuthResponseHeader = _T("Proxy-Authorization");
	return DoAuthentication(authChallenge, req, res, context);
}

BOOL CDownloader::DoAuthentication(const CString &authChallenge, CHttpRequest *&req, CHttpResponse *&res, LPVOID context) {
	LOG0(5, "CDownloader::DoAuthentication()");

	State = DOWNLOAD_STATE_AUTHENTICATING;

	// scheme realm,auth-pars
	int pos = authChallenge.Find(' ');
	CString scheme = authChallenge.Left(pos);

	// parse realm and parameters
	while (pos < authChallenge.GetLength()) {
		int eqPos = authChallenge.Find('=', pos);
		if (eqPos == -1) {
			Error = DOWNLOAD_ERROR_AUTHENTICATION_RESPONSE;
			return FALSE;
		}

		CString name = authChallenge.Mid(pos, eqPos - pos);
		name.TrimLeft();

		int endPos = -1;
		CString value;
		if (authChallenge[eqPos + 1] == '"') {
			endPos = authChallenge.Find('"', eqPos + 1);
			if (endPos == -1) {
				Error = DOWNLOAD_ERROR_AUTHENTICATION_RESPONSE;
				return FALSE;
			}
			endPos = authChallenge.Find(',', endPos);
		}
		else {
			endPos = authChallenge.Find(',', eqPos + 1);
		}

		// last item
		if (endPos == -1)
			endPos = authChallenge.GetLength();

		value = authChallenge.Mid(eqPos + 1, endPos - eqPos - 1);
		// strip "
		value.TrimLeft('"');
		value.TrimRight('"');

		if (name.Compare(_T("realm")) == 0) Realm = value;
		else if (name.Compare(_T("domain")) == 0) Domain = value;
		else if (name.Compare(_T("nonce")) == 0) Nonce = value;
		else if (name.Compare(_T("opaque")) == 0) Opaque = value;
		else if (name.Compare(_T("stale")) == 0) Stale = value;
		else if (name.Compare(_T("algorithm")) == 0) Algorithm = value;
		else if (name.Compare(_T("qop")) == 0) Qop = value;

		pos = endPos + 1;
	}

	if (scheme.CompareNoCase(_T("basic")) == 0) {
		// Basic authentication
		return DoBasicAuthentication(req, res, context);
	}
	else if (scheme.CompareNoCase(_T("digest")) == 0) {
		// Digest authentication
		return DoDigestAuthentication(req, res, context);
	}
	else {
		Error = DOWNLOAD_ERROR_UNKNOWN_AUTH_SCHEME;
		return FALSE;
	}
}

///

void CDownloader::OnBeforeSendRequest(CHttpRequest *&req, LPVOID context) {
	if (!ETag.IsEmpty()) req->SetHeader(_T("If-None-Match"), (LPCTSTR) ETag);
	if (!LastModified.IsEmpty()) req->SetHeader(_T("If-Modified-Since"), (LPCTSTR) LastModified);
}

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

	int redirections = 0;	// number of redirections
	DWORD statusCode;
	CString newAddress, headers;
	CString strETag, strLastModified;

	Updated = FALSE;
	do {
		statusCode = res->GetStatusCode();
		LOG1(1, "StatusCode: %d", statusCode);

		switch (statusCode) {
			case HTTP_STATUS_OK:
			case HTTP_STATUS_PARTIAL_CONTENT:
				SaveHeaders(res);
				if (res->GetHeader(_T("ETag"), strETag)) ETag = strETag;
				if (res->GetHeader(_T("Last-Modified"), strLastModified)) LastModified = strLastModified;
				Updated = TRUE;
				return TRUE;

			case HTTP_STATUS_NOT_MODIFIED:						// 304
				LOG0(3, "- NOT updated");
				Updated = FALSE;	// do not download the file (it is not changed)
				return FALSE;

			case HTTP_STATUS_MOVED:								// 301
			case HTTP_STATUS_REDIRECT:							// 302
			case HTTP_STATUS_REDIRECT_KEEP_VERB:				// 307
			case HTTP_STATUS_REDIRECT_METHOD:					// 303
				redirections++;

				if (res->GetHeader(_T("Location"), newAddress)) {
					CString object;
					if (ParseURL(newAddress, ServiceType, ServerName, object, Port)) {
						// absolute URL
						URL = newAddress;
					}
					else {
						// relative URL
						object = newAddress;
						if (ServiceType == INET_SERVICE_HTTPS) URL.Format(_T("https://%s%s"), ServerName, object);
						else URL.Format(_T("http://%s%s"), ServerName, object);
					}

					delete res;
					res = NULL;

					delete req;
					req = NULL;

					HttpConnection.Close();

					if (HttpConnection.Open(ServiceType, ServerName, Port)) {
						req = HttpConnection.CreateRequest(object);
						if (req != NULL) {
							if (!Range.IsEmpty()) req->SetHeader(_T("Range"), Range);
							req->AddHeaders(AdditionalHeaders);
							HttpConnection.SendRequest(req);
							res = HttpConnection.ReceiveResponse();
							if (res != NULL) {
							}
							else {
								Error = DOWNLOAD_ERROR_RESPONSE_ERROR;
								return FALSE;
							}
						}
						else {
							Error = DOWNLOAD_ERROR_SENDING_REQUEST;
							return FALSE;
						}
					}
					else {
						Error = DOWNLOAD_ERROR_CONNECTION_ERROR;
						return FALSE;
					}
				}
				else {
					Error = DOWNLOAD_ERROR_NO_LOCATION_HEADER;
					return FALSE;
				}

				break;

			case HTTP_STATUS_DENIED:
				// 401 Authorization required
				return WWWAuthentication(req, res, context);

/*			case 407:
				// 407 Proxy Authentication required
//				if (HttpConnection.Proxy->NeedAuth) {
//					AuthSet = TRUE;
//					UserName = HttpConnection.Proxy->UserName;
//					Password = HttpConnection.Proxy->Password;
//					ret = ProxyAuthentication(req, res, context);
//					end = TRUE;
//				}
//				else {
//					// proxy needs authentication
//					end = TRUE;
//				}
				end = TRUE;
				break;
*/

			default:
				Error = DOWNLOAD_ERROR_HTTP_ERROR;
				HttpErrorNo = statusCode;
				return FALSE;
		}
	} while (redirections < 6);

	return FALSE;
}

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

	HttpConnection.Terminate();
	SetEvent(HTerminate);
}

BOOL CDownloader::IsTerminated() {
	return HttpConnection.IsTerminated();
}

//
// SaveHttpObject
//
BOOL CDownloader::SaveHttpObject(CString &url, const CString &strFileName, LPVOID context/* = NULL*/) {
	LOG1(3, "CDownloader::SaveHttpObject('%S')", url);

	HANDLE file = CreateFile(strFileName, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (file == INVALID_HANDLE_VALUE) {
		// not exists
		CreatePath(strFileName);
	}
	else {
		// file exists => resume download
		DWORD fileSize = GetFileSize(file, NULL);
		CloseHandle(file);

		Range.Format(_T("bytes=%d-"), fileSize);
	}

	Error = DOWNLOAD_ERROR_NONE;
	URL = url;

	ReplaceHTMLEntities(url);			// there might be entities in the url

	OnConnection(context);
	CString objectName;
	if (ParseURL(url, ServiceType, ServerName, objectName, Port)) {
		State = DOWNLOAD_STATE_CONNECTING;

		DWORD timeout = 3000;			// we start with 3 seconds
		for (int tries = 0; tries < 3; tries++) {
			if (HttpConnection.Open(ServiceType, ServerName, Port)) {
				CHttpRequest *req = HttpConnection.CreateRequest(objectName);
				if (req != NULL) {
					State = DOWNLOAD_STATE_SENDING_REQUEST;
					if (!Range.IsEmpty()) req->SetHeader(_T("Range"), Range);
					req->AddHeaders(AdditionalHeaders);
					req->AddCookies(Cookies);
					OnBeforeSendRequest(req, context);
					HttpConnection.SendRequest(req, &Config.AdditionalHttpHeaders);

					State = DOWNLOAD_STATE_RECEIVING_RESPONSE;
					CHttpResponse *res = HttpConnection.ReceiveResponse();
					if (res != NULL) {
						if (OnResponse(req, res, context)) {
							if (OnBeforeFileDownload(context)) {
								State = DOWNLOAD_STATE_DATA_TRANSFER;
								if (HttpConnection.GetFile(res, strFileName)) {
									OnFileDownloaded(context);
								}
								else {
									if (HttpConnection.GetSysError() == ERROR_DISK_FULL)
										Error = DOWNLOAD_ERROR_DISK_FULL;
									else
										Error = DOWNLOAD_ERROR_GETTING_FILE;
								}
							}
						}
						delete res;
					}
					else
						Error = DOWNLOAD_ERROR_RESPONSE_ERROR;

					delete req;
				}
				else
					Error = DOWNLOAD_ERROR_SENDING_REQUEST;

				HttpConnection.Close();

				return Error == DOWNLOAD_ERROR_NONE;
			}
			else {
				// wait for a while
				DWORD dwResult = WaitForSingleObject(HTerminate, timeout);
				if (dwResult == WAIT_OBJECT_0)
					break;			// terminated
				else
					timeout *= 2;	// timed out
			}
		}

		Error = DOWNLOAD_ERROR_CONNECTION_ERROR;
	}
	else
		Error = DOWNLOAD_ERROR_MALFORMED_URL;

	return Error == DOWNLOAD_ERROR_NONE;
}

BOOL CDownloader::GetHttpObject(CString &url, CString &strBody, LPVOID context/* = NULL*/) {
	TCHAR tempFileName[MAX_PATH];
	GetTempFileName(Config.CacheLocation, L"rsr", 0, tempFileName);

	BOOL ret =  FALSE;
	if (SaveHttpObject(url, tempFileName)) {
		CString response;

		HANDLE hFile = CreateFile(tempFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE) {
			// suppose the response is short, so that we can read it at once
			DWORD read;
			DWORD size = GetFileSize(hFile, NULL);
			char *buffer = new char [size + 1];
			ReadFile(hFile, buffer, size, &read, NULL);
			buffer[size] = '\0';
			CloseHandle(hFile);

			strBody.Format(_T("%S"), buffer);

			delete [] buffer;

			ret = TRUE;
		}
	}

	DeleteFile(tempFileName);

	return ret;
}

BOOL CDownloader::Post(CString &url, const CString &strBody, CString &response, LPVOID context/* = NULL*/) {
	LOG1(3, "CDownloader::Post('%S')", url);

	Error = DOWNLOAD_ERROR_NONE;
	URL = url;

	ReplaceHTMLEntities(url);			// there might be entities in the url

	OnConnection(context);
	CString objectName;
	if (ParseURL(url, ServiceType, ServerName, objectName, Port)) {
		State = DOWNLOAD_STATE_CONNECTING;

		DWORD timeout = 3000;			// we start with 3 seconds
		for (int tries = 0; tries < 3; tries++) {
			if (HttpConnection.Open(ServiceType, ServerName, Port)) {
				CHttpRequest *req = HttpConnection.CreateRequest(objectName, HTTP_METHOD_POST);
				if (req != NULL) {
					// set the request body
					req->SetBody(strBody);

					// add necessary headers
					req->SetHeader(_T("Content-Type"), _T("application/x-www-form-urlencoded"));
					req->SetHeader(_T("Content-Length"), strBody.GetLength());

					State = DOWNLOAD_STATE_SENDING_REQUEST;
					req->AddHeaders(AdditionalHeaders);
					req->AddCookies(Cookies);
					OnBeforeSendRequest(req, context);
					HttpConnection.SendRequest(req, &Config.AdditionalHttpHeaders);

					State = DOWNLOAD_STATE_RECEIVING_RESPONSE;
					CHttpResponse *res = HttpConnection.ReceiveResponse();
					if (res != NULL) {
						if (OnResponse(req, res, context)) {
							if (OnBeforeFileDownload(context)) {
								State = DOWNLOAD_STATE_DATA_TRANSFER;

								TCHAR tempFileName[MAX_PATH];
								GetTempFileName(Config.CacheLocation, L"rsr", 0, tempFileName);
								if (HttpConnection.GetFile(res, tempFileName)) {
									// ok, we get the response in the file -> read it
									HANDLE hFile = CreateFile(tempFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
									if (hFile != INVALID_HANDLE_VALUE) {
										// suppose the response is short, so that we can read it at once
										DWORD read;
										DWORD size = GetFileSize(hFile, NULL);
										char *buffer = new char [size + 1];
										ReadFile(hFile, buffer, size, &read, NULL);
										buffer[size] = '\0';
										response.Format(_T("%S"), buffer);
										CloseHandle(hFile);
									}

									OnFileDownloaded(context);
								}
								else {
									if (HttpConnection.GetSysError() == ERROR_DISK_FULL)
										Error = DOWNLOAD_ERROR_DISK_FULL;
									else
										Error = DOWNLOAD_ERROR_GETTING_FILE;
								}
								DeleteFile(tempFileName);
							}
						}
						delete res;
					}
					else
						Error = DOWNLOAD_ERROR_RESPONSE_ERROR;

					delete req;
				}
				else
					Error = DOWNLOAD_ERROR_SENDING_REQUEST;

				HttpConnection.Close();

				return Error == DOWNLOAD_ERROR_NONE;
			}
			else {
				// wait for a while
				DWORD dwResult = WaitForSingleObject(HTerminate, timeout);
				if (dwResult == WAIT_OBJECT_0)
					break;			// terminated
				else
					timeout *= 2;	// timed out
			}
		}

		Error = DOWNLOAD_ERROR_CONNECTION_ERROR;
	}
	else
		Error = DOWNLOAD_ERROR_MALFORMED_URL;

	return Error == DOWNLOAD_ERROR_NONE;
}

void CDownloader::FreeAdditionalHeaders() {
	while (!AdditionalHeaders.IsEmpty())
		delete AdditionalHeaders.RemoveHead();
}

void CDownloader::SetCookie(const CString &cookie) {
	Cookies.AddTail(cookie);
}

CString CDownloader::GetErrorMsg() {
	CString errorMsg;

	switch (Error) {
		case DOWNLOAD_ERROR_GETTING_FILE:            errorMsg.LoadString(IDS_ERROR_GETTING_FILE); break;
		case DOWNLOAD_ERROR_RESPONSE_ERROR:          errorMsg.LoadString(IDS_RESPONSE_ERROR); break;
		case DOWNLOAD_ERROR_SENDING_REQUEST:         errorMsg.LoadString(IDS_ERROR_SENDING_REQUEST); break;
		case DOWNLOAD_ERROR_CONNECTION_ERROR:        errorMsg.LoadString(IDS_ERROR_CONNECT); break;
		case DOWNLOAD_ERROR_MALFORMED_URL:           errorMsg.LoadString(IDS_MALFORMED_URL); break;
		case DOWNLOAD_ERROR_AUTHENTICATION_RESPONSE: errorMsg.LoadString(IDS_INVALID_FEED_FILE); break;
		case DOWNLOAD_ERROR_UNKNOWN_AUTH_SCHEME:     errorMsg.LoadString(IDS_UNKNOWN_AUTH_SCHEME); break;
		case DOWNLOAD_ERROR_NO_LOCATION_HEADER:      errorMsg.LoadString(IDS_NO_LOCATION_HEADER); break;
		case DOWNLOAD_ERROR_HTTP_ERROR:              errorMsg.Format(IDS_HTTP_ERROR, HttpErrorNo); break;
		case DOWNLOAD_ERROR_AUTHORIZATION_FAILED:    errorMsg.LoadString(IDS_AUTHORIZATION_FAILED); break;
		case DOWNLOAD_ERROR_AUTHENTICATION_ERROR:    errorMsg.LoadString(IDS_AUTHENTICATION_ERROR); break;
		case DOWNLOAD_ERROR_DISK_FULL:               errorMsg.LoadString(IDS_DISK_FULL); break;
	}
	return errorMsg;
}

⌨️ 快捷键说明

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