changeset 910:eaed02defe6a

More SSLConnection refactoring. Fixes curl downloader.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 18 Aug 2014 18:51:33 +0200
parents 18e3ad073b38
children bf4c8737b52c
files ui/CMakeLists.txt ui/downloader.cpp ui/downloader.h ui/sslconnection.h ui/sslconnection_bare.cpp ui/sslconnection_bare.h ui/sslconnection_curl.cpp ui/sslconnection_curl.h ui/tests/downloadertest.cpp
diffstat 9 files changed, 339 insertions(+), 257 deletions(-) [+]
line wrap: on
line diff
--- a/ui/CMakeLists.txt	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/CMakeLists.txt	Mon Aug 18 18:51:33 2014 +0200
@@ -26,11 +26,13 @@
     ${CMAKE_CURRENT_SOURCE_DIR}/sslhelp.cpp
 )
 
-if (${CURL_FOUND})
+if (${CURL_FOUND} AND ${USE_CURL})
    set(UICOMMON_SOURCES ${UICOMMON_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/sslconnection_curl.cpp)
    add_definitions(-DUSE_CURL)
+elseif (${USE_CURL})
+   MESSAGE(FATAL_ERROR "libcurl not found but usage of curl is requested.")
 else()
-   MESSAGE(STATUS "Warning curl not found only bare polarssl ssl will be supported.")
+   MESSAGE(FATAL_ERROR "${CURL_FOUND} ${USE_CURL}")
 endif()
 
 # Cmake does not correctly identify gcc windres when cross compiling
--- a/ui/downloader.cpp	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/downloader.cpp	Mon Aug 18 18:51:33 2014 +0200
@@ -78,127 +78,6 @@
     return cDir.absolutePath();
 }
 
-QMap<QString, QString> Downloader::parseHeaders(QByteArray *data)
-{
-    int bodyStart = data->indexOf("\r\n\r\n");
-    QMap<QString, QString> retval;
-    QByteArray headers;
-    QString response(*data);
-    if (bodyStart == -1) {
-        qDebug() << "Could not find header end.";
-        emit error(tr("Invalid response"),
-                SSLConnection::InvalidResponse);
-        return retval;
-    }
-
-    /* Take the headers with one additional line break */
-    headers = data->left(bodyStart + 2);
-    /* Chop off the head */
-
-    foreach (const QString& line, response.split("\r\n")) {
-        int sepPos = -1;
-        sepPos = line.indexOf(": ");
-        if (sepPos == -1) {
-            continue;
-        }
-        QString key = line.left(sepPos);
-        QString value = line.right(line.size() - sepPos - 2);
-
-        retval.insert(key, value);
-    }
-
-    *data = data->right(data->size() - bodyStart - 4);
-    return retval;
-}
-
-QDateTime Downloader::getLastModifiedHeader(const QString &resource) {
-    int ret = -1;
-    QByteArray response;
-    QLocale cLocale = QLocale::c();
-    QMap<QString, QString> headers;
-    QString headRequest =
-        QString::fromLatin1("HEAD %1 HTTP/1.0\r\n\r\n").arg(resource);
-
-    ret = mSSLConnection->write(headRequest.toUtf8());
-    if (ret != 0) {
-        emit error (tr("Connection lost"), SSLConnection::ConnectionLost);
-        return QDateTime();
-    }
-
-    response = mSSLConnection->read(1024);
-
-    qDebug() << "Response from server was: " << response;
-
-    if (response.isNull()) {
-        qDebug() << "No response";
-        emit error (tr("Connection lost"), SSLConnection::ConnectionLost);
-        return QDateTime();
-    }
-
-    headers = parseHeaders(&response);
-    const QString lastModified = headers.value("Last-Modified");
-    if (!lastModified.isEmpty()) {
-        QDateTime candidate = cLocale.toDateTime(lastModified,
-                "ddd, dd MMM yyyy HH:mm:ss' GMT'");
-        if (candidate.isValid()) {
-            return candidate;
-        }
-    }
-    emit error (tr("Invalid response from the server"), SSLConnection::InvalidResponse);
-    return QDateTime();
-}
-
-bool Downloader::downloadFile(const QString &resource,
-                              const QString &fileName,
-                              size_t maxSize)
-{
-    int ret = -1;
-    size_t bytesRead = 0;
-    QString getRequest =
-        QString::fromLatin1("GET %1 HTTP/1.0\r\n\r\n").arg(resource);
-
-    QSaveFile outputFile(fileName);
-
-    ret = mSSLConnection->write(getRequest.toUtf8());
-
-    // Open / Create the file to write to.
-    if (!outputFile.open(QIODevice::WriteOnly)) {
-        qDebug() << "Failed to open file";
-        return false;
-    }
-
-    if (ret != 0) {
-        emit error(tr("Connection lost"), SSLConnection::ConnectionLost);
-        return false;
-    }
-
-    bool inBody = false;
-    QMap <QString, QString> headers;
-    do {
-        /* Read the response in 8KiB chunks */
-        int responseSize = 0;
-        QByteArray response = mSSLConnection->read(8192);
-        if (response.isNull()) {
-            qDebug() << "Error reading response";
-            emit error(tr("Connection lost"), SSLConnection::ConnectionLost);
-            return false;
-        }
-        responseSize = response.size();
-        if (!inBody) {
-            headers = parseHeaders(&response);
-            inBody = true;
-        }
-        outputFile.write(response);
-        bytesRead += responseSize;
-        if (responseSize < 8192) {
-            /* Nothing more to read */
-            break;
-        }
-        /* TODO Emit progress */
-    } while (bytesRead < maxSize);
-
-    return outputFile.commit();
-}
 
 void Downloader::run() {
     int ret;
@@ -220,10 +99,11 @@
 
     emit progress(tr("Connected"), 1, -1);
 
-    remoteModSW = getLastModifiedHeader(mResourceSW);
+    remoteModSW = mSSLConnection->getLastModifiedHeader(mResourceSW);
     emit lastModifiedDate(remoteModSW);
 
     if (!remoteModSW.isValid()) {
+        emit error (tr("Connection failed."), SSLConnection::InvalidResponse);
         qDebug() << "Could not parse headers for Software";
         return;
     }
@@ -247,7 +127,8 @@
         qDebug() << "fileName: " << fileName;
 
         if (mDownloadSW) {
-            if (!downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) {
+            if (!mSSLConnection->downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) {
+                emit error(tr("Failed to download File"), SSLConnection::ConnectionLost);
                 qDebug() << "Failed to download software update.";
                 return;
             }
@@ -260,8 +141,9 @@
         return;
     }
 
-    remoteModList = getLastModifiedHeader(mResourceList);
+    remoteModList = mSSLConnection->getLastModifiedHeader(mResourceList);
     if (!remoteModList.isValid()) {
+        emit error (tr("Connection failed."), SSLConnection::InvalidResponse);
         qDebug() << "Could not parse headers for List";
         return;
     }
@@ -280,7 +162,7 @@
 
         qDebug() << "fileName: " << fileName;
 
-        if (!downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) {
+        if (!mSSLConnection->downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) {
             return;
         }
 
--- a/ui/downloader.h	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/downloader.h	Mon Aug 18 18:51:33 2014 +0200
@@ -85,42 +85,6 @@
 
     SSLConnection *mSSLConnection;
 
-    /** @brief get the last modified header of a resource.
-     *
-     * Connection should be established beforehand.
-     * Modifies the error state.
-     *
-     * @param[in] resource The resource to check
-     *
-     * @returns the last modified date or a null datetime in case of errors
-     */
-    QDateTime getLastModifiedHeader(const QString &resource);
-
-    /** @brief Download resource
-     *
-     * Download a resource with the established connection.
-     * Modifies the error state.
-     *
-     * @param[in] resource the resource to download
-     * @param[in] filename where the file should be saved.
-     * @param[in] maxSize maximum amount of bytes to download
-     *
-     * @returns True if the download was successful.
-     */
-    bool downloadFile(const QString &resource, const QString &filename,
-                      size_t maxSize);
-    /**
-     * @brief parses the Headers of a repsonse.
-     *
-     * This removes the headers from the byte array passed as
-     * parameter.
-     *
-     * @param[inout] data: The response to parse.
-     *
-     * @returns: A map of the header fields. Or an empty map on error.
-     */
-    QMap<QString, QString> parseHeaders(QByteArray *data);
-
 Q_SIGNALS:
     /**
      * @brief software update is available
--- a/ui/sslconnection.h	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/sslconnection.h	Mon Aug 18 18:51:33 2014 +0200
@@ -51,18 +51,6 @@
 
     virtual ~SSLConnection() {};
 
-    /** @brief write */
-    virtual int write(const QByteArray& request) = 0;
-
-    /**
-     * @brief read at most len bytes and reset the connection
-     *
-     * @param [in] len Amount of bytes to read.
-     *
-     * @returns a byte array containing the data or
-     * a NULL byte array on error*/
-    virtual QByteArray read(size_t len) = 0;
-
     bool initialized() { return mInitialized; }
     bool connected() { return mConnected; }
 
@@ -74,6 +62,30 @@
      */
     virtual int connect() = 0;
 
+    /** @brief get the last modified header of a resource.
+     *
+     * Connection should be established beforehand.
+     * Modifies the error state.
+     *
+     * @param[in] resource The resource to check
+     *
+     * @returns the last modified date or a null datetime in case of errors
+     */
+    virtual QDateTime getLastModifiedHeader(const QString &resource) = 0;
+
+    /** @brief Download resource
+     *
+     * Download a resource with the established connection.
+     * Modifies the error state.
+     *
+     * @param[in] resource the resource to download
+     * @param[in] filename where the file should be saved.
+     * @param[in] maxSize maximum amount of bytes to download
+     *
+     * @returns True if the download was successful.
+     */
+    virtual bool downloadFile(const QString &resource, const QString &filename,
+                              size_t maxSize) = 0;
 protected:
     QUrl mUrl;
     QByteArray mPinnedCert;
--- a/ui/sslconnection_bare.cpp	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/sslconnection_bare.cpp	Mon Aug 18 18:51:33 2014 +0200
@@ -11,6 +11,7 @@
 #include "sslhelp.h"
 
 #include <QFile>
+#include <QSaveFile>
 #include <QUuid>
 #include <QApplication>
 
@@ -359,4 +360,113 @@
     return retval;
 }
 
+QMap<QString, QString> SSLConnectionBare::parseHeaders(QByteArray *data)
+{
+    int bodyStart = data->indexOf("\r\n\r\n");
+    QMap<QString, QString> retval;
+    QByteArray headers;
+    QString response(*data);
+    if (bodyStart == -1) {
+        qDebug() << "Could not find header end.";
+        return retval;
+    }
 
+    /* Take the headers with one additional line break */
+    headers = data->left(bodyStart + 2);
+    /* Chop off the head */
+
+    foreach (const QString& line, response.split("\r\n")) {
+        int sepPos = -1;
+        sepPos = line.indexOf(": ");
+        if (sepPos == -1) {
+            continue;
+        }
+        QString key = line.left(sepPos);
+        QString value = line.right(line.size() - sepPos - 2);
+
+        retval.insert(key, value);
+    }
+
+    *data = data->right(data->size() - bodyStart - 4);
+    return retval;
+}
+
+QDateTime SSLConnectionBare::getLastModifiedHeader(const QString &resource) {
+    int ret = -1;
+    QByteArray response;
+    QLocale cLocale = QLocale::c();
+    QMap<QString, QString> headers;
+    QString headRequest =
+        QString::fromLatin1("HEAD %1 HTTP/1.0\r\n\r\n").arg(resource);
+
+    ret = write(headRequest.toUtf8());
+    if (ret != 0) {
+        return QDateTime();
+    }
+
+    response = read(1024);
+
+    qDebug() << "Response from server was: " << response;
+
+    if (response.isNull()) {
+        qDebug() << "No response";
+        return QDateTime();
+    }
+
+    headers = parseHeaders(&response);
+    const QString lastModified = headers.value("Last-Modified");
+    if (!lastModified.isEmpty()) {
+        QDateTime candidate = cLocale.toDateTime(lastModified,
+                "ddd, dd MMM yyyy HH:mm:ss' GMT'");
+        if (candidate.isValid()) {
+            return candidate;
+        }
+    }
+    return QDateTime();
+}
+
+bool SSLConnectionBare::downloadFile(const QString &resource,
+                              const QString &fileName,
+                              size_t maxSize)
+{
+    int ret = -1;
+    size_t bytesRead = 0;
+    QString getRequest =
+        QString::fromLatin1("GET %1 HTTP/1.0\r\n\r\n").arg(resource);
+
+    QSaveFile outputFile(fileName);
+
+    ret = write(getRequest.toUtf8());
+
+    // Open / Create the file to write to.
+    if (!outputFile.open(QIODevice::WriteOnly)) {
+        qDebug() << "Failed to open file";
+        return false;
+    }
+
+    bool inBody = false;
+    QMap <QString, QString> headers;
+    do {
+        /* Read the response in 8KiB chunks */
+        int responseSize = 0;
+        QByteArray response = read(8192);
+        if (response.isNull()) {
+            qDebug() << "Error reading response";
+            return false;
+        }
+        responseSize = response.size();
+        if (!inBody) {
+            headers = parseHeaders(&response);
+            inBody = true;
+        }
+        outputFile.write(response);
+        bytesRead += responseSize;
+        if (responseSize < 8192) {
+            /* Nothing more to read */
+            break;
+        }
+    } while (bytesRead < maxSize);
+
+    return outputFile.commit();
+}
+
--- a/ui/sslconnection_bare.h	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/sslconnection_bare.h	Mon Aug 18 18:51:33 2014 +0200
@@ -17,6 +17,8 @@
 #include <polarssl/error.h>
 #include <polarssl/certs.h>
 
+#include <QDateTime>
+
 /**
  * @file sslconnection_bare.h
  * @brief SSLConnection doing bare SSL over PolarSSL
@@ -30,23 +32,12 @@
 
     ~SSLConnectionBare();
 
-    /** @brief write */
-    int write(const QByteArray& request);
+    int connect();
 
-    /**
-     * @brief read at most len bytes and reset the connection
-     *
-     * @param [in] len Amount of bytes to read.
-     *
-     * @returns a byte array containing the data or
-     * a NULL byte array on error*/
-    QByteArray read(size_t len);
+    QDateTime getLastModifiedHeader(const QString &resource);
 
-    /** @brief: Establish the connection
-     *
-     * @returns 0 on success otherwise an error or -1 is returned
-     */
-    int connect();
+    bool downloadFile(const QString &resource, const QString &filename,
+                      size_t maxSize);
 
 private:
     x509_crt mX509PinnedCert;
@@ -82,6 +73,31 @@
 
     /* @brief disconnects the connection */
     void disconnect();
+
+    /**
+     * @brief parses the Headers of a repsonse.
+     *
+     * This removes the headers from the byte array passed as
+     * parameter.
+     *
+     * @param[inout] data: The response to parse.
+     *
+     * @returns: A map of the header fields. Or an empty map on error.
+     */
+    QMap<QString, QString> parseHeaders(QByteArray *data);
+
+    /** @brief write */
+    int write(const QByteArray& request);
+
+    /**
+     * @brief read at most len bytes and reset the connection
+     *
+     * @param [in] len Amount of bytes to read.
+     *
+     * @returns a byte array containing the data or
+     * a NULL byte array on error*/
+    QByteArray read(size_t len);
+
 };
 
 #endif // UI_SSLCONNECTION_BARE_H
--- a/ui/sslconnection_curl.cpp	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/sslconnection_curl.cpp	Mon Aug 18 18:51:33 2014 +0200
@@ -7,9 +7,17 @@
  */
 
 #include "sslconnection_curl.h"
+#include <QSaveFile>
 
 #define CONNECTION_DEBUG
 
+/**@def Wrapper macro around curl_easy_setopt invocation */
+#define CURL_SETOPT(x, y, z) \
+    if (curl_easy_setopt(mCurl, x, y) != CURLE_OK) { \
+        qDebug() << "Setopt failed"; \
+        z; \
+    }
+
 SSLConnectionCurl::SSLConnectionCurl(const QString& url,
                              const QByteArray& certificate):
     SSLConnection (url, certificate),
@@ -23,11 +31,6 @@
         return;
     }
 
-    if (curl_easy_setopt(mCurl, CURLOPT_URL, QUrl(url).toEncoded().constData()) != CURLE_OK) {
-        qDebug() << "Setting url failed";
-        return;
-    }
-
     if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) {
         /* Should be default anyway */
         qDebug() << "Setting verifypeer failed";
@@ -40,6 +43,11 @@
         return;
     }
 
+    if (curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, mErrBuf) != CURLE_OK) {
+        qDebug() << "Setting errorbuf failed";
+        return;
+    }
+
     mCertFile.open();
     if (mCertFile.write(mPinnedCert) != mPinnedCert.size()) {
         qDebug() << "Failed to write temporary certificate";
@@ -70,12 +78,25 @@
 }
 
 int SSLConnectionCurl::connect() {
+    CURLcode retval;
+
+    if (curl_easy_setopt(mCurl, CURLOPT_URL, mUrl.toEncoded().constData()) != CURLE_OK) {
+        qDebug() << "Failed to set URL";
+        return -1;
+    }
+
     if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) {
         qDebug() << "Failed to set connect only option";
         return -1;
     }
-    if (curl_easy_perform (mCurl) != CURLE_OK) {
-        qDebug() << "Failed to connect";
+    retval = curl_easy_perform(mCurl);
+    if (retval != CURLE_OK) {
+        qDebug() << "Failed to connect: " << mErrBuf << " retval: " << retval;
+        if (retval == CURLE_PEER_FAILED_VERIFICATION) {
+            mErrorState = InvalidCertificate;
+            return -1;
+        }
+
         mErrorState = NoConnection;
         return -1;
     }
@@ -83,51 +104,128 @@
     return 0;
 }
 
-int SSLConnectionCurl::write(const QByteArray& request) {
-    size_t written = 0;
+/* Globally do this as we can't pass this to the c function */
+size_t ssl_curl_max_write, ssl_curl_written;
 
-    if (curl_easy_send (mCurl, request.constData(), request.size(), &written) != CURLE_OK) {
-        qDebug() << "Failed to send request";
-        return -1;
+size_t write_data(void *ptr, size_t size, size_t nmemb,
+        QSaveFile *fp)
+{
+    qDebug() << "Writing size: " << size << " * " << nmemb;
+    if (ssl_curl_max_write < ssl_curl_written) {
+        qDebug() << "Aborting write. Too much data.";
+        return 0;
     }
-    if (written != (size_t)request.size()) {
-        qDebug() << "Failed to write everything";
-        return -1;
+    size_t written = fp->write((const char *)ptr, size * nmemb);
+    if (written != size * nmemb) {
+        qDebug() << "Failed to write data. Written: " << written 
+                 << " requested: " << size * nmemb;
+        return 0;
     }
-    return 0;
+    ssl_curl_written += written;
+    return written;
 }
 
-QByteArray SSLConnectionCurl::read(size_t len)
+bool SSLConnectionCurl::downloadFile(const QString &resource,
+                                     const QString &fileName,
+                                     size_t maxSize)
 {
-    unsigned char buf[len];
-    QByteArray retval("");
-    CURLcode ret;
-    size_t read = 0;
-    unsigned int tries = 0;
+    QSaveFile outputFile(fileName);
+    ssl_curl_written = 0;
+    ssl_curl_max_write = maxSize;
+    // Open / Create the file to write to.
+    if (!outputFile.open(QIODevice::WriteOnly)) {
+        qDebug() << "Failed to open file";
+        return false;
+    }
+    QUrl urlCopy = mUrl;
+    urlCopy.setPath(resource);
 
-    do {
-        memset (buf, 0, sizeof(buf));
-        ret = curl_easy_recv (mCurl, buf, len, &read);
-        if (ret == CURLE_OK && read == 0) {
-            return retval;
-        }
-        if (ret == CURLE_AGAIN) {
-            tries++;
-            continue;
-        }
-        if (ret != CURLE_OK) {
-            qDebug() << "Read failed.";
-            return QByteArray();
-        }
-        if (len < (len - read)) {
-            /* Should never happen if ssl_read behaves */
-            qDebug() << "integer overflow in polarSSLRead";
-            return QByteArray();
-        }
+    if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) {
+        qDebug() << "Failed to set URL";
+        return false;
+    }
 
-        len -= read;
-        retval.append((const char *)buf, read);
-    } while (len > 0 && tries < 10);
+    if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) {
+        qDebug() << "Failed to set connect";
+        return false;
+    }
 
-    return retval;
+    if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 0L) != CURLE_OK) {
+        qDebug() << "Failed to set header";
+        return false;
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 0L) != CURLE_OK) {
+        qDebug() << "Failed to set no body";
+        return false;
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, write_data) != CURLE_OK) {
+        qDebug() << "Failed to set write function";
+        return false;
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, &outputFile) != CURLE_OK) {
+        qDebug() << "Failed to set write function";
+        return false;
+    }
+
+    if (curl_easy_perform (mCurl) != CURLE_OK) {
+        qDebug() << "Failed to perform download.";
+        return false;
+    }
+
+    if (!outputFile.commit()) {
+        qDebug() << "Failed to commit data to filesystem.";
+        return false;
+    }
+
+    return true;
 }
+
+QDateTime SSLConnectionCurl::getLastModifiedHeader(const QString &resource) {
+    QUrl urlCopy = mUrl;
+    urlCopy.setPath(resource);
+
+    if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) {
+        qDebug() << "Failed to set URL";
+        return QDateTime();
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) {
+        qDebug() << "Failed to set connect";
+        return QDateTime();
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 1L) != CURLE_OK) {
+        qDebug() << "Failed to set header";
+        return QDateTime();
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 1L) != CURLE_OK) {
+        qDebug() << "Failed to set no body";
+        return QDateTime();
+    }
+
+    if (curl_easy_setopt(mCurl, CURLOPT_FILETIME, 1L) != CURLE_OK) {
+        qDebug() << "Failed to set filetime";
+        return QDateTime();
+    }
+
+    if (curl_easy_perform (mCurl) != CURLE_OK) {
+        qDebug() << "Failed to perform last modified check.";
+        return QDateTime();
+    }
+    long filetime = 0;
+
+    if (curl_easy_getinfo (mCurl, CURLINFO_FILETIME, &filetime) != CURLE_OK) {
+        qDebug() << "Failed to get filetime";
+        return QDateTime();
+    }
+
+    if (filetime == -1) {
+        qDebug() << "Invalid Time";
+        return QDateTime();
+    }
+    return QDateTime::fromTime_t(filetime);
+}
--- a/ui/sslconnection_curl.h	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/sslconnection_curl.h	Mon Aug 18 18:51:33 2014 +0200
@@ -8,11 +8,19 @@
  * See LICENSE.txt for details.
  */
 
+/**
+ * @file sslconnection_curl.h
+ * @brief SSLConnection utilizing libcurl for http.
+ */
+
 #include "sslconnection.h"
 #include <curl/curl.h>
 
+#include <QDateTime>
 #include <QTemporaryFile>
 
+class QSaveFile;
+
 class SSLConnectionCurl : public SSLConnection
 {
 public:
@@ -21,30 +29,20 @@
 
     ~SSLConnectionCurl();
 
-    /** @brief write */
-    int write(const QByteArray& request);
+    int connect();
 
-    /**
-     * @brief read at most len bytes and reset the connection
-     *
-     * @param [in] len Amount of bytes to read.
-     *
-     * @returns a byte array containing the data or
-     * a NULL byte array on error*/
-    QByteArray read(size_t len);
+    QDateTime getLastModifiedHeader(const QString &resource);
 
-    /** @brief: Establish the connection
-     *
-     * @returns 0 on success otherwise an error or -1 is returned
-     */
-    int connect();
+    bool downloadFile(const QString &resource, const QString &filename,
+                      size_t maxSize);
 private:
     CURL *mCurl;
     QTemporaryFile mCertFile;
+    char mErrBuf[CURL_ERROR_SIZE + 1];
+
+    /** @brief Internal write function for curl */
 };
 
-/**
- * @file sslconnection_curl.h
- * @brief SSLConnection utilizing libcurl for http.
- */
+size_t write_data(void *ptr, size_t size, size_t nmemb, QSaveFile *fp);
+
 #endif // UI_SSLCONNECTION_CURL_H
--- a/ui/tests/downloadertest.cpp	Thu Aug 14 11:24:13 2014 +0200
+++ b/ui/tests/downloadertest.cpp	Mon Aug 18 18:51:33 2014 +0200
@@ -94,7 +94,7 @@
     QFileInfo fi(getRandomDataFile(200));
 
     Downloader* downloader = new Downloader(this,
-            QString::fromLatin1("https://localhost:44443"),
+            QString::fromLatin1("https://127.0.0.1:44443"),
             otherCert.readAll(),
             QDateTime::currentDateTime(), // Last installed SW
             QDateTime::fromString("2010", "YYYY"),
@@ -155,7 +155,7 @@
     validCert.open(QIODevice::ReadOnly);
 
     Downloader* downloader = new Downloader(this,
-            QString::fromLatin1("https://localhost:44443"),
+            QString::fromLatin1("https://127.0.0.1:44443"),
             validCert.readAll(),
             QDateTime::fromString("2010", "YYYY"),
             QDateTime::currentDateTime(),
@@ -196,7 +196,7 @@
     validCert.open(QIODevice::ReadOnly);
 
     Downloader* downloader = new Downloader(this,
-            QString::fromLatin1("https://localhost:44443"),
+            QString::fromLatin1("https://127.0.0.1:44443"),
             validCert.readAll(),
             QDateTime::currentDateTime(), // Last installed SW
             QDateTime::fromString("2010", "YYYY"),

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