# HG changeset patch # User Andre Heinecke # Date 1392376815 0 # Node ID 7e2f14c7aba2ac2e88c244b45dadfb648a4a5b9c # Parent fe39d93f12617c582a7d5d8fb5d3e7fe39f414d3 Split up downloader component and further implement it diff -r fe39d93f1261 -r 7e2f14c7aba2 CMakeLists.txt --- a/CMakeLists.txt Thu Feb 13 14:43:15 2014 +0000 +++ b/CMakeLists.txt Fri Feb 14 11:20:15 2014 +0000 @@ -20,6 +20,9 @@ set(M13UI_SOURCES ${CMAKE_SOURCE_DIR}/ui/mainwindow.cpp ${CMAKE_SOURCE_DIR}/ui/certificatelist.cpp + ${CMAKE_SOURCE_DIR}/ui/downloader.cpp + ${CMAKE_SOURCE_DIR}/ui/downloader_win.cpp + ${CMAKE_SOURCE_DIR}/ui/downloader_linux.cpp ${CMAKE_SOURCE_DIR}/ui/listutil.c ) @@ -67,7 +70,8 @@ -lQt5PlatformSupport -lQt5Gui -lcomdlg32 -loleaut32 -limm32 -lwinmm -lglu32 -lopengl32 -lgdi32 -ljpeg -lpng -lQt5Core -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lz -lsicuin -lsicuuc -lsicudt -lpcre16) - set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS}) + + set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS} -lwinhttp) set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat") endif() diff -r fe39d93f1261 -r 7e2f14c7aba2 ui/downloader.cpp --- a/ui/downloader.cpp Thu Feb 13 14:43:15 2014 +0000 +++ b/ui/downloader.cpp Fri Feb 14 11:20:15 2014 +0000 @@ -1,16 +1,10 @@ #include "downloader.h" -#ifndef MYVERSION -#define MYVERSION "1" -#endif - #ifndef DOWNLOAD_SERVER #define DOWNLOAD_SERVER "https://www.intevation.de" #endif #ifdef Q_OS_WIN -#include -#include #endif #include @@ -18,7 +12,9 @@ Downloader::Downloader(QObject* parent, const QString& url) { - Downloader (parent, url, QFile(":Certificates/https").readAll()); + QFile certResource(":certificates/https"); + certResource.open(QFile::ReadOnly); + Downloader (parent, url, certResource.readAll()); } Downloader::Downloader(QObject* parent, const QString& url, @@ -29,91 +25,3 @@ { } -void Downloader::run() { -#ifdef Q_OS_WIN - // We use WinAPI 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. - BOOL bResults = FALSE; - HINTERNET hSession = NULL, - hConnect = NULL, - hRequest = NULL; - SYSTEMTIME lastModified; - DWORD sizeOfSystemtime = sizeof (SYSTEMTIME); - - // Get a syncronous session handle - hSession = WinHttpOpen(L"M13 "MYVERSION, - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); - - if (hSession) { - // Initialize connection. No request is done here. - hConnect = WinHttpConnect(hSession, L""DOWNLOAD_SERVER, - INTERNET_DEFAULT_HTTPS_PORT, 0); - - } - - if (hConnect) { - // Make a head request - hRequest = WinHttpOpenRequest(hConnect, L"HEAD", - L"/index.html", - NULL, WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - 0); - } - - if (hRequest) { - bResults = WinHttpSendRequest(hRequest, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, WINHTTP_NO_REQUEST_DATA, 0, - 0, 0); - } - - if (bResults) { - bResults = WinHttpReceiveResponse(hRequest, NULL); - } - - - - if (bResults) { - bResults = WinHttpQueryHeaders(hRequest, - WINHTTP_QUERY_LAST_MODIFIED | - WINHTTP_QUERY_FLAG_SYSTEMTIME, - NULL, - &lastModified, - &sizeOfSystemtime, - WINHTTP_NO_HEADER_INDEX ); - } - - qDebug() << "Last modified year: " << lastModified.wYear; - - - if (!bResults) { - // Report any errors. - qDebug() << "Error" << GetLastError(); - emit error(tr("Unknown Problem when connecting"), Unknown); - } - - // Cleanup - if (hRequest) { - WinHttpCloseHandle(hRequest); - } - - if (hConnect) { - WinHttpCloseHandle(hConnect); - - } - - if (hSession) { - WinHttpCloseHandle(hSession); - } -#endif - - for (int i=0; i< 10; i++) { - qDebug("Going to sleep\n"); - sleep(10); - } -} diff -r fe39d93f1261 -r 7e2f14c7aba2 ui/downloader_linux.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/downloader_linux.cpp Fri Feb 14 11:20:15 2014 +0000 @@ -0,0 +1,13 @@ +/** + * @file downloader_win.cpp + * @brief Downloader implementation for Linux + */ + + +#include "certificatelist.h" + +#ifdef Q_OS_LINUX +void Downloader::run() { +} +#endif + diff -r fe39d93f1261 -r 7e2f14c7aba2 ui/downloader_win.cpp --- /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 +#include + +#include + +#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 diff -r fe39d93f1261 -r 7e2f14c7aba2 ui/mainwindow.cpp --- a/ui/mainwindow.cpp Thu Feb 13 14:43:15 2014 +0000 +++ b/ui/mainwindow.cpp Fri Feb 14 11:20:15 2014 +0000 @@ -56,7 +56,7 @@ void MainWindow::createTrayIcon() { - QIcon trayImg = QIcon(":/img/tray_22.png"); + QIcon trayImg(":/img/tray_22.png"); mTrayMenu = new QMenu(this); mTrayMenu->addAction(mCheckUpdates);