UINetworkReply.cpp revision 62fb024c605bcbe2d5fefd31d391cd9fee484150
/* $Id$ */
/** @file
*
* VBox frontends: Qt GUI ("VirtualBox"):
* UINetworkReply stuff implementation
*/
/*
* Copyright (C) 2012-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/* Qt includes: */
#include <QDir>
#include <QFile>
#include <QThread>
#include <QRegExp>
/* GUI includes: */
#include "UINetworkReply.h"
#include "UINetworkManager.h"
#include "VBoxGlobal.h"
#include "VBoxUtils.h"
/* Other VBox includes; */
#include <iprt/initterm.h>
/* Our network-reply thread: */
class UINetworkReplyPrivateThread : public QThread
{
public:
/* Constructor: */
/* API: Read stuff: */
/* API: Error stuff: */
/* API: HTTP stuff: */
void abort();
private:
/* Helpers: HTTP stuff: */
int applyProxyRules();
int applyHttpsCertificates();
int applyRawHeaders();
int performMainRequest();
/* Helper: Main thread runner: */
void run();
/* Static helper: File stuff: */
static QString fullCertificateFileName();
/* Static helpers: HTTP stuff: */
static int applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
static int verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512);
/* Variables: */
int m_iError;
static const QString m_strCertificateFileName;
};
/* static */
const QString UINetworkReplyPrivateThread::m_strCertificateFileName = QString("vbox-ssl-cacertificate.crt");
, m_pHttp(0)
{
}
void UINetworkReplyPrivateThread::abort()
{
/* Call for abort: */
}
{
/* Make sure proxy is enabled in Proxy Manager: */
if (!proxyManager.proxyEnabled())
return VINF_SUCCESS;
/* Apply proxy rules: */
return applyProxyRules(m_pHttp,
}
{
/* Prepare variables: */
int rc = VINF_SUCCESS;
/* Check certificates if present: */
else
/* Download certificates if necessary: */
if (!RT_SUCCESS(rc))
/* Apply certificates: */
if (RT_SUCCESS(rc))
/* Return result-code: */
return rc;
}
{
/* Make sure we have a raw headers at all: */
return VINF_SUCCESS;
/* Apply raw headers: */
}
{
/* Perform GET request: */
}
void UINetworkReplyPrivateThread::run()
{
/* Init: */
/* Create HTTP object: */
if (RT_SUCCESS(m_iError))
/* Apply proxy-rules: */
if (RT_SUCCESS(m_iError))
m_iError = applyProxyRules();
/* Apply https-certificates: */
if (RT_SUCCESS(m_iError))
/* Assign raw-headers: */
if (RT_SUCCESS(m_iError))
m_iError = applyRawHeaders();
/* Perform main request: */
if (RT_SUCCESS(m_iError))
/* Destroy HTTP object: */
if (m_pHttp)
{
m_pHttp = 0;
}
}
/* static */
{
}
/* static */
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* Call for HTTP abort: */
return RTHttpAbort(pHttp);
}
/* static */
int UINetworkReplyPrivateThread::applyProxyRules(RTHTTP pHttp, const QString &strHostName, int iPort)
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* Apply HTTP proxy: */
return RTHttpSetProxy(pHttp,
0 /* login */, 0 /* password */);
}
/* static */
int UINetworkReplyPrivateThread::applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* Apply HTTPs certificates: */
}
/* static */
int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request)
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* We should format them first: */
QVector<const char*> formattedHeaderPointers;
{
/* Prepare formatted representation: */
QString strFormattedString = QString("%1: %2").arg(QString(header), QString(request.rawHeader(header)));
}
/* Apply HTTP headers: */
}
/* static */
int UINetworkReplyPrivateThread::performGetRequest(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply)
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* Perform blocking HTTP GET request: */
char *pszBuf = 0;
&pszBuf);
return rc;
}
/* static */
int UINetworkReplyPrivateThread::checkCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
{
/* Open certificates file: */
/* Read certificates file: */
if (RT_SUCCESS(rc))
{
/* Parse the file content: */
#define CERT "-{5}BEGIN CERTIFICATE-{5}[\\s\\S\\r{0,1}\\n]+-{5}END CERTIFICATE-{5}"
/* First check if we have the old format with three certificates: */
regExp.setMinimal(true);
/* If so, fake an error to force re-downloading */
/* Otherwise, check for two certificates: */
if (RT_SUCCESS(rc))
{
regExp.setMinimal(true);
}
/* Verify certificates: */
if (RT_SUCCESS(rc))
{
}
if (RT_SUCCESS(rc))
{
}
}
/* Close certificates file: */
if (fFileOpened)
/* Return result-code: */
return rc;
}
/* static */
int UINetworkReplyPrivateThread::downloadCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
{
/* Open certificates file: */
/* Download PCA-3G5 certificate: */
if (RT_SUCCESS(rc))
/* Download PCA-3 certificate: */
if (RT_SUCCESS(rc))
/* Close certificates file: */
if (fFileOpened)
/* Return result-code: */
return rc;
}
/* static */
{
/* Receive certificate: */
const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem"));
/* Verify certificate: */
if (RT_SUCCESS(rc))
/* Save certificate: */
if (RT_SUCCESS(rc))
/* Return result-code: */
return rc;
}
/* static */
{
/* Receive certificate: */
const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem"));
/* Verify certificate: */
if (RT_SUCCESS(rc))
/* Save certificate: */
if (RT_SUCCESS(rc))
/* Return result-code: */
return rc;
}
/* static */
{
/* PCA 3G5 secure hash algorithm 1: */
const unsigned char baSha1PCA3G5[] =
{
0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
};
/* PCA 3G5 secure hash algorithm 512: */
const unsigned char baSha512PCA3G5[] =
{
0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
};
QByteArray pca3G5sha512 = QByteArray::fromRawData((const char *)baSha512PCA3G5, sizeof(baSha512PCA3G5));
/* Verify certificate: */
}
/* static */
{
/* PCA 3 secure hash algorithm 1: */
const unsigned char baSha1PCA3[] =
{
0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
};
/* PCA 3 secure hash algorithm 512: */
const unsigned char baSha512PCA3[] =
{
0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20,
0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e,
0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6,
0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b,
0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b,
0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d,
0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
};
/* Verify certificate: */
}
/* static */
int UINetworkReplyPrivateThread::verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512)
{
/* Make sure HTTP is created: */
if (!pHttp)
return VERR_INVALID_POINTER;
/* Create digest: */
/* Verify digest: */
/* Cleanup digest: */
/* Return result-code: */
return rc;
}
/* static */
{
/* Save certificate: */
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
/* Add 'new-line' character: */
if (RT_SUCCESS(rc))
#ifdef Q_WS_WIN
#else /* Q_WS_WIN */
#endif /* !Q_WS_WIN */
/* Return result-code: */
return rc;
}
/* Our network-reply object: */
class UINetworkReplyPrivate : public QObject
{
/* Notifiers: */
void finished();
public:
/* Constructor: */
, m_pThread(0)
{
/* Create and run network-reply thread: */
}
/* Destructor: */
{
/* Terminate network-reply thread: */
delete m_pThread;
m_pThread = 0;
}
/* API: Abort reply: */
void abort()
{
}
/* API: Error-code getter: */
/* API: Error-string getter: */
QString errorString() const
{
switch (m_error)
{
case QNetworkReply::NoError:
break;
case QNetworkReply::HostNotFoundError:
return tr("Host not found");
case QNetworkReply::ContentAccessDenied:
return tr("Content access denied");
case QNetworkReply::ProtocolFailure:
return tr("Protocol failure");
return tr("Wrong SSL certificate format");
return tr("SSL authentication failed");
default:
return tr("Unknown reason");
break;
}
return QString();
}
/* API: Reply getter: */
private slots:
/* Handler: Thread finished: */
void sltFinished()
{
{
case VINF_SUCCESS:
break;
case VERR_HTTP_ABORTED:
break;
case VERR_HTTP_NOT_FOUND:
break;
case VERR_HTTP_ACCESS_DENIED:
break;
case VERR_HTTP_BAD_REQUEST:
break;
break;
break;
default:
break;
}
}
private:
/* Variables: */
};
, m_pReply(0)
{
/* Create network-reply object: */
switch (requestType)
{
/* Prepare Qt network-reply (HEAD): */
break;
/* Prepare Qt network-reply (GET): */
case UINetworkRequestType_GET:
break;
/* Prepare our network-reply (GET): */
break;
}
/* Prepare network-reply object connections: */
connect(m_pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
}
{
/* Cleanup network-reply object: */
if (m_pReply)
{
delete m_pReply;
m_pReply = 0;
}
}
{
switch (m_replyType)
{
case UINetworkReplyType_Our: /* TODO: header() */ break;
}
return result;
}
{
switch (m_replyType)
{
case UINetworkReplyType_Qt: result = qobject_cast<QNetworkReply*>(m_pReply)->attribute(code); break;
case UINetworkReplyType_Our: /* TODO: attribute() */ break;
}
return result;
}
void UINetworkReply::abort()
{
switch (m_replyType)
{
}
}
{
switch (m_replyType)
{
case UINetworkReplyType_Our: result = qobject_cast<UINetworkReplyPrivate*>(m_pReply)->error(); break;
}
return result;
}
{
switch (m_replyType)
{
case UINetworkReplyType_Qt: strResult = qobject_cast<QNetworkReply*>(m_pReply)->errorString(); break;
case UINetworkReplyType_Our: strResult = qobject_cast<UINetworkReplyPrivate*>(m_pReply)->errorString(); break;
}
return strResult;
}
{
switch (m_replyType)
{
case UINetworkReplyType_Our: result = qobject_cast<UINetworkReplyPrivate*>(m_pReply)->readAll(); break;
}
return result;
}
{
switch (m_replyType)
{
case UINetworkReplyType_Our: /* TODO: url() */ break;
}
return result;
}
#include "UINetworkReply.moc"