2
* Copyright 2008 Benjamin C. Meyer <ben@meyerhome.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301 USA
20
/****************************************************************************
22
** Copyright (C) 2007-2008 Trolltech ASA. All rights reserved.
24
** This file is part of the demonstration applications of the Qt Toolkit.
26
** This file may be used under the terms of the GNU General Public
27
** License versions 2.0 or 3.0 as published by the Free Software
28
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
29
** included in the packaging of this file. Alternatively you may (at
30
** your option) use any later version of the GNU General Public
31
** License if such license has been publicly approved by Trolltech ASA
32
** (or its successors, if any) and the KDE Free Qt Foundation. In
33
** addition, as a special exception, Trolltech gives you certain
34
** additional rights. These rights are described in the Trolltech GPL
35
** Exception version 1.2, which can be found at
36
** http://www.trolltech.com/products/qt/gplexception/ and in the file
37
** GPL_EXCEPTION.txt in this package.
39
** Please review the following information to ensure GNU General
40
** Public Licensing requirements will be met:
41
** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
42
** you are unsure which license is appropriate for your use, please
43
** review the following information:
44
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
45
** or contact the sales department at sales@trolltech.com.
47
** In addition, as a special exception, Trolltech, as the sole
48
** copyright holder for Qt Designer, grants users of the Qt/Eclipse
49
** Integration plug-in the right for the Qt/Eclipse Integration to
50
** link to functionality provided by Qt Designer and its related
53
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
54
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
55
** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
58
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
59
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
61
****************************************************************************/
63
#include "networkaccessmanager.h"
65
#include "acceptlanguagedialog.h"
66
#include "browserapplication.h"
67
#include "browsermainwindow.h"
68
#include "schemeaccesshandler.h"
69
#include "ui_passworddialog.h"
73
#include <qmessagebox.h>
74
#include <qsettings.h>
76
#include <qtextdocument.h>
78
#include <qauthenticator.h>
79
#include <qnetworkproxy.h>
80
#include <qnetworkreply.h>
81
#include <qsslconfiguration.h>
82
#include <qsslerror.h>
83
#include <qdatetime.h>
85
#if QT_VERSION >= 0x040500
86
#include <qnetworkdiskcache.h>
87
#include <qdesktopservices.h>
90
#if QT_VERSION >= 0x040500
91
NetworkProxyFactory::NetworkProxyFactory()
92
: QNetworkProxyFactory()
96
void NetworkProxyFactory::setHttpProxy(const QNetworkProxy &proxy)
101
void NetworkProxyFactory::setGlobalProxy(const QNetworkProxy &proxy)
103
m_globalProxy = proxy;
106
QList<QNetworkProxy> NetworkProxyFactory::queryProxy(const QNetworkProxyQuery &query)
108
QList<QNetworkProxy> ret;
110
if (query.protocolTag() == QLatin1String("http") && m_httpProxy.type() != QNetworkProxy::DefaultProxy)
112
ret << m_globalProxy;
118
NetworkAccessManager::NetworkAccessManager(QObject *parent)
119
: QNetworkAccessManager(parent)
121
connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
122
SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)));
123
connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
124
SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
125
#ifndef QT_NO_OPENSSL
126
connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
127
SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&)));
129
connect(BrowserApplication::instance(), SIGNAL(privacyChanged(bool)),
130
this, SLOT(privacyChanged(bool)));
133
// Register custom scheme handlers
134
setSchemeHandler(QLatin1String("file"), new FileAccessHandler(this));
137
void NetworkAccessManager::setSchemeHandler(const QString &scheme, SchemeAccessHandler *handler)
139
m_schemeHandlers.insert(scheme, handler);
142
void NetworkAccessManager::loadSettings()
145
settings.beginGroup(QLatin1String("proxy"));
147
if (settings.value(QLatin1String("enabled"), false).toBool()) {
148
int proxyType = settings.value(QLatin1String("type"), 0).toInt();
150
proxy = QNetworkProxy::Socks5Proxy;
151
else if (proxyType == 1)
152
proxy = QNetworkProxy::HttpProxy;
154
proxy.setType(QNetworkProxy::HttpCachingProxy);
155
#if QT_VERSION >= 0x040500
156
proxy.setCapabilities(QNetworkProxy::CachingCapability | QNetworkProxy::HostNameLookupCapability);
159
proxy.setHostName(settings.value(QLatin1String("hostName")).toString());
160
proxy.setPort(settings.value(QLatin1String("port"), 1080).toInt());
161
proxy.setUser(settings.value(QLatin1String("userName")).toString());
162
proxy.setPassword(settings.value(QLatin1String("password")).toString());
164
#if QT_VERSION >= 0x040500
165
NetworkProxyFactory *proxyFactory = new NetworkProxyFactory;
166
if (proxy.type() == QNetworkProxy::HttpCachingProxy) {
167
proxyFactory->setHttpProxy(proxy);
168
proxyFactory->setGlobalProxy(QNetworkProxy::DefaultProxy);
170
proxyFactory->setHttpProxy(QNetworkProxy::DefaultProxy);
171
proxyFactory->setGlobalProxy(proxy);
173
setProxyFactory(proxyFactory);
179
#ifndef QT_NO_OPENSSL
180
QSslConfiguration sslCfg = QSslConfiguration::defaultConfiguration();
181
QList<QSslCertificate> ca_list = sslCfg.caCertificates();
182
QList<QSslCertificate> ca_new = QSslCertificate::fromData(settings.value(QLatin1String("CaCertificates")).toByteArray());
185
sslCfg.setCaCertificates(ca_list);
186
QSslConfiguration::setDefaultConfiguration(sslCfg);
189
settings.beginGroup(QLatin1String("network"));
190
QStringList acceptList = settings.value(QLatin1String("acceptLanguages"),
191
AcceptLanguageDialog::defaultAcceptList()).toStringList();
192
m_acceptLanguage = AcceptLanguageDialog::httpString(acceptList);
194
#if QT_VERSION >= 0x040500
195
bool cacheEnabled = settings.value(QLatin1String("cacheEnabled"), true).toBool();
196
if (QLatin1String(qVersion()) == QLatin1String("4.5.1"))
197
cacheEnabled = false;
200
int maximumCacheSize = settings.value(QLatin1String("maximumCacheSize"), 50).toInt() * 1024 * 1024;
202
QNetworkDiskCache *diskCache;
204
diskCache = qobject_cast<QNetworkDiskCache*>(cache());
206
diskCache = new QNetworkDiskCache(this);
208
QString location = QDesktopServices::storageLocation(QDesktopServices::CacheLocation)
209
+ QLatin1String("/browser");
210
diskCache->setCacheDirectory(location);
211
diskCache->setMaximumCacheSize(maximumCacheSize);
214
if (QLatin1String(qVersion()) > QLatin1String("4.5.1"))
221
void NetworkAccessManager::privacyChanged(bool isPrivate)
224
#if QT_VERSION >= 0x040500
225
if (QLatin1String(qVersion()) > QLatin1String("4.5.1"))
234
void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
236
BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
238
QDialog dialog(mainWindow);
239
dialog.setWindowFlags(Qt::Sheet);
241
Ui::PasswordDialog passwordDialog;
242
passwordDialog.setupUi(&dialog);
244
passwordDialog.iconLabel->setText(QString());
245
passwordDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
247
QString introMessage = tr("<qt>Enter username and password for \"%1\" at %2</qt>");
248
introMessage = introMessage.arg(Qt::escape(auth->realm())).arg(Qt::escape(reply->url().toString()));
249
passwordDialog.introLabel->setText(introMessage);
250
passwordDialog.introLabel->setWordWrap(true);
252
if (dialog.exec() == QDialog::Accepted) {
253
auth->setUser(passwordDialog.userNameLineEdit->text());
254
auth->setPassword(passwordDialog.passwordLineEdit->text());
258
void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
260
BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
262
QDialog dialog(mainWindow);
263
dialog.setWindowFlags(Qt::Sheet);
265
Ui::ProxyDialog proxyDialog;
266
proxyDialog.setupUi(&dialog);
268
proxyDialog.iconLabel->setText(QString());
269
proxyDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
271
QString introMessage = tr("<qt>Connect to proxy \"%1\" using:</qt>");
272
introMessage = introMessage.arg(Qt::escape(proxy.hostName()));
273
proxyDialog.introLabel->setText(introMessage);
274
proxyDialog.introLabel->setWordWrap(true);
276
if (dialog.exec() == QDialog::Accepted) {
277
auth->setUser(proxyDialog.userNameLineEdit->text());
278
auth->setPassword(proxyDialog.passwordLineEdit->text());
282
#ifndef QT_NO_OPENSSL
283
QString NetworkAccessManager::certToFormattedString(QSslCertificate cert)
286
message << cert.subjectInfo(QSslCertificate::CommonName);
287
message << tr("Issuer: %1").arg(cert.issuerInfo(QSslCertificate::CommonName));
288
message << tr("Not valid before: %1").arg(cert.effectiveDate().toString());
289
message << tr("Valid until: %1").arg(cert.expiryDate().toString());
291
QMultiMap<QSsl::AlternateNameEntryType, QString> names = cert.alternateSubjectNames();
292
if (names.count() > 0) {
294
list += QLatin1String("<br />");
295
list += tr("Alternate Names:");
296
list += QLatin1String("<ul><li>");
297
list += QStringList(names.values(QSsl::DnsEntry)).join(QLatin1String("</li><li>"));
298
list += QLatin1String("</li></ul>");
302
QString result = QLatin1String("<p>") + message.join(QLatin1String("<br />")) + QLatin1String("</p>");
307
void NetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &error)
309
BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
312
QList<QSslCertificate> ca_merge = QSslCertificate::fromData(settings.value(QLatin1String("CaCertificates")).toByteArray());
314
QList<QSslCertificate> ca_new;
315
QStringList errorStrings;
316
for (int i = 0; i < error.count(); ++i) {
317
if (ca_merge.contains(error.at(i).certificate()))
319
errorStrings += error.at(i).errorString();
320
if (!error.at(i).certificate().isNull()) {
321
ca_new.append(error.at(i).certificate());
324
if (errorStrings.isEmpty()) {
325
reply->ignoreSslErrors();
329
QString errors = errorStrings.join(QLatin1String("</li><li>"));
330
int ret = QMessageBox::warning(mainWindow,
331
QCoreApplication::applicationName() + tr(" - SSL Errors"),
333
"<br/><br/>for: <tt>%1</tt>"
334
"<ul><li>%2</li></ul>\n\n"
335
"Do you want to ignore these errors?</qt>").arg(reply->url().toString()).arg(errors),
336
QMessageBox::Yes | QMessageBox::No,
339
if (ret == QMessageBox::Yes) {
340
if (ca_new.count() > 0) {
341
QStringList certinfos;
342
for (int i = 0; i < ca_new.count(); ++i)
343
certinfos += certToFormattedString(ca_new.at(i));
344
ret = QMessageBox::question(mainWindow, QCoreApplication::applicationName(),
345
tr("<qt>Certificates:<br/>"
347
"Do you want to accept all these certificates?</qt>")
348
.arg(certinfos.join(QString())),
349
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
350
if (ret == QMessageBox::Yes) {
353
QSslConfiguration sslCfg = QSslConfiguration::defaultConfiguration();
354
QList<QSslCertificate> ca_list = sslCfg.caCertificates();
356
sslCfg.setCaCertificates(ca_list);
357
QSslConfiguration::setDefaultConfiguration(sslCfg);
358
reply->setSslConfiguration(sslCfg);
361
for (int i = 0; i < ca_merge.count(); ++i)
362
pems += ca_merge.at(i).toPem() + '\n';
363
settings.setValue(QLatin1String("CaCertificates"), pems);
366
reply->ignoreSslErrors();
371
QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
373
QNetworkReply *reply = 0;
375
// Check if there is a valid handler registered for the requested URL scheme
376
if (m_schemeHandlers.contains(request.url().scheme()))
377
reply = m_schemeHandlers[request.url().scheme()]->createRequest(op, request, outgoingData);
381
if (!m_acceptLanguage.isEmpty()) {
382
QNetworkRequest req = request;
383
req.setRawHeader("Accept-Language", m_acceptLanguage);
384
reply = QNetworkAccessManager::createRequest(op, req, outgoingData);
385
emit requestCreated(op, req, reply);
387
reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
388
emit requestCreated(op, request, reply);