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

http://wald.intevation.org/projects/trustbridge/