Mercurial > trustbridge
diff ui/downloader_win.cpp @ 11:7e2f14c7aba2
Split up downloader component and further implement it
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Fri, 14 Feb 2014 11:20:15 +0000 |
parents | |
children | 95e1b6edf2fc |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/downloader_win.cpp Fri Feb 14 11:20:15 2014 +0000 @@ -0,0 +1,259 @@ +/** + * @file downloader_win.cpp + * @brief Downloader implementation for Windows + * + * We use Windows API here instead of Qt because we want to avoid + * QtNetworks SSL stack which is based on OpenSSL and so + * we might be incompatible with GPL code. Also using the + * native API means that the security of the SSL implementation + * is tied to the security of the system. + * + */ +#include "downloader.h" +#ifdef Q_OS_WIN +#ifndef MYVERSION +#define MYVERSION "1" +#endif + +#include <windows.h> +#include <winhttp.h> + +#include <QDebug> + +#define DEBUG if (1) qDebug() << __PRETTY_FUNCTION__ + +const QString getLastErrorMsg() { + LPWSTR bufPtr = NULL; + DWORD err = GetLastError(); + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, 0, (LPWSTR)&bufPtr, 0, NULL); + const QString result = + (bufPtr) ? QString::fromUtf16((const ushort*)bufPtr).trimmed() : + QString("Unknown Error %1").arg(err); + LocalFree(bufPtr); + return result; +} + +/** @brief open a session with appropiate proxy settings + * + * @param[inout] *pHSession pointer to a HInternet structure + * + * On error call getLastError to get extended error information. + * + * @returns True on success, false on error. + */ + + +bool openSession(HINTERNET *pHSession) +{ + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig; + + DEBUG; + if (!pHSession) { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + qDebug() << "2"; + memset(&proxyConfig, 0, sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)); + + if (WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig)) { + if (proxyConfig.fAutoDetect) { + // TODO Handle this + qDebug() << "Autodetect is set"; + } + + if (proxyConfig.lpszProxy || proxyConfig.lpszProxyBypass) { + DEBUG << "Using proxies."; + } + + if (proxyConfig.lpszProxy) { + *pHSession = WinHttpOpen(L"M13 "MYVERSION, + WINHTTP_ACCESS_TYPE_NAMED_PROXY, + proxyConfig.lpszProxy, + proxyConfig.lpszProxyBypass, 0); + } + } + + if (!*pHSession) { + DEBUG << "No IE Proxy falling back to default proxy"; + *pHSession = WinHttpOpen(L"M13 "MYVERSION, + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); + } + // Cleanup + if (proxyConfig.lpszAutoConfigUrl) { + GlobalFree(proxyConfig.lpszAutoConfigUrl); + } + + if (proxyConfig.lpszProxy) { + GlobalFree(proxyConfig.lpszProxy); + } + + if (proxyConfig.lpszProxyBypass) { + GlobalFree(proxyConfig.lpszProxyBypass); + } + return *pHSession; +} + + +/** @brief initialize a connection in the session + * + * @param[in] HSession the session to work in. + * @param[inout] *pHConnect pointer to the connection. + * @param[in] url pointer to the URL in wchar representation. + * + * On error call getLastError to get extended error information. + * + * @returns True on success, false on error. + */ +bool initializeConnection(HINTERNET hSession, HINTERNET *pHConnect, + LPCWSTR url) +{ + DEBUG; + if (!hSession || !pHConnect) { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + // Initialize connection. No request is done here. + *pHConnect = WinHttpConnect(hSession, url, + INTERNET_DEFAULT_HTTPS_PORT, 0); + + return *pHConnect; +} + +/** @brief Create a request + * + * @param[in] HSession the session to work in. + * @param[in] HConnect the connection to use. + * @param[inout] *pHRequest pointer to the request structure to be filled. + * @param[in] requestType the HTTP request to be made default is GET + * @param[in] resource pointer to the resource to request in wchar + * representation. + * + * On error call getLastError to get extended error information. + * This function still does not do any networking but only initializes + * it. + * + * @returns True on success, false on error. + */ + +bool createRequest(HINTERNET hSession, HINTERNET hConnect, + HINTERNET *pHRequest, LPCWSTR requestType, LPCWSTR resource) +{ + DEBUG; + if (!hSession || !hConnect || !pHRequest) { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + *pHRequest = WinHttpOpenRequest(hConnect, requestType, resource, + NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_SECURE); + return *pHRequest; +} + +void Downloader::run() { + BOOL bResults = FALSE; + HINTERNET hSession = NULL, + hConnect = NULL, + hRequest = NULL; + + SYSTEMTIME lastModified; + DWORD sizeOfSystemtime = sizeof (SYSTEMTIME); + + memset(&lastModified, 0, sizeof (SYSTEMTIME)); + + if (!openSession(&hSession)) { + DEBUG << "Failed to open session: " << getLastErrorMsg(); + return; + } + + if (!initializeConnection(hSession, &hConnect, L"www.intevation.de")) { + DEBUG << "Failed to initialize connection: " << getLastErrorMsg(); + goto cleanup; + } + + if (!createRequest(hSession, hConnect, &hRequest, L"GET", L"/")) { + DEBUG << "Failed to create the request: " << getLastErrorMsg(); + goto cleanup; + } + + if (hRequest) { + DEBUG << "Doing Request"; + bResults = WinHttpSendRequest(hRequest, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, WINHTTP_NO_REQUEST_DATA, 0, + 0, 0); + } else { + DEBUG << "Error: " << GetLastError(); + } + + + if (bResults) { + DEBUG << "Recieving Response"; + bResults = WinHttpReceiveResponse(hRequest, NULL); + } else { + DEBUG << "Error: " << GetLastError(); + } + + if (bResults) { + DEBUG << "Querying Headers"; + bResults = WinHttpQueryHeaders(hRequest, + WINHTTP_QUERY_LAST_MODIFIED | + WINHTTP_QUERY_FLAG_SYSTEMTIME, + NULL, + &lastModified, + &sizeOfSystemtime, + WINHTTP_NO_HEADER_INDEX); + } else { + DWORD errCode = GetLastError(); + switch (errCode) { + case ERROR_WINHTTP_HEADER_NOT_FOUND: + DEBUG << "Header not found"; + break; + case ERROR_WINHTTP_INCORRECT_HANDLE_STATE: + DEBUG << "Incorrect handle state"; + break; + case ERROR_WINHTTP_INCORRECT_HANDLE_TYPE: + DEBUG << "Incorrect handle type"; + break; + case ERROR_WINHTTP_INTERNAL_ERROR: + DEBUG << "Internal error"; + break; + case ERROR_NOT_ENOUGH_MEMORY: + DEBUG << "OOM"; + break; + default: + DEBUG << "Error: " << getLastErrorMsg(); + } + } + + DEBUG << "Last modified year: " << lastModified.wYear; + + + if (!bResults) { + // Report any errors. + DEBUG << "Error" << GetLastError(); + emit error(tr("Unknown Problem when connecting"), Unknown); + } +cleanup: + if (hRequest) { + WinHttpCloseHandle(hRequest); + } + + if (hConnect) { + WinHttpCloseHandle(hConnect); + + } + + if (hSession) { + WinHttpCloseHandle(hSession); + } + return; +} +#endif