Comparar commits

..

90 Commits

Autor SHA1 Mensagem Data
Olivier Goffart 0249a68420 SelectiveSync: adjust the position of the "Loading" label
It should be parented to the treeview to be sure that is shows inside of it.
2017-01-13 10:55:45 +01:00
Christian Kamm aa6f041c36 wizardSelectiveSyncDefaultNothing applies to folder wizard #4581
Previous the Theme option only applied to the account setup wizard.
2017-01-13 10:52:39 +01:00
Christian Kamm dce3f8c4f6 Selective sync: Adjust widget common to folder/account wizards 2017-01-13 10:52:10 +01:00
Christian Kamm 084146756b Account: Fix displayName() #5413
This displayName() seemed to be based on Account::user() which used
to call _credentials->user(). But then we repurposed user() to be
davUser() and this usage wasn't updated to point back to the username
used for the credentials.
2017-01-03 13:54:59 +01:00
ckamm e1f5a49c21 Don't blacklist 507 Insufficent Storage #5346 (#5424) 2017-01-03 13:48:32 +01:00
ckamm 143320341e Build: Enable Q_ASSERT in release mode (#5425) 2017-01-03 13:42:25 +01:00
Christian Kamm e286bb1b64 Wizard: Don't accidentally pre-fill url field #5412
slotUrlEditFinished() is called when the wizard is triggered in
some situations.
2017-01-03 11:53:40 +01:00
Olivier Goffart d433f0e08e HTTPCreds: remove all cookies when logging out (#5383)
Some custom server use persistent cookies with the auth token. So we should
clear all the cookies when disconnecting.
Account::clearCookieJar is only called from the HTTPCredentials. This funciton
is not used for shibboleth.
There is probably no reasons to keep the HTTP cookie anyway.

Issue #5370
2017-01-03 11:39:10 +01:00
Christian Kamm 107149d601 Doc: Improve example #5422 2017-01-03 11:31:51 +01:00
Christian Kamm fa9b36f829 Wizard: Let the user know if url is invalid #5398 2017-01-03 11:28:56 +01:00
Christian Kamm 6775292d63 Fix compile of tests 2017-01-03 10:52:39 +01:00
Christian Kamm 6835429a28 Sql: Allow prepare fail for PRAGMA quick_check #5357
This actually happens in low-disk situations.
2017-01-03 10:43:29 +01:00
Christian Kamm 22135f9f57 Fixup broken authType on load #5408 2017-01-03 10:38:20 +01:00
Jenkins for ownCloud 0fd06a225c [tx-robot] updated from transifex 2017-01-03 02:19:30 +01:00
Christian Kamm 473dcb0947 Only create a FolderWatcher if the path exists
Also retry creating it before each sync.

See #5317
2017-01-02 08:52:26 +01:00
Christian Kamm e306f4611c Reschedule a folder regularly with some delay for some errors
Like "folder doesn't exist" - such that we will detect when the folder
becomes available and start syncing.

See #5317
2017-01-02 08:52:26 +01:00
Markus Goetz c6f4f44619 Fix up SSL client certificates #5213 #69 (#5289)
The re-enables the UI, uses Qt API for importing and
stores the certificate/key in the system keychain.
People who had set up client certs need to re-setup the account. This is ok
since it was an undocumented feature anyway.
2017-01-02 08:34:02 +01:00
Jenkins for ownCloud 0865c63745 [tx-robot] updated from transifex 2017-01-02 02:19:26 +01:00
Jenkins for ownCloud b81c3a6a67 [tx-robot] updated from transifex 2017-01-01 02:19:32 +01:00
Jenkins for ownCloud cc56e5639d [tx-robot] updated from transifex 2016-12-30 02:18:34 +01:00
Jenkins for ownCloud 3ce5b358ae [tx-robot] updated from transifex 2016-12-25 02:18:27 +01:00
Jenkins for ownCloud e968284618 [tx-robot] updated from transifex 2016-12-24 02:18:26 +01:00
Jenkins for ownCloud c7723179d8 [tx-robot] updated from transifex 2016-12-23 02:18:34 +01:00
Jenkins for ownCloud 1872f3f94a [tx-robot] updated from transifex 2016-12-22 02:18:30 +01:00
Christian Kamm 3b7887ca35 Wizard: Detach saved account from wizard
Fixes #5408 #5407.

The problem was that cleanup of the credentials page set the
credentials of the account back to dummy, thereby overriding
things like shib usernames.

This should be broken since a932eac832.
2016-12-21 15:31:12 +01:00
Piotr Mrówczyński d781e63fab Add capability to disable parallel chunked upload #5364 - technical review (#5403) 2016-12-21 15:08:45 +01:00
Kyle Fazzari d1237cdda3 Correctly handle possible missing GIT_SHA1. (#5401)
Currently, if get_git_head_revision() doesn't define GIT_SHA1 (which it
doesn't in some cases) it's possible to end up with the following error:

    CMake Error at CMakeLists.txt:69 (if):
      if given arguments:

        "STREQUAL" "GITDIR-NOTFOUND"

      Unknown arguments specified

Fix this by making sure both left and right hand arguments to STREQUAL
are always strings, even if GIT_SHA1 is undefined.

Signed-off-by: Kyle Fazzari <kyle@canonical.com>
2016-12-21 14:14:26 +01:00
Christian Kamm 030e3a5d4a Increase initial bandwidth estimates #4428 #5390
To 2 MB/s and 10 files/s.
2016-12-21 08:53:47 +01:00
Jenkins for ownCloud 4fa4a6a5ed [tx-robot] updated from transifex 2016-12-21 02:18:28 +01:00
Phil Davis 23fb07240b Fix Mac PATH command
Reported in the doc repo owncloud/documentation#1618
This version as suggested by @jturcotte
2016-12-20 20:01:38 +01:00
Christian Kamm 3912dba33a Move qDeclareMetatype from Folder to SyncEngine 2016-12-20 11:43:39 +01:00
Christian Kamm d8c479ab1e Don't wipe db if check fails while disk space is low #5357
An experimental fix for the issue, merged because it's low risk and
makes testing easier.
2016-12-20 09:33:59 +01:00
Jenkins for ownCloud bec67455c1 [tx-robot] updated from transifex 2016-12-20 02:18:27 +01:00
Jenkins for ownCloud ba6a37a601 [tx-robot] updated from transifex 2016-12-19 02:18:28 +01:00
Jenkins for ownCloud 03f5091e73 [tx-robot] updated from transifex 2016-12-18 02:18:28 +01:00
Jenkins for ownCloud 6b6ff08821 [tx-robot] updated from transifex 2016-12-17 02:18:27 +01:00
Jenkins for ownCloud 35a0ee4893 [tx-robot] updated from transifex 2016-12-16 02:18:29 +01:00
Jenkins for ownCloud 3519391119 [tx-robot] updated from transifex 2016-12-15 02:18:37 +01:00
Olivier Goffart 775a1c9ad8 FolderStatusModel: Fix insert/remove items when there are labels
Otherwise it might happen that the model is inconsistant and this can
lead to crash in the worst case.

(For example, if there was a "fetching" label, and we hide it because it
was a 404. In this case, we would not call begin/endRemoveRows, so the
view could still call the model with an index of row 0, that used to be
for the label, but now correspond to the first element of _subs. And
because _subs is empty, this could lead to crashes)
2016-12-14 14:13:47 +01:00
Olivier Goffart ac95844ebd Propagator: make sure every network job has a parent
This could make sure that the network job gets deleted if the parent job gets
deleted, and would avoid crashes like:

Crash: EXCEPTION_ACCESS_VIOLATION_READ at 0xffffffff8b008a04
  File "qiodevice.cpp", line 1617, in QIODevice::errorString
  File "propagatedownload.cpp", line 264, in OCC::GETFileJob::slotReadyRead
  File "moc_propagatedownload.cpp", line 85, in OCC::GETFileJob::qt_static_metacall
  File "qobject.cpp", line 3716, in QMetaObject::activate
  File "moc_qiodevice.cpp", line 154, in QIODevice::readyRead
  File "qnetworkreplyhttpimpl.cpp", line 1045, in QNetworkReplyHttpImplPrivate::replyDownloadData

(#5329)
2016-12-14 14:13:47 +01:00
Olivier Goffart c5b90d9507 Account::slotHandleSslErrors: add guards in case the reply gets deleted in the dialog event loop
Since slotHandleSslErrors will show a dialog with an eventloop, it could be
That the reply gets deleted. Guard against that.

(#5329)
2016-12-14 14:13:47 +01:00
Christian Kamm d631f2e070 Sync now: Disable on disconnect, rename while running #2158 2016-12-13 15:28:52 +01:00
Jonathan Kawohl 5bae2ed5ef fixed merge conflicts 2016-12-13 09:12:50 +01:00
Jenkins for ownCloud 5af2a657ca [tx-robot] updated from transifex 2016-12-13 02:18:28 +01:00
Jenkins for ownCloud 71231026a0 [tx-robot] updated from transifex 2016-12-12 02:18:28 +01:00
Jenkins for ownCloud dfca67b63a [tx-robot] updated from transifex 2016-12-11 02:18:27 +01:00
Jenkins for ownCloud 7dc6a3b89f [tx-robot] updated from transifex 2016-12-10 02:18:32 +01:00
Jocelyn Turcotte f985111b62 Fix the log window not showing csync logs
The csync log level was only set up on startup, and for log files.
Fix the issue by making Logger::isNoop rely on being explicitly activated
for the log window instead of relying on the presence of a connected
signal, and move the csync log level logic in Logger.
2016-12-09 10:03:46 +01:00
Jocelyn Turcotte e8d734b1c2 Fix the sync direction being wrong on MSVC
The compiler seems to use signed enums and we need to reserve an extra
bit for the sign to avoid the 2 value to overflow and being interpreted
as -2 when read, and thus not being correctly compared to the full enum
value.
2016-12-09 10:03:46 +01:00
Jenkins for ownCloud a38864fcb4 [tx-robot] updated from transifex 2016-12-09 02:18:28 +01:00
Jenkins for ownCloud 47bab51474 [tx-robot] updated from transifex 2016-12-08 02:18:27 +01:00
Jocelyn Turcotte d0d5b2b4ee Don't try to deploy the mng image format plugin on macOS
Qt now only build it if the system library is available since libmng
isn't active enough to make its security reliable enough. We don't
use that image format ourselves anyway.
2016-12-07 15:26:23 +01:00
Jocelyn Turcotte 36967122db Rebase Qt patches on 5.6 #3449
Also get rid of the list of different version. We always only support one Qt version
for macOS and Windows, and the list of patches will be based on that supported
version.
2016-12-07 15:26:23 +01:00
Jenkins for ownCloud 3fd67b9fb6 [tx-robot] updated from transifex 2016-12-07 02:18:34 +01:00
ckamm 5bef1aa402 Merge pull request #5045 from owncloud/dbjournal_per_account
Allow a folder to be synced to several accounts. This changes the path of the sync journal file!
2016-12-06 10:55:58 +01:00
Jenkins for ownCloud de9ea19e7e [tx-robot] updated from transifex 2016-12-06 02:18:34 +01:00
Olivier Goffart 4ac2b764a4 libsync: Clear the upload info after several retries (#5345)
Issue #5344
2016-12-05 17:21:36 +01:00
Jenkins for ownCloud 0614cda337 [tx-robot] updated from transifex 2016-12-05 02:18:32 +01:00
Jenkins for ownCloud 9e895b9b3e [tx-robot] updated from transifex 2016-12-04 02:18:28 +01:00
Jenkins for ownCloud f501211c63 [tx-robot] updated from transifex 2016-12-03 02:18:25 +01:00
Jenkins for ownCloud 77ac1b46dd [tx-robot] updated from transifex 2016-12-02 02:18:35 +01:00
Jenkins for ownCloud 745c21623c [tx-robot] updated from transifex 2016-12-01 02:18:28 +01:00
Jenkins for ownCloud b91c116518 [tx-robot] updated from transifex 2016-11-30 02:18:34 +01:00
Felix Tiede d090a3330a Generate .desktop file with OEM name directly.
Instead of renaming the .desktop file at install time it is now
generated with its OEM name during configure time.
2016-11-29 18:36:26 +01:00
Felix Tiede d04e7841e2 Fix file installation source path.
By default the file is copied from the source and not the build
directory which will fail with the configure-time built file.
2016-11-29 18:36:26 +01:00
Felix Tiede d7a4726544 Extend OEM configurability to dolphin desktop file.
OEM configurability creates binaries with OEM names which the .desktop
file doesn't take into account and thus dolphin integration does not
work if OEM changes the binary's name(s).
These changes are now integrated into the .desktop file at compile time.
2016-11-29 18:36:26 +01:00
Olivier Goffart 19d2677db1 libsync: use the new webdav url if the server reports it
The rules to select the webdav url are now:

 - If the server reports that the new chunking algorithm is working,
   always use remote.php/dav/files/<username>
   This capability can be overriden with an environment variable

 - Otherwise, use the dav path provided by the theme, which defaults to
   remote.php/webdav

This means that with the newer server, the branding can no longer override
the webdav URL. If there is still an usecase for the branding to do so, we
need to find another way to override it. But it is now more complicated to
configure as might need include the username and need different endpoint
depending on the operations (chunks or not)

Issue #4007
2016-11-29 16:16:20 +01:00
Christian Kamm acb155503b Ensure the 'Sync paused' state is used after pausing #5290 2016-11-29 09:56:45 +01:00
Jenkins for ownCloud 4cb80b08a2 [tx-robot] updated from transifex 2016-11-29 02:18:28 +01:00
Jenkins for ownCloud cd85b7c6d7 [tx-robot] updated from transifex 2016-11-28 02:18:33 +01:00
Olivier Goffart 109056e676 owncloudcmd: Don't put the password in the URL
As the URL might be print on the logs.
Also don't change the scheme from http to owncloud.

This was required before when we were using neon through csync, but now that
we use QNAM for everything we don't need it. The credentials from the account
are used.
2016-11-26 12:57:44 +01:00
Jenkins for ownCloud 51a1bea5de [tx-robot] updated from transifex 2016-11-26 02:18:36 +01:00
Christian Kamm 68f99bcc27 AccountSettings: Add a "Force sync now" context menu option 2016-11-25 14:23:56 +01:00
Jenkins for ownCloud 7523db354d [tx-robot] updated from transifex 2016-11-25 02:18:27 +01:00
Jenkins for ownCloud 4919c9e7b1 [tx-robot] updated from transifex 2016-11-24 02:18:38 +01:00
Christian Kamm 045498c71a Account: Rename user() to davUser()
Avoids potential confusion with credentials->user()
2016-11-23 17:08:17 +01:00
Markus Goetz 679ac0d26a Wizard: Show if server asks for client certificate #2799 #69 (#5261)
This also nicely displays the 'Untrusted domain' message of oC.
The link to add a trusted domain (via web browser) is clickable.
2016-11-23 11:43:15 +01:00
Markus Goetz 2e3a3bcf84 Folder: Make folder only accessible by user #5282 (#5315)
Because on OS X the parent folder might not protect
against access.
2016-11-23 11:05:41 +01:00
Jonathan Kawohl ad437a49f9 Merge branch 'Kawohl-master'
fix conflict
2016-11-23 11:01:52 +01:00
Jonathan Kawohl 6b2282bf0d Merge branch 'master' of https://github.com/owncloud/client into Kawohl-master
fix conflict
2016-11-23 10:59:18 +01:00
Jonathan Kawohl 42aed56a5a Merge branch 'master' of https://gthub.com/Kawohl/client into Kawohl-master
fix conflict
2016-11-23 10:56:29 +01:00
Jonathan Kawohl ca9ec46253 fixed note 2016-11-23 09:17:33 +01:00
Jonathan Kawohl a92eec160a fixed review https://github.com/owncloud/client/pull/5259#pullrequestreview-9743725 2016-11-23 09:10:58 +01:00
Jenkins for ownCloud cc91c42dfa [tx-robot] updated from transifex 2016-11-23 02:18:37 +01:00
Olivier Goffart d22d0e7e30 Propagator: don't use dynamic_cast for QObject
qobject_cast is better. (no need to use RTTI when we have QMetaObject
2016-11-22 17:37:41 +01:00
Jonathan Kawohl ffac3f6213 fixing wrong files Revert "fix for https://github.com/owncloud/client/issues/1251"
This reverts commit 4f1feab845.
2016-10-24 15:16:06 +02:00
Jonathan Kawohl 4f1feab845 fix for https://github.com/owncloud/client/issues/1251 2016-10-24 15:09:25 +02:00
Jonathan Kawohl f738cfd7fe added info on qtkeychain
added installation info on qtkeychain
2016-10-24 09:00:07 +02:00
Jonathan Kawohl 092c935422 Correcting for PR comments 2016-10-20 13:05:56 +02:00
Jonathan Kawohl 72d8175032 updated link for documentation and added more info to osx build 2016-10-19 11:12:11 +02:00
111 arquivos alterados com 8864 adições e 10618 exclusões
+4 -1
Ver Arquivo
@@ -58,6 +58,9 @@ if( UNIX AND NOT APPLE )
endif()
####
# Enable Q_ASSERT etc. in all builds
add_definitions( -DQT_FORCE_ASSERTS )
include(GNUInstallDirs)
include(DefineInstallationPaths)
include(GenerateExportHeader)
@@ -69,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
# if we cannot get it from git, directly try .tag (packages)
# this will work if the tar balls have been properly created
# via git-archive.
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
-1
Ver Arquivo
@@ -40,7 +40,6 @@ QT_PLUGINS = [
'imageformats/libqico.dylib',
'imageformats/libqjpeg.dylib',
'imageformats/libqsvg.dylib',
'imageformats/libqmng.dylib',
]
QT_PLUGINS_SEARCH_PATH=[
@@ -1,42 +0,0 @@
From ea4dcc5931d455e4ee3e958ffa54a9f54ab022c8 Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Mon, 5 Jan 2015 10:45:25 +0100
Subject: [PATCH 1/3] Fix crash on Mac OS if PAC URL contains non-URL legal
chars
macQueryInternal() was retrieving the PAC URL string as-entered by
the user in the 'Proxies' tab of the system network settings dialog
and passing it to CFURLCreateWithString().
CFURLCreateWithString() returns null if the input string contains
non-URL legal chars or is empty.
Change-Id: I9166d0433a62c7b2274b5435a7dea0a16997d10e
Patch-By: Robert Knight
Task-number: QTBUG-36787
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
Reviewed-by: Markus Goetz <markus@woboq.com>
---
src/network/kernel/qnetworkproxy_mac.cpp | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
index 7d26246..81bce0c 100644
--- a/src/network/kernel/qnetworkproxy_mac.cpp
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -221,7 +221,11 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
int enabled;
if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
// PAC is enabled
- CFStringRef cfPacLocation = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
+ // kSCPropNetProxiesProxyAutoConfigURLString returns the URL string
+ // as entered in the system proxy configuration dialog
+ CFStringRef pacLocationSetting = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
+ QCFType<CFStringRef> cfPacLocation = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, pacLocationSetting, NULL, NULL,
+ kCFStringEncodingUTF8);
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
QCFType<CFDataRef> pacData;
--
1.8.3.4 (Apple Git-47)
@@ -1,38 +0,0 @@
From a83e4d1d9dd90d4563ce60f27dfb7802a780e33e Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Mon, 5 Jan 2015 11:42:52 +0100
Subject: [PATCH 2/3] Fix possible crash when passing an invalid PAC URL
This commit checks whether CFURLCreateWithString() succeeded.
It does not appear to be possible to enter an empty URL directly in the
PAC configuration dialog but I can't rule out the possibility
that it could find its way into the settings via some other means.
Change-Id: I6c2053d385503bf0330f5ae9fb1ec36a473d425d
Patch-By: Robert Knight
Task-number: QTBUG-36787
Reviewed-by: Markus Goetz <markus@woboq.com>
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
---
src/network/kernel/qnetworkproxy_mac.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
index 81bce0c..6be032e 100644
--- a/src/network/kernel/qnetworkproxy_mac.cpp
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -230,6 +230,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
QCFType<CFDataRef> pacData;
QCFType<CFURLRef> pacUrl = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, NULL);
+ if (!pacUrl) {
+ qWarning("Invalid PAC URL \"%s\"", qPrintable(QCFString::toQString(cfPacLocation)));
+ return result;
+ }
SInt32 errorCode;
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacUrl, &pacData, NULL, NULL, &errorCode)) {
QString pacLocation = QCFString::toQString(cfPacLocation);
--
1.8.3.4 (Apple Git-47)
@@ -1,39 +0,0 @@
From 83bd9393e5564ea9168fda90c0f44456633a483a Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Mon, 5 Jan 2015 15:22:57 +0100
Subject: [PATCH 3/3] Fix crash if PAC script retrieval returns a null CFData
instance
The documentation for CFURLCreateDataAndPropertiesFromResource()
does not make this clear but from looking at the CFNetwork implementation
and a user stacktrace it appears that this function can return true
but not set the data argument under certain circumstances.
Change-Id: I48034a640d6f47a51cd5883bbafacad4bcbd0415
Task-number: QTBUG-36787
Patch-By: Robert Knight
Reviewed-by: Markus Goetz <markus@woboq.com>
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
---
src/network/kernel/qnetworkproxy_mac.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
index 6be032e..a1ac349 100644
--- a/src/network/kernel/qnetworkproxy_mac.cpp
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
@@ -240,7 +240,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
qWarning("Unable to get the PAC script at \"%s\" (%s)", qPrintable(pacLocation), cfurlErrorDescription(errorCode));
return result;
}
-
+ if (!pacData) {
+ qWarning("\"%s\" returned an empty PAC script", qPrintable(QCFString::toQString(cfPacLocation)));
+ return result;
+ }
QCFType<CFStringRef> pacScript = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1);
if (!pacScript) {
// This should never happen, but the documentation says it may return NULL if there was a problem creating the object.
--
1.8.3.4 (Apple Git-47)
@@ -1,32 +0,0 @@
From 22f3d359350fd65e4bbe2e9420fcc4460e8a590a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= <morten.sorvig@digia.com>
Date: Tue, 10 Mar 2015 22:37:39 +0100
Subject: [PATCH] Cocoa: Fix systray SVG icons.
Regression caused by f3699510.
Task-number: QTBUG-44686
Change-Id: I546422a67d4da29fac196025b09bddcb45c1b641
Reviewed-by: Timur Pocheptsov <Timur.Pocheptsov@digia.com>
---
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index e449fd3..8a35705 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -234,6 +234,10 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
}
}
+ // Handle SVG icons, which do not return anything for availableSizes().
+ if (!selectedSize.isValid())
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
+
QPixmap pixmap = icon.pixmap(selectedSize, mode);
// Draw a low-resolution icon if there is not enough pixels for a retina
--
1.9.1
@@ -1,115 +0,0 @@
From ee7fea33383726f0bb72e8082a357820e3ee3675 Mon Sep 17 00:00:00 2001
From: Jocelyn Turcotte <jturcotte@woboq.com>
Date: Tue, 24 Feb 2015 17:02:02 +0100
Subject: [PATCH] OSX Fix disapearing tray icon
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It would happen together with an error:
QPainter::begin: Paint device returned engine == 0
and would be caused by the size provided to QIcon::pixmap being empty,
itself caused by the availableSizes list being empty for the Selected
mode.
This bug was most often hidden by the fact that the Selected icon mode
was not triggered properly since we usually only set menuVisible after
calling updateIcon, and most of the time when it did, we would overwrite
it right after with a Normal mode icon.
Fix the issue by disabling the broken feature completely since the
default Selected icon is grayed out while tray icons are now usually
black (or white when selected). To support the dark menu bar mode on
10.10 we'll need to use NSImage's setTemplate anyway and that
knowing in advance if we can invert the colors ourselves would also
better solve the menuVisible usecase.
Task-number: QTBUG-42910
Change-Id: If9ec9659af28ecceb841bfc2f11721e6029fe891
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
---
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 8a35705..d366a3c 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -102,7 +102,6 @@ QT_USE_NAMESPACE
QCocoaSystemTrayIcon *systray;
NSStatusItem *item;
QCocoaMenu *menu;
- bool menuVisible;
QIcon icon;
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
}
@@ -202,8 +201,6 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
m_sys->item->icon = icon;
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
-
// The reccomended maximum title bar icon height is 18 points
// (device independent pixels). The menu height on past and
// current OS X versions is 22 points. Provide some future-proofing
@@ -218,9 +215,8 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// devicePixelRatio for the "best" screen on the system.
qreal devicePixelRatio = qApp->devicePixelRatio();
const int maxPixmapHeight = maxImageHeight * devicePixelRatio;
- const QIcon::Mode mode = menuVisible ? QIcon::Selected : QIcon::Normal;
QSize selectedSize;
- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) {
+ Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) {
// Select a pixmap based on the height. We want the largest pixmap
// with a height smaller or equal to maxPixmapHeight. The pixmap
// may rectangular; assume it has a reasonable size. If there is
@@ -236,9 +232,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// Handle SVG icons, which do not return anything for availableSizes().
if (!selectedSize.isValid())
- selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight));
- QPixmap pixmap = icon.pixmap(selectedSize, mode);
+ QPixmap pixmap = icon.pixmap(selectedSize);
// Draw a low-resolution icon if there is not enough pixels for a retina
// icon. This prevents showing a small icon on retina displays.
@@ -385,9 +381,6 @@ QT_END_NAMESPACE
Q_UNUSED(notification);
down = NO;
- parent->systray->updateIcon(parent->icon);
- parent->menuVisible = false;
-
[self setNeedsDisplay:YES];
}
@@ -397,8 +390,6 @@ QT_END_NAMESPACE
int clickCount = [mouseEvent clickCount];
[self setNeedsDisplay:YES];
- parent->systray->updateIcon(parent->icon);
-
if (clickCount == 2) {
[self menuTrackingDone:nil];
[parent doubleClickSelector:self];
@@ -454,7 +445,6 @@ QT_END_NAMESPACE
if (self) {
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
menu = 0;
- menuVisible = false;
systray = sys;
imageCell = [[QNSImageView alloc] initWithParent:self];
[item setView: imageCell];
@@ -498,7 +488,6 @@ QT_END_NAMESPACE
selector:@selector(menuTrackingDone:)
name:NSMenuDidEndTrackingNotification
object:m];
- menuVisible = true;
[item popUpStatusItemMenu: m];
}
}
--
1.9.1
@@ -1,691 +0,0 @@
From cff39fba10ffc10ee4dcfdc66ff6528eb26462d3 Mon Sep 17 00:00:00 2001
From: Markus Goetz <markus@woboq.com>
Date: Fri, 10 Apr 2015 14:09:53 +0200
Subject: [PATCH] QNAM: Fix upload corruptions when server closes connection
This patch fixes several upload corruptions if the server closes the connection
while/before we send data into it. They happen inside multiple places in the HTTP
layer and are explained in the comments.
Corruptions are:
* The upload byte device has an in-flight signal with pending upload data, if
it gets reset (because server closes the connection) then the re-send of the
request was sometimes taking this stale in-flight pending upload data.
* Because some signals were DirectConnection and some were QueuedConnection, there
was a chance that a direct signal overtakes a queued signal. The state machine
then sent data down the socket which was buffered there (and sent later) although
it did not match the current state of the state machine when it was actually sent.
* A socket was seen as being able to have requests sent even though it was not
encrypted yet. This relates to the previous corruption where data is stored inside
the socket's buffer and then sent later.
The included auto test produces all fixed corruptions, I detected no regressions
via the other tests.
This code also adds a bit of sanity checking to protect from possible further
problems.
[ChangeLog][QtNetwork] Fix HTTP(s) upload corruption when server closes connection
Change-Id: I54c883925ec897050941498f139c4b523030432e
Reviewed-by: Peter Hartmann <peter-qt@hartmann.tk>
---
src/corelib/io/qnoncontiguousbytedevice.cpp | 18 +++
src/corelib/io/qnoncontiguousbytedevice_p.h | 4 +
.../access/qhttpnetworkconnectionchannel.cpp | 35 ++++-
.../access/qhttpnetworkconnectionchannel_p.h | 2 +
src/network/access/qhttpprotocolhandler.cpp | 7 +
src/network/access/qhttpthreaddelegate_p.h | 36 ++++-
src/network/access/qnetworkreplyhttpimpl.cpp | 25 ++-
src/network/access/qnetworkreplyhttpimpl_p.h | 7 +-
.../access/qnetworkreply/tst_qnetworkreply.cpp | 175 ++++++++++++++++++++-
9 files changed, 279 insertions(+), 30 deletions(-)
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
index 11510a8..760ca3d 100644
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -236,6 +236,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size()
return byteArray->size();
}
+qint64 QNonContiguousByteDeviceByteArrayImpl::pos()
+{
+ return currentPosition;
+}
+
QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb)
: QNonContiguousByteDevice(), currentPosition(0)
{
@@ -273,6 +278,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
return currentPosition >= size();
}
+qint64 QNonContiguousByteDeviceRingBufferImpl::pos()
+{
+ return currentPosition;
+}
+
bool QNonContiguousByteDeviceRingBufferImpl::reset()
{
if (resetDisabled)
@@ -406,6 +416,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
return device->size() - initialPosition;
}
+qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()
+{
+ if (device->isSequential())
+ return -1;
+
+ return device->pos();
+}
+
QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
{
byteDevice = bd;
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
index c05ae11..4d7b7b0 100644
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -61,6 +61,7 @@ public:
virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
virtual bool advanceReadPointer(qint64 amount) = 0;
virtual bool atEnd() = 0;
+ virtual qint64 pos() { return -1; }
virtual bool reset() = 0;
void disableReset();
bool isResetDisabled() { return resetDisabled; }
@@ -106,6 +107,7 @@ public:
bool atEnd();
bool reset();
qint64 size();
+ qint64 pos() Q_DECL_OVERRIDE;
protected:
QByteArray* byteArray;
qint64 currentPosition;
@@ -121,6 +123,7 @@ public:
bool atEnd();
bool reset();
qint64 size();
+ qint64 pos() Q_DECL_OVERRIDE;
protected:
QSharedPointer<QRingBuffer> ringBuffer;
qint64 currentPosition;
@@ -138,6 +141,7 @@ public:
bool atEnd();
bool reset();
qint64 size();
+ qint64 pos() Q_DECL_OVERRIDE;
protected:
QIODevice* device;
QByteArray* currentReadBuffer;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 9f63280..49c6793 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy);
#endif
+ // We want all signals (except the interactive ones) be connected as QueuedConnection
+ // because else we're falling into cases where we recurse back into the socket code
+ // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
+ // is safer.
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
- Qt::DirectConnection);
+ Qt::QueuedConnection);
QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()),
- Qt::DirectConnection);
+ Qt::QueuedConnection);
QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()),
- Qt::DirectConnection);
+ Qt::QueuedConnection);
// The disconnected() and error() signals may already come
// while calling connectToHost().
@@ -143,13 +147,13 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()),
- Qt::DirectConnection);
+ Qt::QueuedConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)),
- Qt::DirectConnection);
+ Qt::QueuedConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
@@ -186,8 +190,11 @@ void QHttpNetworkConnectionChannel::close()
// pendingEncrypt must only be true in between connected and encrypted states
pendingEncrypt = false;
- if (socket)
+ if (socket) {
+ // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
+ // there is no socket yet.
socket->close();
+ }
}
@@ -353,6 +360,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
}
return false;
}
+
+ // This code path for ConnectedState
+ if (pendingEncrypt) {
+ // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up
+ // and corrupt the things sent to the server.
+ return false;
+ }
+
return true;
}
@@ -659,6 +674,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
{
Q_UNUSED(bytes);
+ if (ssl) {
+ // In the SSL case we want to send data from encryptedBytesWritten signal since that one
+ // is the one going down to the actual network, not only into some SSL buffer.
+ return;
+ }
+
// bytes have been written to the socket. write even more of them :)
if (isSocketWriting())
sendRequest();
@@ -734,7 +755,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
// ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
//channels[i].reconnectAttempts = 2;
- if (pendingEncrypt) {
+ if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
#ifndef QT_NO_SSL
if (connection->sslContext().isNull()) {
// this socket is making the 1st handshake for this connection,
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 692c0e6..231fe11 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
class QHttpNetworkConnectionChannel : public QObject {
Q_OBJECT
public:
+ // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt).
+ // Also add an Unconnected state so IdleState does not have double meaning.
enum ChannelState {
IdleState = 0, // ready to send request
ConnectingState = 1, // connecting to host
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 28e10f7..3357948 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest()
// nothing to read currently, break the loop
break;
} else {
+ if (m_channel->written != uploadByteDevice->pos()) {
+ // Sanity check. This was useful in tracking down an upload corruption.
+ qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos();
+ Q_ASSERT(m_channel->written == uploadByteDevice->pos());
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
+ return false;
+ }
qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
// socket broke down
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 1661082..b553409 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -187,6 +187,7 @@ protected:
QByteArray m_dataArray;
bool m_atEnd;
qint64 m_size;
+ qint64 m_pos; // to match calls of haveDataSlot with the expected position
public:
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
: QNonContiguousByteDevice(),
@@ -194,7 +195,8 @@ public:
m_amount(0),
m_data(0),
m_atEnd(aE),
- m_size(s)
+ m_size(s),
+ m_pos(0)
{
}
@@ -202,6 +204,11 @@ public:
{
}
+ qint64 pos() Q_DECL_OVERRIDE
+ {
+ return m_pos;
+ }
+
const char* readPointer(qint64 maximumLength, qint64 &len)
{
if (m_amount > 0) {
@@ -229,11 +236,10 @@ public:
m_amount -= a;
m_data += a;
+ m_pos += a;
- // To main thread to inform about our state
- emit processedData(a);
-
- // FIXME possible optimization, already ask user thread for some data
+ // To main thread to inform about our state. The m_pos will be sent as a sanity check.
+ emit processedData(m_pos, a);
return true;
}
@@ -250,10 +256,21 @@ public:
{
m_amount = 0;
m_data = 0;
+ m_dataArray.clear();
+
+ if (wantDataPending) {
+ // had requested the user thread to send some data (only 1 in-flight at any moment)
+ wantDataPending = false;
+ }
// Communicate as BlockingQueuedConnection
bool b = false;
emit resetData(&b);
+ if (b) {
+ // the reset succeeded, we're at pos 0 again
+ m_pos = 0;
+ // the HTTP code will anyway abort the request if !b.
+ }
return b;
}
@@ -264,8 +281,13 @@ public:
public slots:
// From user thread:
- void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
+ void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
{
+ if (pos != m_pos) {
+ // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
+ // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
+ return;
+ }
wantDataPending = false;
m_dataArray = dataArray;
@@ -285,7 +307,7 @@ signals:
// to main thread:
void wantData(qint64);
- void processedData(qint64);
+ void processedData(qint64 pos, qint64 amount);
void resetData(bool *b);
};
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 4ce7303..974a101 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
, synchronous(false)
, state(Idle)
, statusCode(0)
+ , uploadByteDevicePosition(false)
, uploadDeviceChoking(false)
, outgoingData(0)
, bytesUploaded(-1)
@@ -863,9 +864,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
q, SLOT(uploadByteDeviceReadyReadSlot()),
Qt::QueuedConnection);
- // From main thread to user thread:
- QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)),
- forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection);
+ // From user thread to http thread:
+ QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
+ forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
forwardUploadDevice, SIGNAL(readyRead()),
Qt::QueuedConnection);
@@ -873,8 +874,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
// From http thread to user thread:
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
q, SLOT(wantUploadDataSlot(qint64)));
- QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
- q, SLOT(sentUploadDataSlot(qint64)));
+ QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
+ q, SLOT(sentUploadDataSlot(qint64,qint64)));
QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
q, SLOT(resetUploadDataSlot(bool*)),
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
@@ -1268,12 +1269,22 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig
void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
{
*r = uploadByteDevice->reset();
+ if (*r) {
+ // reset our own position which is used for the inter-thread communication
+ uploadByteDevicePosition = 0;
+ }
}
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
-void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount)
+void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount)
{
+ if (uploadByteDevicePosition + amount != pos) {
+ // Sanity check, should not happen.
+ error(QNetworkReply::UnknownNetworkError, "");
+ return;
+ }
uploadByteDevice->advanceReadPointer(amount);
+ uploadByteDevicePosition += amount;
}
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
@@ -1298,7 +1309,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
QByteArray dataArray(data, currentUploadDataLength);
// Communicate back to HTTP thread
- emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
+ emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
}
void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot()
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 77d9c5a..1940922 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -120,7 +120,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64))
- Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64))
+ Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64))
Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot())
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
@@ -144,7 +144,7 @@ signals:
void startHttpRequestSynchronously();
- void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
+ void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
};
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
@@ -195,6 +195,7 @@ public:
// upload
QNonContiguousByteDevice* createUploadByteDevice();
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+ qint64 uploadByteDevicePosition;
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
QIODevice *outgoingData;
QSharedPointer<QRingBuffer> outgoingDataBuffer;
@@ -283,7 +284,7 @@ public:
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
void resetUploadDataSlot(bool *r);
void wantUploadDataSlot(qint64);
- void sentUploadDataSlot(qint64);
+ void sentUploadDataSlot(qint64, qint64);
// From user's QNonContiguousByteDevice
void uploadByteDeviceReadyReadSlot();
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index 3ccedf6..d2edf67 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -457,6 +457,10 @@ private Q_SLOTS:
void putWithRateLimiting();
+#ifndef QT_NO_SSL
+ void putWithServerClosingConnectionImmediately();
+#endif
+
// NOTE: This test must be last!
void parentingRepliesToTheApp();
private:
@@ -4718,18 +4722,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
class SslServer : public QTcpServer {
Q_OBJECT
public:
- SslServer() : socket(0) {};
+ SslServer() : socket(0), m_ssl(true) {}
void incomingConnection(qintptr socketDescriptor) {
QSslSocket *serverSocket = new QSslSocket;
serverSocket->setParent(this);
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
+ connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
+ if (!m_ssl) {
+ emit newPlainConnection(serverSocket);
+ return;
+ }
QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
if (testDataDir.isEmpty())
testDataDir = QCoreApplication::applicationDirPath();
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
- connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
serverSocket->setProtocol(QSsl::AnyProtocol);
connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
@@ -4740,11 +4748,12 @@ public:
}
}
signals:
- void newEncryptedConnection();
+ void newEncryptedConnection(QSslSocket *s);
+ void newPlainConnection(QSslSocket *s);
public slots:
void encryptedSlot() {
socket = (QSslSocket*) sender();
- emit newEncryptedConnection();
+ emit newEncryptedConnection(socket);
}
void readyReadSlot() {
// for the incoming sockets, not the server socket
@@ -4753,6 +4762,7 @@ public slots:
public:
QSslSocket *socket;
+ bool m_ssl;
};
// very similar to ioPostToHttpUploadProgress but for SSL
@@ -4780,7 +4790,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QNetworkReplyPtr reply(manager.post(request, sourceFile));
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
- connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors()));
// get the request started and the incoming socket connected
@@ -4788,7 +4798,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
QVERIFY(!QTestEventLoop::instance().timeout());
QTcpSocket *incomingSocket = server.socket;
QVERIFY(incomingSocket);
- disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
incomingSocket->setReadBufferSize(1*1024);
@@ -7905,6 +7915,159 @@ void tst_QNetworkReply::putWithRateLimiting()
}
+#ifndef QT_NO_SSL
+
+class PutWithServerClosingConnectionImmediatelyHandler: public QObject
+{
+ Q_OBJECT
+public:
+ bool m_parsedHeaders;
+ QByteArray m_receivedData;
+ QByteArray m_expectedData;
+ QSslSocket *m_socket;
+ PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s)
+ {
+ m_socket->setParent(this);
+ connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot()));
+ connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot()));
+ }
+signals:
+ void correctFileUploadReceived();
+ void corruptFileUploadReceived();
+
+public slots:
+ void closeDelayed() {
+ m_socket->close();
+ }
+
+ void readyReadSlot()
+ {
+ QByteArray data = m_socket->readAll();
+ m_receivedData += data;
+ if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
+ m_parsedHeaders = true;
+ QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
+ // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
+ // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
+ // This test catches that.
+ }
+
+ }
+ void disconnectedSlot()
+ {
+ if (m_parsedHeaders) {
+ //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n"));
+ m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data
+ }
+ if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) {
+ // We had received some data but it is corrupt!
+ qDebug() << "CORRUPT" << m_receivedData.count();
+
+ // Use this to track down the pattern of the corruption and conclude the source
+// QFile a("/tmp/corrupt");
+// a.open(QIODevice::WriteOnly);
+// a.write(m_receivedData);
+// a.close();
+
+// QFile b("/tmp/correct");
+// b.open(QIODevice::WriteOnly);
+// b.write(m_expectedData);
+// b.close();
+ //exit(1);
+ emit corruptFileUploadReceived();
+ } else {
+ emit correctFileUploadReceived();
+ }
+ }
+};
+
+class PutWithServerClosingConnectionImmediatelyServer: public SslServer
+{
+ Q_OBJECT
+public:
+ int m_correctUploads;
+ int m_corruptUploads;
+ int m_repliesFinished;
+ int m_expectedReplies;
+ QByteArray m_expectedData;
+ PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0)
+ {
+ QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
+ QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
+ }
+
+public slots:
+ void createHandlerForConnection(QSslSocket* s) {
+ PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData);
+ handler->setParent(this);
+ QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect()));
+ QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt()));
+ }
+ void increaseCorrect() {
+ m_correctUploads++;
+ }
+ void increaseCorrupt() {
+ m_corruptUploads++;
+ }
+ void replyFinished() {
+ m_repliesFinished++;
+ if (m_repliesFinished == m_expectedReplies) {
+ QTestEventLoop::instance().exitLoop();
+ }
+ }
+};
+
+
+
+void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
+{
+ const int numUploads = 40;
+ qint64 wantedSize = 512*1024; // 512 kB
+ QByteArray sourceFile;
+ for (int i = 0; i < wantedSize; ++i) {
+ sourceFile += (char)'a' +(i%26);
+ }
+ bool withSsl = false;
+
+ for (int s = 0; s <= 1; s++) {
+ withSsl = (s == 1);
+ // Test also needs to run several times because of 9c2ecf89
+ for (int j = 0; j < 20; j++) {
+ // emulate a minimal https server
+ PutWithServerClosingConnectionImmediatelyServer server;
+ server.m_ssl = withSsl;
+ server.m_expectedData = sourceFile;
+ server.m_expectedReplies = numUploads;
+ server.listen(QHostAddress(QHostAddress::LocalHost), 0);
+
+ for (int i = 0; i < numUploads; i++) {
+ // create the request
+ QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i));
+ QNetworkRequest request(url);
+ QNetworkReply *reply = manager.put(request, sourceFile);
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
+ connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished()));
+ reply->setParent(&server);
+ }
+
+ // get the request started and the incoming socket connected
+ QTestEventLoop::instance().enterLoop(10);
+
+ //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
+
+ // Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
+ QVERIFY(server.m_correctUploads > 5);
+ // Because actually important is that we don't get any corruption:
+ QCOMPARE(server.m_corruptUploads, 0);
+
+ server.close();
+ }
+ }
+
+
+}
+
+#endif
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
--
1.9.1
@@ -1,434 +0,0 @@
From eae0cb09f1310e755c2aff7c1112f7a6c09d7a53 Mon Sep 17 00:00:00 2001
From: Markus Goetz <markus@woboq.com>
Date: Fri, 19 Jun 2015 15:35:34 +0200
Subject: [PATCH] Network: Fix up previous corruption patch
This is a fix-up for cff39fba10ffc10ee4dcfdc66ff6528eb26462d3.
That patch lead to some internal state issues that lead to the QTBUG-47048
or to QNetworkReply objects erroring with "Connection Closed" when
the server closed the Keep-Alive connection.
This patch changes the QNAM socket slot connections to be DirectConnection.
We don't close the socket anymore in slots where it is anyway in a closed state
afterwards. This prevents event/stack recursions.
We also flush QSslSocket/QTcpSocket receive buffers when receiving a disconnect
so that the developer always gets the full decrypted data from the buffers.
[ChangeLog][QtNetwork] Fix HTTP issues with "Unknown Error" and "Connection Closed"
[ChangeLog][QtNetwork][Sockets] Read OS/encrypted read buffers when connection
closed by server.
Change-Id: Ib4d6a2d0d988317e3a5356f36e8dbcee4590beed
Task-number: QTBUG-47048
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
Reviewed-by: Richard J. Moore <rich@kde.org>
---
src/network/access/qhttpnetworkconnection.cpp | 1 -
.../access/qhttpnetworkconnectionchannel.cpp | 108 +++++++++++++--------
.../access/qhttpnetworkconnectionchannel_p.h | 1 +
src/network/access/qhttpnetworkreply.cpp | 2 +-
src/network/access/qhttpprotocolhandler.cpp | 1 -
src/network/socket/qabstractsocket.cpp | 7 +-
src/network/ssl/qsslsocket.cpp | 8 ++
src/network/ssl/qsslsocket_openssl.cpp | 7 ++
.../access/qnetworkreply/tst_qnetworkreply.cpp | 9 +-
9 files changed, 94 insertions(+), 50 deletions(-)
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 365ce55..543c70e 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -917,7 +917,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
for (int i = 0; i < channelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
channels[i].resendCurrent = false;
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
// if this is not possible, error will be emitted and connection terminated
if (!channels[i].resetUploadData())
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 49c6793..e2f6307 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
+// connection times out)
+// We use 3 because we can get a _q_error 3 times depending on the timing:
+static const int reconnectAttemptsDefault = 3;
+
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
: socket(0)
, ssl(false)
@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
, resendCurrent(false)
, lastStatus(0)
, pendingEncrypt(false)
- , reconnectAttempts(2)
+ , reconnectAttempts(reconnectAttemptsDefault)
, authMethod(QAuthenticatorPrivate::None)
, proxyAuthMethod(QAuthenticatorPrivate::None)
, authenticationCredentialsSent(false)
@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
socket->setProxy(QNetworkProxy::NoProxy);
#endif
- // We want all signals (except the interactive ones) be connected as QueuedConnection
- // because else we're falling into cases where we recurse back into the socket code
- // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
- // is safer.
+ // After some back and forth in all the last years, this is now a DirectConnection because otherwise
+ // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
+ // which behave slightly differently on Windows vs Linux
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
this, SLOT(_q_bytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(connected()),
this, SLOT(_q_connected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(readyRead()),
this, SLOT(_q_readyRead()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
// The disconnected() and error() signals may already come
// while calling connectToHost().
@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
qRegisterMetaType<QAbstractSocket::SocketError>();
QObject::connect(socket, SIGNAL(disconnected()),
this, SLOT(_q_disconnected()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
#ifndef QT_NO_NETWORKPROXY
@@ -147,13 +151,13 @@ void QHttpNetworkConnectionChannel::init()
// won't be a sslSocket if encrypt is false
QObject::connect(sslSocket, SIGNAL(encrypted()),
this, SLOT(_q_encrypted()),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(_q_sslErrors(QList<QSslError>)),
Qt::DirectConnection);
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
this, SLOT(_q_encryptedBytesWritten(qint64)),
- Qt::QueuedConnection);
+ Qt::DirectConnection);
if (ignoreAllSslErrors)
sslSocket->ignoreSslErrors();
@@ -397,7 +401,7 @@ void QHttpNetworkConnectionChannel::allDone()
// reset the reconnection attempts after we receive a complete reply.
// in case of failures, each channel will attempt two reconnects before emitting error.
- reconnectAttempts = 2;
+ reconnectAttempts = reconnectAttemptsDefault;
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
if (state != QHttpNetworkConnectionChannel::ClosingState)
@@ -651,6 +655,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
+void QHttpNetworkConnectionChannel::resendCurrentRequest()
+{
+ requeueCurrentlyPipelinedRequests();
+ if (reply)
+ resendCurrent = true;
+ if (qobject_cast<QHttpNetworkConnection*>(connection))
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+}
+
bool QHttpNetworkConnectionChannel::isSocketBusy() const
{
return (state & QHttpNetworkConnectionChannel::BusyState);
@@ -694,8 +707,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
return;
}
- // read the available data before closing
- if (isSocketWaiting() || isSocketReading()) {
+ // read the available data before closing (also done in _q_error for other codepaths)
+ if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
if (reply) {
state = QHttpNetworkConnectionChannel::ReadingState;
_q_receiveReply();
@@ -707,7 +720,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
state = QHttpNetworkConnectionChannel::IdleState;
requeueCurrentlyPipelinedRequests();
- close();
+
+ pendingEncrypt = false;
}
@@ -789,11 +803,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
errorCode = QNetworkReply::ConnectionRefusedError;
break;
case QAbstractSocket::RemoteHostClosedError:
- // try to reconnect/resend before sending an error.
- // while "Reading" the _q_disconnected() will handle this.
- if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
+ // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
+ // The reconnectAttempts handling catches the cases where we can re-send the request.
+ if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
+ // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
+ // is sent on them. No need to error the other replies below. Just bail out here.
+ // The _q_disconnected will handle the possibly pipelined replies
+ return;
+ } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ // Try to reconnect/resend before sending an error.
+ // While "Reading" the _q_disconnected() will handle this.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -818,24 +840,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// we can ignore the readbuffersize as the data is already
// in memory and we will not receive more data on the socket.
reply->setReadBufferSize(0);
+ reply->setDownstreamLimited(false);
_q_receiveReply();
-#ifndef QT_NO_SSL
- if (ssl) {
- // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
- // So we need to check this if the socket is a QSslSocket. When the socket is flushed
- // it will force a decrypt of the encrypted data in the plainsocket.
- QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
- qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
- while (sslSocket->encryptedBytesAvailable()) {
- sslSocket->flush();
- _q_receiveReply();
- qint64 afterFlush = sslSocket->encryptedBytesAvailable();
- if (afterFlush == beforeFlush)
- break;
- beforeFlush = afterFlush;
- }
+ if (!reply) {
+ // No more reply assigned after the previous call? Then it had been finished successfully.
+ requeueCurrentlyPipelinedRequests();
+ state = QHttpNetworkConnectionChannel::IdleState;
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
}
-#endif
}
errorCode = QNetworkReply::RemoteHostClosedError;
@@ -846,7 +859,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::SocketTimeoutError:
// try to reconnect/resend before sending an error.
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::TimeoutError;
@@ -860,7 +873,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionClosedError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyConnectionClosedError;
@@ -868,7 +881,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
case QAbstractSocket::ProxyConnectionTimeoutError:
// try to reconnect/resend before sending an error.
if (reconnectAttempts-- > 0) {
- closeAndResendCurrentRequest();
+ resendCurrentRequest();
return;
}
errorCode = QNetworkReply::ProxyTimeoutError;
@@ -916,8 +929,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
- if (that) //signal emission triggered event loop
- close();
+ if (that) {
+ //signal emission triggered event loop
+ if (!socket)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else if (socket->state() == QAbstractSocket::UnconnectedState)
+ state = QHttpNetworkConnectionChannel::IdleState;
+ else
+ state = QHttpNetworkConnectionChannel::ClosingState;
+
+ // pendingEncrypt must only be true in between connected and encrypted states
+ pendingEncrypt = false;
+ }
}
#ifndef QT_NO_NETWORKPROXY
@@ -941,7 +964,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
{
- sendRequest();
+ if (reply)
+ sendRequest();
}
#ifndef QT_NO_SSL
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 231fe11..a834b7d 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -169,6 +169,7 @@ public:
void handleUnexpectedEOF();
void closeAndResendCurrentRequest();
+ void resendCurrentRequest();
bool isSocketBusy() const;
bool isSocketWriting() const;
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 55863a3..8b71bd8 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny()
return QByteArray();
// we'll take the last buffer, so schedule another read from http
- if (d->downstreamLimited && d->responseData.bufferCount() == 1)
+ if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
d->connection->d_func()->readMoreLater(this);
return d->responseData.read();
}
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index 3357948..380aaac 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest()
if (!m_reply) {
// heh, how should that happen!
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
- m_channel->state = QHttpNetworkConnectionChannel::IdleState;
return false;
}
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 2666771..0e82d4a 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -768,6 +768,7 @@ bool QAbstractSocketPrivate::canReadNotification()
void QAbstractSocketPrivate::canCloseNotification()
{
Q_Q(QAbstractSocket);
+ // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canCloseNotification()");
@@ -777,7 +778,11 @@ void QAbstractSocketPrivate::canCloseNotification()
if (isBuffered) {
// Try to read to the buffer, if the read fail we can close the socket.
newBytes = buffer.size();
- if (!readFromSocket()) {
+ qint64 oldReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
+ bool hadReadFromSocket = readFromSocket();
+ readBufferMaxSize = oldReadBufferMaxSize;
+ if (!hadReadFromSocket) {
q->disconnectFromHost();
return;
}
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index c1fab94..2b9e923 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2294,6 +2294,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
qCDebug(lcSsl) << "\tstate =" << q->state();
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
#endif
+ // this moves encrypted bytes from plain socket into our buffer
+ if (plainSocket->bytesAvailable()) {
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
+
q->setSocketError(plainSocket->error());
q->setErrorString(plainSocket->errorString());
emit q->error(error);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index ac4336a..94655fe 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1419,6 +1419,13 @@ void QSslSocketBackendPrivate::disconnected()
{
if (plainSocket->bytesAvailable() <= 0)
destroySslContext();
+ else {
+ // Move all bytes into the plain buffer
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
+ readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
+ transmit();
+ readBufferMaxSize = tmpReadBufferMaxSize;
+ }
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
//it will be destroyed when the socket is deleted.
}
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index d2edf67..138f528 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -1051,7 +1051,7 @@ protected:
// clean up QAbstractSocket's residue:
while (client->bytesToWrite() > 0) {
qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
- if (!client->waitForBytesWritten(2000)) {
+ if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
return;
}
@@ -1071,7 +1071,7 @@ protected:
measuredSentBytes += writeNextData(client, bytesToWrite);
while (client->bytesToWrite() > 0) {
- if (!client->waitForBytesWritten(2000)) {
+ if (!client->waitForBytesWritten(10000)) {
qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
return;
}
@@ -7946,7 +7946,7 @@ public slots:
m_receivedData += data;
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
m_parsedHeaders = true;
- QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
+ QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
// This test catches that.
@@ -8052,11 +8052,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
// get the request started and the incoming socket connected
QTestEventLoop::instance().enterLoop(10);
+ QVERIFY(!QTestEventLoop::instance().timeout());
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
- QVERIFY(server.m_correctUploads > 5);
+ QVERIFY(server.m_correctUploads > 2);
// Because actually important is that we don't get any corruption:
QCOMPARE(server.m_corruptUploads, 0);
--
1.9.1
@@ -1,64 +0,0 @@
From bc32c0ebc0bc00db84ca2f28eb16ab2e5b53a1b6 Mon Sep 17 00:00:00 2001
From: Markus Goetz <markus@woboq.com>
Date: Fri, 24 Jul 2015 09:53:20 +0200
Subject: [PATCH] QNAM: Fix reply deadlocks on server closing connection
The _q_readyRead can also be called from readMoreLater() because we implemented
it so that bandwidth limited reading can be implemented.
This can lead to a race condition if the socket is closing at the specific moment
and then deadlock the channel: It will stay unusable with a zombie request.
The fix in QHttpProtocolaHandler checks if there is actually bytes available to read
from the socket and only then continue.
The fix in the HTTP channel needs to be done to properly finish the reply in
cases of a server replying with HTTP/1.0 or "Connection: close".
The delayed incovation of _q_receiveReply will properly finish up the reply.
Change-Id: I19ce2ae595f91d56386cc7406ccacc9935672b6b
Reviewed-by: Richard J. Moore <rich@kde.org>
---
src/network/access/qhttpnetworkconnectionchannel.cpp | 4 ++++
src/network/access/qhttpprotocolhandler.cpp | 7 ++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 7428f9b..257aa13 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -829,11 +829,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (!reply->d_func()->expectContent()) {
// No content expected, this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
// There was no content-length header and it's not chunked encoding,
// so this is a valid way to have the connection closed by the server
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
return;
}
// ok, we got a disconnect even though we did not expect it
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index ab2e3da..a208315 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
}
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ if (m_socket->bytesAvailable()) {
+ // We might get a spurious call from readMoreLater()
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
+ // Therefore check if there is actually bytes available before changing the channel state.
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
+ }
if (m_reply)
_q_receiveReply();
}
--
1.9.1
@@ -1,33 +0,0 @@
From 63cf5d3d26a6f65938c3cdec1734eac9faaaf8cb Mon Sep 17 00:00:00 2001
From: Markus Goetz <markus@woboq.com>
Date: Tue, 22 Sep 2015 14:26:24 -0400
Subject: [PATCH] QNAM: Assign proper channel before sslErrors() emission
There can be a race condition where another channel connects
and gets the sslErrors() from the socket first. Then the
QSslConfiguration from the wrong socket (the default
channel 0's socket) was used.
Task-number: QTBUG-18722
Change-Id: Ibbfa48c27f181563745daf540fa792a57cc09682
Reviewed-by: Richard J. Moore <rich@kde.org>
---
src/network/access/qhttpnetworkconnectionchannel.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 257aa13..477cba2 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -1066,6 +1066,8 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
connection->d_func()->pauseConnection();
if (pendingEncrypt && !reply)
connection->d_func()->dequeueRequest(socket);
+ if (reply) // a reply was actually dequeued.
+ reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest();
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
if (reply)
emit reply->sslErrors(errors);
--
1.9.1
@@ -1,121 +0,0 @@
From 0df5d079290b4c3b13e58e9397fabdc1dfdba96b Mon Sep 17 00:00:00 2001
From: Ulf Hermann <ulf.hermann@theqtcompany.com>
Date: Fri, 25 Sep 2015 13:23:46 +0200
Subject: [PATCH] Don't let closed http sockets pass as valid connections
A QAbstractSocket can be close()'d at any time, independently of its
current connection state. being closed means that we cannot use it to
read or write data, but internally it might still have some data to
send or receive, for example to an http server. We can even get a
connected() signal after close()'ing the socket.
We need to catch this condition and mark any pending data not yet
written to the socket for resending.
Task-number: QTBUG-48326
Change-Id: I6f61c35f2c567f2a138f8cfe9ade7fd1ec039be6
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
---
.../access/qhttpnetworkconnectionchannel.cpp | 7 ++-
.../tst_qhttpnetworkconnection.cpp | 54 ++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 293909c..b4eda34 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -272,7 +272,12 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
QAbstractSocket::SocketState socketState = socket->state();
// resend this request after we receive the disconnected signal
- if (socketState == QAbstractSocket::ClosingState) {
+ // If !socket->isOpen() then we have already called close() on the socket, but there was still a
+ // pending connectToHost() for which we hadn't seen a connected() signal, yet. The connected()
+ // has now arrived (as indicated by socketState != ClosingState), but we cannot send anything on
+ // such a socket anymore.
+ if (socketState == QAbstractSocket::ClosingState ||
+ (socketState != QAbstractSocket::UnconnectedState && !socket->isOpen())) {
if (reply)
resendCurrent = true;
return false;
diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
index 5d072af..0d188a8 100644
--- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
+++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
@@ -36,6 +36,7 @@
#include "private/qhttpnetworkconnection_p.h"
#include "private/qnoncontiguousbytedevice_p.h"
#include <QAuthenticator>
+#include <QTcpServer>
#include "../../../network-settings.h"
@@ -106,6 +107,8 @@ private Q_SLOTS:
void getAndThenDeleteObject();
void getAndThenDeleteObject_data();
+
+ void overlappingCloseAndWrite();
};
tst_QHttpNetworkConnection::tst_QHttpNetworkConnection()
@@ -1112,6 +1115,57 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject()
}
}
+class TestTcpServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ TestTcpServer() : errorCodeReports(0)
+ {
+ connect(this, &QTcpServer::newConnection, this, &TestTcpServer::onNewConnection);
+ QVERIFY(listen(QHostAddress::LocalHost));
+ }
+
+ int errorCodeReports;
+
+public slots:
+ void onNewConnection()
+ {
+ QTcpSocket *socket = nextPendingConnection();
+ if (!socket)
+ return;
+ // close socket instantly!
+ connect(socket, &QTcpSocket::readyRead, socket, &QTcpSocket::close);
+ }
+
+ void onReply(QNetworkReply::NetworkError code)
+ {
+ QCOMPARE(code, QNetworkReply::RemoteHostClosedError);
+ ++errorCodeReports;
+ }
+};
+
+void tst_QHttpNetworkConnection::overlappingCloseAndWrite()
+{
+ // server accepts connections, but closes the socket instantly
+ TestTcpServer server;
+ QNetworkAccessManager accessManager;
+
+ // ten requests are scheduled. All should result in an RemoteHostClosed...
+ QUrl url;
+ url.setScheme(QStringLiteral("http"));
+ url.setHost(server.serverAddress().toString());
+ url.setPort(server.serverPort());
+ for (int i = 0; i < 10; ++i) {
+ QNetworkRequest request(url);
+ QNetworkReply *reply = accessManager.get(request);
+ // Not using Qt5 connection syntax here because of overly baroque syntax to discern between
+ // different error() methods.
+ QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ &server, SLOT(onReply(QNetworkReply::NetworkError)));
+ }
+
+ QTRY_COMPARE(server.errorCodeReports, 10);
+}
QTEST_MAIN(tst_QHttpNetworkConnection)
--
1.9.1
@@ -1,113 +0,0 @@
From c056e63cea1915667997c982f48296ce5acdcc80 Mon Sep 17 00:00:00 2001
From: Lorn Potter <lorn.potter@gmail.com>
Date: Tue, 2 Jun 2015 13:22:23 +1000
Subject: [PATCH] Make sure to report correct NetworkAccessibility
Task-number: QTBUG-46323
Change-Id: Ibdeb3280091a97d785d4314340678a63e88fb219
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
---
src/network/access/qnetworkaccessmanager.cpp | 25 +++++++++++++++++--------
src/network/access/qnetworkaccessmanager_p.h | 2 ++
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index e878feb..84931cb 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -472,11 +472,11 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
// the QNetworkSession's signals
connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
SLOT(_q_onlineStateChanged(bool)));
- // we would need all active configurations to check for
- // d->networkConfigurationManager.isOnline(), which is asynchronous
- // and potentially expensive. We can just check the configuration here
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
}
+ // we would need all active configurations to check for
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
+ // and potentially expensive. We can just check the configuration here
+ d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
#endif
}
@@ -946,6 +946,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
{
Q_D(QNetworkAccessManager);
+ d->defaultAccessControl = false;
if (d->networkAccessible != accessible) {
NetworkAccessibility previous = networkAccessible();
@@ -964,7 +965,6 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
{
Q_D(const QNetworkAccessManager);
-
if (d->networkSessionRequired) {
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
if (networkSession) {
@@ -975,7 +975,13 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
return NotAccessible;
} else {
// Network accessibility is either disabled or unknown.
- return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
+ if (d->defaultAccessControl) {
+ if (d->online)
+ return d->networkAccessible;
+ else
+ return NotAccessible;
+ }
+ return (d->networkAccessible);
}
} else {
if (d->online)
@@ -1568,7 +1574,7 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
if (!networkSessionStrongRef) {
online = false;
- if (networkAccessible == QNetworkAccessManager::NotAccessible)
+ if (networkAccessible == QNetworkAccessManager::NotAccessible || !online)
emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
else
emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
@@ -1616,11 +1622,14 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
if (online) {
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
online = false;
- emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
+ networkAccessible = QNetworkAccessManager::NotAccessible;
+ emit q->networkAccessibleChanged(networkAccessible);
}
} else {
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
online = true;
+ if (defaultAccessControl)
+ networkAccessible = QNetworkAccessManager::Accessible;
emit q->networkAccessibleChanged(networkAccessible);
}
}
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index f513324..c715da0 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -84,6 +84,7 @@ public:
initializeSession(true),
#endif
cookieJarCreated(false),
+ defaultAccessControl(true),
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
{ }
~QNetworkAccessManagerPrivate();
@@ -164,6 +165,7 @@ public:
#endif
bool cookieJarCreated;
+ bool defaultAccessControl;
// The cache with authorization data:
QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
--
1.9.1
@@ -1,233 +0,0 @@
From bb281eea179d50a413f4ec1ff172d27ee48d3a41 Mon Sep 17 00:00:00 2001
From: Lorn Potter <lorn.potter@gmail.com>
Date: Fri, 17 Jul 2015 15:32:23 +1000
Subject: [PATCH] Make sure networkAccessibilityChanged is emitted
Task-number: QTBUG-46323
Change-Id: I8297072b62763136f457ca6ae15282d1c22244f4
Reviewed-by: Timo Jyrinki <timo.jyrinki@canonical.com>
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
---
src/network/access/qnetworkaccessmanager.cpp | 70 +++++++++++++++-------
src/network/access/qnetworkaccessmanager_p.h | 14 ++++-
.../tst_qnetworkaccessmanager.cpp | 31 +++++-----
3 files changed, 77 insertions(+), 38 deletions(-)
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 84931cb..f9e9513 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -278,7 +278,8 @@ static void ensureInitialized()
\snippet code/src_network_access_qnetworkaccessmanager.cpp 4
- Network requests can be reenabled again by calling
+ Network requests can be re-enabled again, and this property will resume to
+ reflect the actual device state by calling
\snippet code/src_network_access_qnetworkaccessmanager.cpp 5
@@ -467,16 +468,12 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
qRegisterMetaType<QSharedPointer<char> >();
#ifndef QT_NO_BEARERMANAGEMENT
- if (!d->networkSessionRequired) {
- // if a session is required, we track online state through
- // the QNetworkSession's signals
- connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
- SLOT(_q_onlineStateChanged(bool)));
- }
- // we would need all active configurations to check for
- // d->networkConfigurationManager.isOnline(), which is asynchronous
- // and potentially expensive. We can just check the configuration here
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
+ // if a session is required, we track online state through
+ // the QNetworkSession's signals if a request is already made.
+ // we need to track current accessibility state by default
+ //
+ connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
+ SLOT(_q_onlineStateChanged(bool)));
#endif
}
@@ -946,7 +943,8 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
{
Q_D(QNetworkAccessManager);
- d->defaultAccessControl = false;
+
+ d->defaultAccessControl = accessible == NotAccessible ? false : true;
if (d->networkAccessible != accessible) {
NetworkAccessibility previous = networkAccessible();
@@ -965,6 +963,10 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
{
Q_D(const QNetworkAccessManager);
+
+ if (d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
+ return UnknownAccessibility;
+
if (d->networkSessionRequired) {
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
if (networkSession) {
@@ -1622,32 +1624,56 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
if (online) {
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
online = false;
- networkAccessible = QNetworkAccessManager::NotAccessible;
- emit q->networkAccessibleChanged(networkAccessible);
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
+ networkAccessible = QNetworkAccessManager::NotAccessible;
+ emit q->networkAccessibleChanged(networkAccessible);
+ }
}
} else {
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
online = true;
if (defaultAccessControl)
- networkAccessible = QNetworkAccessManager::Accessible;
- emit q->networkAccessibleChanged(networkAccessible);
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
+ networkAccessible = QNetworkAccessManager::Accessible;
+ emit q->networkAccessibleChanged(networkAccessible);
+ }
}
}
}
void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
{
- // if the user set a config, we only care whether this one is active.
+ Q_Q(QNetworkAccessManager);
+ // if the user set a config, we only care whether this one is active.
// Otherwise, this QNAM is online if there is an online config.
if (customNetworkConfiguration) {
online = (networkConfiguration.state() & QNetworkConfiguration::Active);
} else {
- if (isOnline && online != isOnline) {
- networkSessionStrongRef.clear();
- networkSessionWeakRef.clear();
+ if (online != isOnline) {
+ if (isOnline) {
+ networkSessionStrongRef.clear();
+ networkSessionWeakRef.clear();
+ }
+ online = isOnline;
+ }
+ }
+ if (online) {
+ if (defaultAccessControl) {
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
+ networkAccessible = QNetworkAccessManager::Accessible;
+ emit q->networkAccessibleChanged(networkAccessible);
+ }
+ }
+ } else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) {
+ if (networkAccessible != QNetworkAccessManager::UnknownAccessibility) {
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
+ emit q->networkAccessibleChanged(networkAccessible);
+ }
+ } else {
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
+ networkAccessible = QNetworkAccessManager::NotAccessible;
+ emit q->networkAccessibleChanged(networkAccessible);
}
-
- online = isOnline;
}
}
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index c715da0..54ae114 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -78,7 +78,6 @@ public:
customNetworkConfiguration(false),
networkSessionRequired(networkConfigurationManager.capabilities()
& QNetworkConfigurationManager::NetworkSessionRequired),
- networkAccessible(QNetworkAccessManager::Accessible),
activeReplyCount(0),
online(false),
initializeSession(true),
@@ -86,7 +85,18 @@ public:
cookieJarCreated(false),
defaultAccessControl(true),
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
- { }
+ {
+#ifndef QT_NO_BEARERMANAGEMENT
+ // we would need all active configurations to check for
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
+ // and potentially expensive. We can just check the configuration here
+ online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
+ if (online)
+ networkAccessible = QNetworkAccessManager::Accessible;
+ else
+ networkAccessible = QNetworkAccessManager::NotAccessible;
+#endif
+ }
~QNetworkAccessManagerPrivate();
void _q_replyFinished();
diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
index b4e4b9c..8ecb57d 100644
--- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
+++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
@@ -74,6 +74,10 @@ void tst_QNetworkAccessManager::networkAccessible()
// if there is no session, we cannot know in which state we are in
QNetworkAccessManager::NetworkAccessibility initialAccessibility =
manager.networkAccessible();
+
+ if (initialAccessibility == QNetworkAccessManager::UnknownAccessibility)
+ QSKIP("Unknown accessibility", SkipAll);
+
QCOMPARE(manager.networkAccessible(), initialAccessibility);
manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
@@ -94,29 +98,28 @@ void tst_QNetworkAccessManager::networkAccessible()
QCOMPARE(manager.networkAccessible(), initialAccessibility);
QNetworkConfigurationManager configManager;
- bool sessionRequired = (configManager.capabilities()
- & QNetworkConfigurationManager::NetworkSessionRequired);
QNetworkConfiguration defaultConfig = configManager.defaultConfiguration();
if (defaultConfig.isValid()) {
manager.setConfiguration(defaultConfig);
- // the accessibility has not changed if no session is required
- if (sessionRequired) {
+ QCOMPARE(spy.count(), 0);
+
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active))
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
+ else
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
+
+ manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
+
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active)) {
QCOMPARE(spy.count(), 1);
- QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(),
- QNetworkAccessManager::Accessible);
+ QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
+ QNetworkAccessManager::NotAccessible);
} else {
QCOMPARE(spy.count(), 0);
}
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
-
- manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
-
- QCOMPARE(spy.count(), 1);
- QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
- QNetworkAccessManager::NotAccessible);
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
}
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
#endif
}
--
1.9.1
@@ -1,52 +0,0 @@
From e996d68f6130847637ba287518cff1289cfa48e5 Mon Sep 17 00:00:00 2001
From: Lorn Potter <lorn.potter@gmail.com>
Date: Fri, 6 Nov 2015 14:22:44 +1000
Subject: [PATCH] Make UnknownAccessibility not block requests
This allows requests to proceed without needing bearer plugins.
Task-number: QTBUG-49267
Change-Id: Ie5ce188ddefebd14d666bb5846e8f93ee2925ed1
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
---
src/network/access/qnetworkaccessmanager.cpp | 3 +--
src/network/access/qnetworkaccessmanager_p.h | 2 ++
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 086140f..0e5870a 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -976,7 +976,6 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
else
return NotAccessible;
} else {
- // Network accessibility is either disabled or unknown.
if (d->defaultAccessControl) {
if (d->online)
return d->networkAccessible;
@@ -1161,7 +1160,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
#ifndef QT_NO_BEARERMANAGEMENT
// Return a disabled network reply if network access is disabled.
// Except if the scheme is empty or file://.
- if (!d->networkAccessible && !isLocalFile) {
+ if (d->networkAccessible == NotAccessible && !isLocalFile) {
return new QDisabledNetworkReply(this, req, op);
}
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index 54ae114..3fc33b5 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -93,6 +93,8 @@ public:
online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
if (online)
networkAccessible = QNetworkAccessManager::Accessible;
+ else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
else
networkAccessible = QNetworkAccessManager::NotAccessible;
#endif
--
1.9.1
@@ -1,152 +0,0 @@
From ae9d3f4c6c1a732788cd1f24c6a928cee16c3991 Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Tue, 27 Jan 2015 16:58:32 +0100
Subject: [PATCH] Win32: Re-init system proxy if internet settings change
Because Proxy Auto Configuration performs DNS lookups,
the proxy settings are being cached. For long-running
programs this means that once users switch e.g. from or
to company networks with a proxy, they instantly will
lose connectivity because we cache the old setting.
To remedy this, we monitor the Registry (locations
courtesy of Chromium's platform support) for changes
in its settings, and requery for the current proxy in
that case.
Task-number: QTBUG-3470
Task-number: QTBUG-29990
Change-Id: Id25a51387bcd232c5f879cea0371038986d0e2de
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
---
src/network/kernel/qnetworkproxy_win.cpp | 86 +++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 2 deletions(-)
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
index da2c020..f7741ce 100644
--- a/src/network/kernel/qnetworkproxy_win.cpp
+++ b/src/network/kernel/qnetworkproxy_win.cpp
@@ -345,12 +345,66 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
return removeDuplicateProxies(result);
}
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+namespace {
+class QRegistryWatcher {
+public:
+ void addLocation(HKEY hive, const QString& path)
+ {
+ HKEY openedKey;
+ if (RegOpenKeyEx(hive, reinterpret_cast<const wchar_t*>(path.utf16()), 0, KEY_READ, &openedKey) != ERROR_SUCCESS)
+ return;
+
+ const DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
+ REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY;
+
+ // Watch the registry key for a change of value.
+ HANDLE handle = CreateEvent(NULL, true, false, NULL);
+ if (RegNotifyChangeKeyValue(openedKey, true, filter, handle, true) != ERROR_SUCCESS) {
+ CloseHandle(handle);
+ return;
+ }
+ m_watchEvents.append(handle);
+ m_registryHandles.append(openedKey);
+ }
+
+ bool hasChanged() const {
+ return !isEmpty() &&
+ WaitForMultipleObjects(m_watchEvents.size(), m_watchEvents.data(), false, 0) < WAIT_OBJECT_0 + m_watchEvents.size();
+ }
+
+ bool isEmpty() const {
+ return m_watchEvents.isEmpty();
+ }
+
+ void clear() {
+ foreach (HANDLE event, m_watchEvents)
+ CloseHandle(event);
+ foreach (HKEY key, m_registryHandles)
+ RegCloseKey(key);
+
+ m_watchEvents.clear();
+ m_registryHandles.clear();
+ }
+
+ ~QRegistryWatcher() {
+ clear();
+ }
+
+private:
+ QVector<HANDLE> m_watchEvents;
+ QVector<HKEY> m_registryHandles;
+};
+} // namespace
+#endif // !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+
class QWindowsSystemProxy
{
public:
QWindowsSystemProxy();
~QWindowsSystemProxy();
void init();
+ void reset();
QMutex mutex;
@@ -361,7 +415,9 @@ public:
QStringList proxyServerList;
QStringList proxyBypass;
QList<QNetworkProxy> defaultResult;
-
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ QRegistryWatcher proxySettingsWatcher;
+#endif
bool initialized;
bool functional;
bool isAutoConfig;
@@ -381,16 +437,42 @@ QWindowsSystemProxy::~QWindowsSystemProxy()
ptrWinHttpCloseHandle(hHttpSession);
}
+void QWindowsSystemProxy::reset()
+{
+ autoConfigUrl.clear();
+ proxyServerList.clear();
+ proxyBypass.clear();
+ defaultResult.clear();
+ defaultResult << QNetworkProxy::NoProxy;
+ functional = false;
+ isAutoConfig = false;
+}
+
void QWindowsSystemProxy::init()
{
- if (initialized)
+ bool proxySettingsChanged = false;
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ proxySettingsChanged = proxySettingsWatcher.hasChanged();
+#endif
+
+ if (initialized && !proxySettingsChanged)
return;
initialized = true;
+ reset();
+
#ifdef Q_OS_WINCE
// Windows CE does not have any of the following API
return;
#else
+
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ proxySettingsWatcher.clear(); // needs reset to trigger a new detection
+ proxySettingsWatcher.addLocation(HKEY_CURRENT_USER, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
+#endif
+
// load the winhttp.dll library
QSystemLibrary lib(L"winhttp");
if (!lib.load())
--
1.9.1
@@ -1,32 +0,0 @@
From c1a67e7dc3a6f8876efa32cdbabbfde1c5a37bc6 Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Tue, 31 Mar 2015 17:43:44 +0200
Subject: [PATCH] Windows: Do not crash if SSL context is gone after root cert
lookup
On Windows, we perform an extra certificate lookup for root CAs that
are not in Windows' (minimal) root store. This check can take up to
15 seconds. The SSL context can already be gone once we return. Hence
we now check for a non-null SSL context on Windows before proceeding.
Change-Id: I1951569d9b17da33fa604f7c9d8b33255acf200d
Reviewed-by: Richard J. Moore <rich@kde.org>
---
src/network/ssl/qsslsocket_openssl.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 0e1a3e5..b132aec 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1281,7 +1281,7 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi
if (plainSocket)
plainSocket->resume();
paused = false;
- if (checkSslErrors())
+ if (checkSslErrors() && ssl)
continueHandshake();
}
--
1.9.1
@@ -1,39 +0,0 @@
From cf6881c03d9f08c6ace83defe461423bb87f30d8 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@theqtcompany.com>
Date: Fri, 15 Jan 2016 14:15:51 +0100
Subject: [PATCH] OS X: Ensure system tray icon is prepared even when menu bar
is hidden
On OS X 10.11 (El Capitan) the system menu bar can be automatically
hidden, in which case the menu bar height is reported to be 0 when
using the menuBarHeight API.
This resulted in failing to prepare an image for the system tray
icon item, making the tray item "invisible".
Instead we now use the [[NSStatusBar systemStatusBar] thickness]
API, which returns the correct height regardless of the menu bar
being hidden or not.
Task-number: QTBUG-48960
Change-Id: I208fb8df13754964a6f254cadfbff06dd56c6bab
---
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index a3ffb5b..8152c57 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -198,7 +198,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
// current OS X versions is 22 points. Provide some future-proofing
// by deriving the icon height from the menu height.
const int padding = 4;
- const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
const int maxImageHeight = menuHeight - padding;
// Select pixmap based on the device pixel height. Ideally we would use
--
2.6.2.2.g1b5ffa3
+11 -46
Ver Arquivo
@@ -1,55 +1,20 @@
## Patches used
There are our patches on top of Qt 5.4.0, which we are currently
using for our binary packages on Windows and Mac OS X. Most of them
There are our patches on top of Qt 5.6.2, which we are currently
using for our binary packages on Windows and macOS. Most of them
have been sent upstream and are part of newer Qt releases.
All changes are designed to up upstream, and all those that are
All changes are designed to be upstream, and all those that are
special hacks to Qt will bear a NOUPSTREAM in their name
The git-style numeration is ordered by order of creation, their
purpose is outlined in each patches' front matter.
You can apply those patches on a git clone using:
### Part of Qt v5.4.1 and later
* 0001-Fix-crash-on-Mac-OS-if-PAC-URL-contains-non-URL-lega.patch
* 0002-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
* 0003-Fix-crash-if-PAC-script-retrieval-returns-a-null-CFD.patch
### Part of Qt v5.4.2 and later
* 0004-Cocoa-Fix-systray-SVG-icons.patch
* 0005-OSX-Fix-disapearing-tray-icon.patch
* 0007-QNAM-Fix-upload-corruptions-when-server-closes-conne.patch
* 0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
### Part of Qt v5.5.0 and later
* 0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
### Part of Qt v5.5.1 and later
* 0007-X-Network-Fix-up-previous-corruption-patch.patch
* 0008-QNAM-Fix-reply-deadlocks-on-server-closing-connectio.patch
* 0014-Fix-SNI-for-TlsV1_0OrLater-TlsV1_1OrLater-and-TlsV1_.patch
* 0016-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
### Part of Qt v5.5.2 (UNRELEASED!)
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
### Part of Qt v5.6 and later
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
* 0013-Make-UnknownAccessibility-not-block-requests.patch
* 0019-Ensure-system-tray-icon-is-prepared-even-when-menu-bar.patch
### Part of Qt 5.7 and later
* 0015-Remove-legacy-platform-code-in-QSslSocket-for-OS-X-1.patch
### Not submitted upstream to be part of any release:
* 0006-Fix-force-debug-info-with-macx-clang_NOUPSTREAM.patch
This is only needed if you intent to harvest debugging symbols
for breakpad.
```
git am <client>/admin/qt/patches/qtbase/*.patch
```
You can update them using:
```
git format-patch -N --no-signature -o <client>/admin/qt/patches/qtbase/ <v5.x.y>
```
@@ -1,30 +1,27 @@
From f3cd07c11e0b7327ffc629f48a89c8c457cdba75 Mon Sep 17 00:00:00 2001
From 96c34ce85136cbdc16ef83effa8a13137f7ae4c5 Mon Sep 17 00:00:00 2001
From: Jocelyn Turcotte <jturcotte@woboq.com>
Date: Fri, 6 Mar 2015 16:12:37 +0100
Subject: [PATCH] Fix -force-debug-info with macx-clang
Subject: [PATCH] [NOUPSTREAM] Fix -force-debug-info with macx-clang
---
mkspecs/common/clang.conf | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf
index 2c29bb8..110d380 100644
index e003b94..e9b3291 100644
--- a/mkspecs/common/clang.conf
+++ b/mkspecs/common/clang.conf
@@ -20,11 +20,13 @@ QMAKE_CFLAGS_ISYSTEM = -isystem
QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
@@ -21,11 +21,13 @@ QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_
QMAKE_CFLAGS_USE_PRECOMPILE = -Xclang -include-pch -Xclang ${QMAKE_PCH_OUTPUT}
QMAKE_CFLAGS_LTCG = -flto
QMAKE_CFLAGS_DISABLE_LTCG = -fno-lto
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_OPTIMIZE -g
QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
QMAKE_CXXFLAGS_CXX11 = -std=c++11
QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG
+QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_CXX11 =
QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
--
2.2.0
QMAKE_CXXFLAGS_CXX11 = -std=c++11
QMAKE_CXXFLAGS_CXX14 = -std=c++1y
QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
@@ -1,7 +1,7 @@
From 06818f6d1c602aa3c4f9356324866432d2dd0195 Mon Sep 17 00:00:00 2001
From e6bccb1f0d8ca59acb1ffdac74a823c06346e7f3 Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <daniel@molkentin.de>
Date: Mon, 16 Nov 2015 15:02:37 +0100
Subject: [PATCH 1/2] Remove legacy platform code in QSslSocket for OS X < 10.5
Subject: [PATCH] Remove legacy platform code in QSslSocket for OS X < 10.5
This avoids manual symbol lookups and makes the code more readable.
Mark identical code.
@@ -16,20 +16,18 @@ Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
Conflicts:
src/network/ssl/qsslsocket_openssl.cpp
---
src/network/ssl/qsslsocket_openssl.cpp | 83 +++++++++++-----------------------
src/network/ssl/qsslsocket_openssl.cpp | 81 +++++++++++-----------------------
src/network/ssl/qsslsocket_p.h | 6 +--
2 files changed, 28 insertions(+), 61 deletions(-)
2 files changed, 26 insertions(+), 61 deletions(-)
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 13fc534..7d0fe00 100644
index 82644c1..415f147 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -69,14 +69,19 @@
#include <QtCore/qvarlengtharray.h>
#include <QLibrary> // for loading the security lib for the CA store
@@ -76,14 +76,17 @@
#include <string.h>
+#include <string.h>
+
+#ifdef Q_OS_DARWIN
+# include <private/qcore_mac_p.h>
+#endif
@@ -50,7 +48,7 @@ index 13fc534..7d0fe00 100644
PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0;
PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0;
PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0;
@@ -482,23 +487,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
@@ -509,23 +512,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
#ifndef QT_NO_LIBRARY
//load symbols needed to receive certificates from system store
@@ -59,23 +57,23 @@ index 13fc534..7d0fe00 100644
- if (securityLib.load()) {
- ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData");
- if (!ptrSecCertificateCopyData)
- qWarning("could not resolve symbols in security library"); // should never happen
- qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen
-
- ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates");
- if (!ptrSecTrustSettingsCopyCertificates) { // method was introduced in Leopard, use legacy method if it's not there
- ptrSecTrustCopyAnchorCertificates = (PtrSecTrustCopyAnchorCertificates) securityLib.resolve("SecTrustCopyAnchorCertificates");
- if (!ptrSecTrustCopyAnchorCertificates)
- qWarning("could not resolve symbols in security library"); // should never happen
- qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen
- }
- } else {
- qWarning("could not load security library");
- qCWarning(lcSsl, "could not load security library");
- }
-#elif defined(Q_OS_WIN)
+#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
#if defined(Q_OS_WINCE)
@@ -635,40 +624,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
@@ -693,40 +680,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
timer.start();
#endif
QList<QSslCertificate> systemCerts;
@@ -101,7 +99,7 @@ index 13fc534..7d0fe00 100644
- data = ptrSecCertificateCopyData(cfCert);
-
- if (data == NULL) {
- qWarning("error retrieving a CA certificate from the system store");
- qCWarning(lcSsl, "error retrieving a CA certificate from the system store");
- } else {
- QByteArray rawCert = QByteArray::fromRawData((const char *)CFDataGetBytePtr(data), CFDataGetLength(data));
- systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der));
@@ -127,15 +125,15 @@ index 13fc534..7d0fe00 100644
- }
- else {
- // no detailed error handling here
- qWarning("could not retrieve system CA certificates");
- qCWarning(lcSsl, "could not retrieve system CA certificates");
}
}
#elif defined(Q_OS_WIN)
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 6e7a2c5..c1a6f05 100644
index d651971..17cc7b4 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -145,11 +145,7 @@ public:
@@ -151,11 +151,7 @@ public:
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
@@ -148,6 +146,3 @@ index 6e7a2c5..c1a6f05 100644
static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW;
static PtrCertFindCertificateInStore ptrCertFindCertificateInStore;
static PtrCertCloseStore ptrCertCloseStore;
--
1.9.1
@@ -1,7 +1,7 @@
From 6b9366e7748857f14d5b0f92ced70c08ab5235b7 Mon Sep 17 00:00:00 2001
From 9d1120db0973ea7741b13a6555b20ae61f6d037e Mon Sep 17 00:00:00 2001
From: Daniel Molkentin <danimo@owncloud.com>
Date: Wed, 25 Nov 2015 12:37:27 +0100
Subject: [PATCH 2/2] QSslSocket: evaluate CAs in all keychain categories
Subject: [PATCH] QSslSocket: evaluate CAs in all keychain categories
This will make sure that certs in the domainUser (login),
and domainAdmin (per machine) keychain are being picked up
@@ -15,7 +15,7 @@ it will be accepted.
[ChangeLog][Platform Specific Changes] OS X now accepts trusted
certificates from the login and system keychains.
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e to Qt 5.4)
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e)
Task-number: QTBUG-32898
Change-Id: Ia23083d5af74388eeee31ba07239735cbbe64368
@@ -29,10 +29,10 @@ Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
create mode 100644 src/network/ssl/qsslsocket_mac_shared.cpp
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 8887f47..6347c20 100644
index 549906a..7b202b0 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1446,6 +1446,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
@@ -1508,6 +1508,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
returned by defaultCaCertificates(). You can replace that database
with your own with setDefaultCaCertificates().
@@ -198,10 +198,10 @@ index 0000000..60fea4c
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 7d0fe00..7415e32 100644
index 415f147..7a3cb42 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -71,14 +71,6 @@
@@ -76,14 +76,6 @@
#include <string.h>
@@ -216,15 +216,15 @@ index 7d0fe00..7415e32 100644
QT_BEGIN_NAMESPACE
#if defined(Q_OS_WIN)
@@ -616,6 +608,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
setDefaultCiphers(defaultCiphers);
@@ -672,6 +664,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves()
setDefaultSupportedEllipticCurves(curves);
}
+#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
{
ensureInitialized();
@@ -624,25 +617,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
@@ -680,25 +673,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
timer.start();
#endif
QList<QSslCertificate> systemCerts;
@@ -251,7 +251,7 @@ index 7d0fe00..7415e32 100644
if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
HCERTSTORE hSystemStore;
#if defined(Q_OS_WINCE)
@@ -719,6 +694,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
@@ -775,6 +750,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
return systemCerts;
}
@@ -260,10 +260,10 @@ index 7d0fe00..7415e32 100644
void QSslSocketBackendPrivate::startClientEncryption()
{
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 384e149..9546f18 100644
index 29c47cd..8eb605b 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -45,7 +45,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
@@ -62,7 +62,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
ssl/qsslsocket_openssl.cpp \
ssl/qsslsocket_openssl_symbols.cpp
@@ -274,6 +274,3 @@ index 384e149..9546f18 100644
# Add optional SSL libs
# Static linking of OpenSSL with msvc:
--
1.9.1
-5
Ver Arquivo
@@ -44,11 +44,6 @@
extern "C" {
#endif
struct csync_client_certs_s {
char *certificatePath;
char *certificatePasswd;
};
enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
-3
Ver Arquivo
@@ -103,9 +103,6 @@ struct csync_s {
} callbacks;
c_strlist_t *excludes;
// needed for SSL client certificate support
struct csync_client_certs_s *clientCerts;
struct {
char *file;
+6 -2
Ver Arquivo
@@ -83,7 +83,7 @@ To set up your build environment for development using HomeBrew_:
3. Add Qt from brew to the path::
export PATH=/usr/local/Cellar/qt5/5.x.y/bin/qmake
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
Where ``x.z`` is the current version of Qt 5 that brew has installed
on your machine.
@@ -100,7 +100,7 @@ To set up your build environment for development using HomeBrew_:
its Common Name as a third parameter (use quotes) to have the package
signed automatically.
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
as a ``pkg`` installer. Do not call "make package" at any time when
compiling for OS X, as this will build a disk image, and will not
work correctly.
@@ -249,6 +249,10 @@ To build the most up-to-date version of the client:
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -D_OPENSSL_VERSION=1.0.2a -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
qtkeychain must be compiled with the same prefix e.g CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ .
4. Call ``make``.
The owncloud binary will appear in the ``bin`` directory.
+1 -1
Ver Arquivo
@@ -65,7 +65,7 @@ If no client is configured, or if you choose to use a different user to synchron
you can specify the user
password setting with the usual URL pattern. For example::
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
$ owncloudcmd /home/user/my_sync_folder https://carla:secret@server/owncloud/remote.php/webdav/
To synchronize the ownCloud directory ``Music`` to the local directory
``media/music``, through a proxy listening on port ``8080``, and on a gateway
+105
Ver Arquivo
@@ -511,6 +511,111 @@ X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
GenericName[oc]=Dorsièr de Sincronizacion
+2 -1
Ver Arquivo
@@ -49,5 +49,6 @@ target_link_libraries(${OWNCLOUDDOLPHINOVERLAYPLUGIN} KF5::CoreAddons KF5::KIOCo
set(OWNCLOUDDOLPHINACTIONPLUGIN ${APPLICATION_EXECUTABLE}dolphinactionplugin)
add_library(${OWNCLOUDDOLPHINACTIONPLUGIN} MODULE ownclouddolphinactionplugin.cpp)
target_link_libraries(${OWNCLOUDDOLPHINACTIONPLUGIN} KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ${OWNCLOUDDOLPHINHELPER})
install(FILES ownclouddolphinactionplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} RENAME ${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop)
configure_file(ownclouddolphinactionplugin.desktop.in ${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop ESCAPE_QUOTES @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS ${OWNCLOUDDOLPHINACTIONPLUGIN} DESTINATION ${KDE_INSTALL_PLUGINDIR})
@@ -1,6 +1,6 @@
[Desktop Entry]
Type=Service
Name=OwncloudAction
Name=@APPLICATION_NAME@Action
ServiceTypes=KFileItemAction/Plugin
MimeType=application/octet-stream;inode/directory;
X-KDE-Library=ownclouddolphinactionplugin
X-KDE-Library=@APPLICATION_EXECUTABLE@dolphinactionplugin
-110
Ver Arquivo
@@ -1,110 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* \file p12topem.cpp
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include "p12topem.h"
/**
* \fn string x509ToString (BIO)
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o) {
BUF_MEM *bptr;
BIO_get_mem_ptr(o, &bptr);
int len = bptr->length;
void* data = calloc(len+10, sizeof(char));
BIO_read(o, data, len);
string ret = std::string(static_cast<char*>(data));
free(data);
return ret;
}
/**
* \fn resultP12ToPem p12ToPem (string, string)
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd) {
FILE *fp;
PKCS12 *p12 = NULL;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
STACK_OF(X509) *ca = NULL;
BIO *o = BIO_new(BIO_s_mem());
string privateKey = "";
string certificate = "";
resultP12ToPem ret;
ret.ReturnCode = false;
ret.ErrorCode = 0;
ret.Comment = "";
ret.PrivateKey = "";
ret.Certificate = "";
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
if(!(fp = fopen(p12File.c_str(), "rb"))) {
ret.ErrorCode = 1;
ret.Comment = strerror(errno);
return ret;
}
p12 = d2i_PKCS12_fp(fp, &p12);
fclose (fp);
if (!p12) {
ret.ErrorCode = 2;
ret.Comment = "Unable to open PKCS#12 file";
return ret;
}
if (!PKCS12_parse(p12, p12Passwd.c_str(), &pkey, &cert, &ca)) {
ret.ErrorCode = 3;
ret.Comment = "Unable to parse PKCS#12 file (wrong password ?)";
return ret;
}
PKCS12_free(p12);
if (!(pkey && cert)) {
ret.ErrorCode = 4;
ret.Comment = "Certificate and/or key file doesn't exists";
} else {
PEM_write_bio_PrivateKey(o, pkey, 0, 0, 0, NULL, 0);
privateKey = x509ToString(o);
PEM_write_bio_X509(o, cert);
certificate = x509ToString(o);
BIO_free(o);
ret.ReturnCode = true;
ret.ErrorCode = 0;
ret.Comment = "All is fine";
ret.PrivateKey = privateKey;
ret.Certificate = certificate;
}
return ret;
}
-62
Ver Arquivo
@@ -1,62 +0,0 @@
/*
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef P12TOPEM_H
#define P12TOPEM_H
/**
* \file p12topem.h
* \brief Static library to convert p12 to pem
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
* \version 1.0.0
* \date 09 January 2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
using namespace std;
/**
* \struct resultP12ToPem p12topem.h
*/
struct resultP12ToPem {
bool ReturnCode;
int ErrorCode;
string Comment;
string PrivateKey;
string Certificate;
};
/**
* \brief Return string from BIO SSL
* \param BIO o PEM_write_BIO_...
* \return string PEM
*/
string x509ToString(BIO *o);
/**
* \brief Convert P12 to PEM
* \param string p12File Path to P12 file
* \param string p12Passwd Password to open P12 file
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
*/
resultP12ToPem p12ToPem(string p12File, string p12Passwd);
#endif /* P12TOPEM_H */
+3 -12
Ver Arquivo
@@ -121,7 +121,7 @@ QString queryPassword(const QString &user)
class HttpCredentialsText : public HttpCredentials {
public:
HttpCredentialsText(const QString& user, const QString& password)
: HttpCredentials(user, password, "", ""), // FIXME: not working with client certs yet (qknight)
: HttpCredentials(user, password), // FIXME: not working with client certs yet (qknight)
_sslTrusted(false)
{}
@@ -328,8 +328,7 @@ int main(int argc, char **argv) {
if( !options.target_url.contains( account->davPath() )) {
options.target_url.append(account->davPath());
}
if (options.target_url.startsWith("http"))
options.target_url.replace(0, 4, "owncloud");
QUrl url = QUrl::fromUserInput(options.target_url);
// Order of retrieval attempt (later attempts override earlier ones):
@@ -370,14 +369,6 @@ int main(int argc, char **argv) {
}
}
// ### ensure URL is free of credentials
if (url.userName().isEmpty()) {
url.setUserName(user);
}
if (url.password().isEmpty()) {
url.setPassword(password);
}
// take the unmodified url to pass to csync_create()
QByteArray remUrl = options.target_url.toUtf8();
@@ -516,7 +507,7 @@ restart_sync:
app.exec();
if (engine.isAnotherSyncNeeded()) {
if (engine.isAnotherSyncNeeded() != NoFollowUpSync) {
if (restartCount < options.restartTimes) {
restartCount++;
qDebug() << "Restarting Sync, because another sync is needed" << restartCount;
-1
Ver Arquivo
@@ -151,7 +151,6 @@ set(3rdparty_SRC
../3rdparty/qtsingleapplication/qtlocalpeer.cpp
../3rdparty/qtsingleapplication/qtsingleapplication.cpp
../3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp
../3rdparty/certificates/p12topem.cpp
)
if (APPLE)
+12 -1
Ver Arquivo
@@ -214,6 +214,17 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
auto acc = createAccount();
QString authType = settings.value(QLatin1String(authTypeC)).toString();
// There was an account-type saving bug when 'skip folder config' was used
// See #5408. This attempts to fix up the "dummy" authType
if (authType == QLatin1String("dummy")) {
if (settings.contains(QLatin1String("http_user"))) {
authType = "http";
} else if (settings.contains(QLatin1String("shibboleth_shib_user"))) {
authType = "shibboleth";
}
}
QString overrideUrl = Theme::instance()->overrideServerUrl();
QString forceAuth = Theme::instance()->forceConfigAuthType();
if(!forceAuth.isEmpty() && !overrideUrl.isEmpty() ) {
@@ -237,7 +248,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
acc->setCredentials(CredentialsFactory::create(authType));
// now the cert, it is in the general group
// now the server cert, it is in the general group
settings.beginGroup(QLatin1String("General"));
acc->setApprovedCerts(QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray()));
settings.endGroup();
+34 -3
Ver Arquivo
@@ -31,6 +31,7 @@
#include "owncloudsetupwizard.h"
#include "creds/abstractcredentials.h"
#include "tooltipupdater.h"
#include "filesystem.h"
#include <math.h>
@@ -110,7 +111,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
QAction *syncNowAction = new QAction(this);
syncNowAction->setShortcut(QKeySequence(Qt::Key_F6));
connect(syncNowAction, SIGNAL(triggered()), SLOT(slotSyncCurrentFolderNow()));
connect(syncNowAction, SIGNAL(triggered()), SLOT(slotScheduleCurrentFolder()));
addAction(syncNowAction);
connect(ui->_folderList, SIGNAL(clicked(const QModelIndex &)),
@@ -213,8 +214,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
}
tv->setCurrentIndex(index);
QString alias = _model->data( index, FolderStatusDelegate::FolderAliasRole ).toString();
bool folderPaused = _model->data( index, FolderStatusDelegate::FolderSyncPaused).toBool();
bool folderConnected = _model->data( index, FolderStatusDelegate::FolderAccountConnected ).toBool();
auto folderMan = FolderMan::instance();
QMenu *menu = new QMenu(tv);
menu->setAttribute(Qt::WA_DeleteOnClose);
@@ -228,6 +231,15 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
connect(ac, SIGNAL(triggered(bool)), this, SLOT(doExpand()));
}
if (!folderPaused) {
ac = menu->addAction(tr("Force sync now"));
if (folderMan->currentSyncFolder() == folderMan->folder(alias)) {
ac->setText(tr("Restart sync"));
}
ac->setEnabled(folderConnected);
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotForceSyncCurrentFolder()));
}
ac = menu->addAction(folderPaused ? tr("Resume sync") : tr("Pause sync"));
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotEnableCurrentFolder()));
@@ -301,8 +313,9 @@ void AccountSettings::slotFolderWizardAccepted()
tr("<p>Could not create local folder <i>%1</i>.")
.arg(QDir::toNativeSeparators(definition.localPath)));
return;
} else {
FileSystem::setFolderMinimumPermissions(definition.localPath);
}
}
}
@@ -462,7 +475,7 @@ void AccountSettings::slotEnableCurrentFolder()
}
}
void AccountSettings::slotSyncCurrentFolderNow()
void AccountSettings::slotScheduleCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( !selected.isValid() )
@@ -473,6 +486,24 @@ void AccountSettings::slotSyncCurrentFolderNow()
folderMan->scheduleFolder(folderMan->folder(alias));
}
void AccountSettings::slotForceSyncCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( !selected.isValid() )
return;
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
FolderMan *folderMan = FolderMan::instance();
// Terminate and reschedule any running sync
if (Folder* current = folderMan->currentSyncFolder()) {
folderMan->terminateSyncProcess();
folderMan->scheduleFolder(current);
}
// Insert the selected folder at the front of the queue
folderMan->scheduleFolderNext(folderMan->folder(alias));
}
void AccountSettings::slotOpenOC()
{
if( _OCUrl.isValid() )
+2 -1
Ver Arquivo
@@ -71,7 +71,8 @@ public slots:
protected slots:
void slotAddFolder();
void slotEnableCurrentFolder();
void slotSyncCurrentFolderNow();
void slotScheduleCurrentFolder();
void slotForceSyncCurrentFolder();
void slotRemoveCurrentFolder();
void slotOpenCurrentFolder();
void slotFolderWizardAccepted();
+2 -2
Ver Arquivo
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>462</width>
<height>186</height>
<height>188</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,7 +32,7 @@
<item row="0" column="0">
<widget class="QLabel" name="labelCertificateFile">
<property name="text">
<string>Certificate :</string>
<string>Certificate &amp; Key (pkcs12) :</string>
</property>
</widget>
</item>
-12
Ver Arquivo
@@ -347,14 +347,6 @@ void Application::slotownCloudWizardDone( int res )
}
}
static void csyncLogCatcher(int /*verbosity*/,
const char */*function*/,
const char *buffer,
void */*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
void Application::setupLogging()
{
// might be called from second instance
@@ -370,10 +362,6 @@ void Application::setupLogging()
.arg(property("ui_lang").toString())
.arg(_theme->version())
.arg(Utility::platformName());
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 );
}
void Application::slotUseMonoIconsChanged(bool)
+1 -1
Ver Arquivo
@@ -27,7 +27,7 @@ class HttpCredentialsGui : public HttpCredentials {
Q_OBJECT
public:
explicit HttpCredentialsGui() : HttpCredentials() {}
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
HttpCredentialsGui(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key) : HttpCredentials(user, password, certificate, key) {}
void askFromUser() Q_DECL_OVERRIDE;
Q_INVOKABLE void askFromUserAsync();
+6 -6
Ver Arquivo
@@ -65,9 +65,6 @@ Folder::Folder(const FolderDefinition& definition,
, _fileLog(new SyncRunFileLog)
, _saveBackwardsCompatible(false)
{
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
qsrand(QTime::currentTime().msec());
_timeSinceLastSyncStart.start();
_timeSinceLastSyncDone.start();
@@ -826,7 +823,7 @@ void Folder::slotSyncFinished(bool success)
_fileLog->finish();
bubbleUpSyncResult();
bool anotherSyncNeeded = _engine->isAnotherSyncNeeded();
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
@@ -839,6 +836,9 @@ void Folder::slotSyncFinished(bool success)
} else if( _syncResult.warnCount() > 0 ) {
// there have been warnings on the way.
_syncResult.setStatus(SyncResult::Problem);
} else if( _definition.paused ) {
// Maybe the sync was terminated because the user paused the folder
_syncResult.setStatus(SyncResult::Paused);
} else {
_syncResult.setStatus(SyncResult::Success);
}
@@ -874,7 +874,7 @@ void Folder::slotSyncFinished(bool success)
_timeSinceLastSyncDone.restart();
// Increment the follow-up sync counter if necessary.
if (anotherSyncNeeded) {
if (anotherSyncNeeded == ImmediateFollowUp) {
_consecutiveFollowUpSyncs++;
qDebug() << "another sync was requested by the finished sync, this has"
<< "happened" << _consecutiveFollowUpSyncs << "times";
@@ -883,7 +883,7 @@ void Folder::slotSyncFinished(bool success)
}
// Maybe force a follow-up sync to take place, but only a couple of times.
if (anotherSyncNeeded && _consecutiveFollowUpSyncs <= 3)
if (anotherSyncNeeded == ImmediateFollowUp && _consecutiveFollowUpSyncs <= 3)
{
// Sometimes another sync is requested because a local file is still
// changing, so wait at least a small amount of time before syncing
+37 -10
Ver Arquivo
@@ -148,6 +148,7 @@ int FolderMan::unloadAndDeleteAllFolders()
void FolderMan::registerFolderMonitor( Folder *folder )
{
if( !folder ) return;
if( !QDir(folder->path()).exists() ) return;
if( !_folderWatchers.contains(folder->alias() ) ) {
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
@@ -544,6 +545,26 @@ void FolderMan::scheduleFolder( Folder *f )
startScheduledSyncSoon();
}
void FolderMan::scheduleFolderNext(Folder* f)
{
auto alias = f->alias();
qDebug() << "Schedule folder " << alias << " to sync! Front-of-queue.";
if( !f->canSync() ) {
qDebug() << "Folder is not ready to sync, not scheduled!";
return;
}
_scheduledFolders.removeAll(f);
f->prepareToSync();
emit folderSyncStateChange(f);
_scheduledFolders.prepend(f);
emit scheduleQueueChanged();
startScheduledSyncSoon();
}
void FolderMan::slotScheduleETagJob(const QString &/*alias*/, RequestEtagJob *job)
{
QObject::connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotEtagJobDestroyed(QObject*)));
@@ -710,6 +731,10 @@ void FolderMan::slotStartScheduledFolderSync()
// Start syncing this folder!
if( folder ) {
// Safe to call several times, and necessary to try again if
// the folder path didn't exist previously.
registerFolderMonitor(folder);
_currentSyncFolder = folder;
folder->startSync( QStringList() );
}
@@ -813,18 +838,20 @@ void FolderMan::slotScheduleFolderByTime()
continue;
}
// Retry a couple of times after failure
bool syncAgainAfterFail = f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3;
qint64 syncAgainAfterFailDelay = 10 * 1000; // 10s for the first retry-after-fail
// Retry a couple of times after failure; or regularly if requested
bool syncAgain =
(f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3)
|| f->syncEngine().isAnotherSyncNeeded() == DelayedFollowUp;
qint64 syncAgainDelay = 10 * 1000; // 10s for the first retry-after-fail
if (f->consecutiveFailingSyncs() > 1)
syncAgainAfterFailDelay = 60 * 1000; // 60s for each further attempt
if (syncAgainAfterFail
&& msecsSinceSync > syncAgainAfterFailDelay) {
syncAgainDelay = 60 * 1000; // 60s for each further attempt
if (syncAgain
&& msecsSinceSync > syncAgainDelay) {
qDebug() << "** scheduling folder" << f->alias()
<< "because the last"
<< f->consecutiveFailingSyncs() << "syncs failed, last status:"
<< f->syncResult().statusString()
<< "time since last sync:" << msecsSinceSync;
<< ", the last" << f->consecutiveFailingSyncs() << "syncs failed"
<< ", anotherSyncNeeded" << f->syncEngine().isAnotherSyncNeeded()
<< ", last status:" << f->syncResult().statusString()
<< ", time since last sync:" << msecsSinceSync;
scheduleFolder(f);
continue;
+10 -6
Ver Arquivo
@@ -161,12 +161,22 @@ public:
/** Queues a folder for syncing. */
void scheduleFolder(Folder*);
/** Puts a folder in the very front of the queue. */
void scheduleFolderNext(Folder*);
/** Queues all folders for syncing. */
void scheduleAllFolders();
void setDirtyProxy(bool value = true);
void setDirtyNetworkLimits();
/**
* Terminates the current folder sync.
*
* It does not switch the folder to paused state.
*/
void terminateSyncProcess();
signals:
/**
* signal to indicate a folder has changed its sync state.
@@ -247,12 +257,6 @@ private slots:
void slotScheduleFolderByTime();
private:
/**
* Terminates the current folder sync.
*
* It does not switch the folder to paused state.
*/
void terminateSyncProcess();
/** Adds a new folder, does not add it to the account settings and
* does not set an account on the new folder.
+6 -9
Ver Arquivo
@@ -527,10 +527,8 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
if (!info || info->_fetched || info->_fetching)
return;
info->_hasError = false;
info->resetSubs(this, parent);
info->_fetching = true;
info->_fetchingLabel = false;
QString path = info->_folder->remotePath();
if (info->_path != QLatin1String("/")) {
if (!path.endsWith(QLatin1Char('/'))) {
@@ -698,17 +696,16 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
qDebug() << r->errorString();
parentInfo->_lastErrorString = r->errorString();
parentInfo->resetSubs(this, idx);
if (r->error() == QNetworkReply::ContentNotFoundError) {
parentInfo->_fetched = true;
} else {
if (!parentInfo->hasLabel()) {
beginInsertRows(idx, 0, 0);
endInsertRows();
}
Q_ASSERT(!parentInfo->hasLabel());
beginInsertRows(idx, 0, 0);
parentInfo->_hasError = true;
endInsertRows();
}
parentInfo->_fetching = false;
parentInfo->_fetchingLabel = false;
}
}
+9 -6
Ver Arquivo
@@ -482,9 +482,8 @@ void FolderWizardRemotePath::showWarn( const QString& msg ) const
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
{
QVBoxLayout *layout = new QVBoxLayout(this);
_treeView = new SelectiveSyncTreeView(account, this);
layout->addWidget(new QLabel(tr("Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.")));
layout->addWidget(_treeView);
_selectiveSync = new SelectiveSyncWidget(account, this);
layout->addWidget(_selectiveSync);
}
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
@@ -501,13 +500,17 @@ void FolderWizardSelectiveSync::initializePage()
QString alias = QFileInfo(targetPath).fileName();
if (alias.isEmpty())
alias = Theme::instance()->appName();
_treeView->setFolderInfo(targetPath, alias);
QStringList initialBlacklist;
if (Theme::instance()->wizardSelectiveSyncDefaultNothing()) {
initialBlacklist = QStringList("/");
}
_selectiveSync->setFolderInfo(targetPath, alias, initialBlacklist);
QWizardPage::initializePage();
}
bool FolderWizardSelectiveSync::validatePage()
{
wizard()->setProperty("selectiveSyncBlackList", QVariant(_treeView->createBlackList()));
wizard()->setProperty("selectiveSyncBlackList", QVariant(_selectiveSync->createBlackList()));
return true;
}
@@ -517,7 +520,7 @@ void FolderWizardSelectiveSync::cleanupPage()
QString alias = QFileInfo(targetPath).fileName();
if (alias.isEmpty())
alias = Theme::instance()->appName();
_treeView->setFolderInfo(targetPath, alias);
_selectiveSync->setFolderInfo(targetPath, alias);
QWizardPage::cleanupPage();
}
+2 -2
Ver Arquivo
@@ -27,7 +27,7 @@
namespace OCC {
class SelectiveSyncTreeView;
class SelectiveSyncWidget;
class ownCloudInfo;
@@ -127,7 +127,7 @@ public:
virtual void cleanupPage() Q_DECL_OVERRIDE;
private:
SelectiveSyncTreeView *_treeView;
SelectiveSyncWidget *_selectiveSync;
};
+2 -1
Ver Arquivo
@@ -110,8 +110,9 @@ LogBrowser::LogBrowser(QWidget *parent) :
setModal(false);
Logger::instance()->setLogWindowActivated(true);
// Direct connection for log coming from this thread, and queued for the one in a different thread
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
connect(Logger::instance(), SIGNAL(logWindowLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
QAction *showLogWindow = new QAction(this);
showLogWindow->setShortcut(QKeySequence("F12"));
+42 -5
Ver Arquivo
@@ -31,6 +31,7 @@
#include "sslerrordialog.h"
#include "accountmanager.h"
#include "clientproxy.h"
#include "filesystem.h"
#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
@@ -202,10 +203,39 @@ void OwncloudSetupWizard::slotOwnCloudFoundAuth(const QUrl& url, const QVariantM
void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
{
_ocWizard->displayError(tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString()), checkDowngradeAdvised(reply));
int resultCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
// Do this early because reply might be deleted in message box event loop
QString msg;
if (!_ocWizard->account()->url().isValid()) {
msg = tr("Invalid URL");
} else {
msg = tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString());
}
bool isDowngradeAdvised = checkDowngradeAdvised(reply);
// If a client cert is needed, nginx sends:
// 400 "<html>\r\n<head><title>400 No required SSL certificate was sent</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>400 Bad Request</h1></center>\r\n<center>No required SSL certificate was sent</center>\r\n<hr><center>nginx/1.10.0</center>\r\n</body>\r\n</html>\r\n"
// If the IP needs to be added as "trusted domain" in oC, oC sends:
// https://gist.github.com/guruz/ab6d11df1873c2ad3932180de92e7d82
if (resultCode != 200 && contentType.startsWith("text/")) {
// FIXME: Synchronous dialogs are not so nice because of event loop recursion
// (we already create a dialog further below)
QString serverError = reply->peek(1024*20);
qDebug() << serverError;
QMessageBox messageBox(_ocWizard);
messageBox.setText(serverError);
messageBox.addButton(QMessageBox::Ok);
messageBox.setTextFormat(Qt::RichText);
messageBox.exec();
}
// Displays message inside wizard and possibly also another message box
_ocWizard->displayError(msg, isDowngradeAdvised);
// Allow the credentials dialog to pop up again for the same URL.
// Maybe the user just clicked 'Cancel' by accident or changed his mind.
@@ -340,8 +370,8 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
} else {
QString res = tr("Creating local sync folder %1...").arg(localFolder);
if( fi.mkpath( localFolder ) ) {
FileSystem::setFolderMinimumPermissions(localFolder);
Utility::setupFavLink( localFolder );
// FIXME: Create a local sync folder.
res += tr("ok");
} else {
res += tr("failed.");
@@ -528,6 +558,13 @@ void OwncloudSetupWizard::slotSkipFolderConfiguration()
AccountState *OwncloudSetupWizard::applyAccountChanges()
{
AccountPtr newAccount = _ocWizard->account();
// Detach the account that is going to be saved from the
// wizard to ensure it doesn't accidentally get modified
// later (such as from running cleanup such as
// AbstractCredentialsWizardPage::cleanupPage())
_ocWizard->setAccount(AccountManager::createAccount());
auto manager = AccountManager::instance();
auto newState = manager->addAccount(newAccount);
+71 -55
Ver Arquivo
@@ -18,6 +18,7 @@
#include "networkjobs.h"
#include "theme.h"
#include "folderman.h"
#include "configfile.h"
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QTreeWidget>
@@ -29,6 +30,7 @@
#include <QScopedValueRollback>
#include <QTreeWidgetItem>
#include <QLabel>
#include <QVBoxLayout>
namespace OCC {
@@ -54,32 +56,48 @@ private:
}
};
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
: QTreeWidget(parent), _inserting(false), _account(account)
SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
: QWidget(parent)
, _account(account)
, _inserting(false)
, _folderTree(new QTreeWidget(this))
{
_loading = new QLabel(tr("Loading ..."), this);
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
setSortingEnabled(true);
sortByColumn(0, Qt::AscendingOrder);
setColumnCount(2);
_loading = new QLabel(tr("Loading ..."), _folderTree);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
auto header = new QLabel(this);
header->setText(tr("Deselect remote folders you do not wish to synchronize."));
header->setWordWrap(true);
layout->addWidget(header);
layout->addWidget(_folderTree);
connect(_folderTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
SLOT(slotItemExpanded(QTreeWidgetItem*)));
connect(_folderTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
SLOT(slotItemChanged(QTreeWidgetItem*,int)));
_folderTree->setSortingEnabled(true);
_folderTree->sortByColumn(0, Qt::AscendingOrder);
_folderTree->setColumnCount(2);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
_folderTree->header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
_folderTree->header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
#else
header()->resizeSection(0, sizeHint().width()/2);
_folderTree->header()->resizeSection(0, sizeHint().width()/2);
#endif
header()->setStretchLastSection(true);
headerItem()->setText(0, tr("Name"));
headerItem()->setText(1, tr("Size"));
_folderTree->header()->setStretchLastSection(true);
_folderTree->headerItem()->setText(0, tr("Name"));
_folderTree->headerItem()->setText(1, tr("Size"));
}
QSize SelectiveSyncTreeView::sizeHint() const
QSize SelectiveSyncWidget::sizeHint() const
{
return QTreeView::sizeHint().expandedTo(QSize(400, 400));
return QWidget::sizeHint().expandedTo(QSize(600, 600));
}
void SelectiveSyncTreeView::refreshFolders()
void SelectiveSyncWidget::refreshFolders()
{
LsColJob *job = new LsColJob(_account, _folderPath, this);
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
@@ -88,12 +106,12 @@ void SelectiveSyncTreeView::refreshFolders()
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
job->start();
clear();
_folderTree->clear();
_loading->show();
_loading->move(10,header()->height() + 10);
_loading->move(10, _folderTree->header()->height() + 10);
}
void SelectiveSyncTreeView::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
void SelectiveSyncWidget::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
{
_folderPath = folderPath;
if (_folderPath.startsWith(QLatin1Char('/'))) {
@@ -116,7 +134,7 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
return 0;
}
void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
{
QFileIconProvider prov;
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
@@ -159,13 +177,13 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
}
}
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
{
auto job = qobject_cast<LsColJob *>(sender());
QScopedValueRollback<bool> isInserting(_inserting);
_inserting = true;
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(_folderTree->topLevelItem(0));
QUrl url = _account->davUrl();
QString pathToRemove = url.path();
@@ -206,15 +224,11 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
}
if (!root) {
root = new SelectiveSyncTreeViewItem(this);
root = new SelectiveSyncTreeViewItem(_folderTree);
root->setText(0, _rootName);
root->setIcon(0, Theme::instance()->applicationIcon());
root->setData(0, Qt::UserRole, QString());
if (_oldBlackList.isEmpty()) {
root->setCheckState(0, Qt::Checked);
} else {
root->setCheckState(0, Qt::PartiallyChecked);
}
root->setCheckState(0, Qt::Checked);
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
if (size >= 0) {
root->setText(1, Utility::octetsToString(size));
@@ -236,10 +250,19 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
recursiveInsert(root, paths, path, size);
}
// Root is partially checked if any children are not checked
for (int i = 0; i < root->childCount(); ++i) {
const auto child = root->child(i);
if (child->checkState(0) != Qt::Checked) {
root->setCheckState(0, Qt::PartiallyChecked);
break;
}
}
root->setExpanded(true);
}
void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
{
if (r->error() == QNetworkReply::ContentNotFoundError) {
_loading->setText(tr("No subfolders currently on the server."));
@@ -249,7 +272,7 @@ void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
_loading->resize(_loading->sizeHint()); // because it's not in a layout
}
void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
{
QString dir = item->data(0, Qt::UserRole).toString();
if (dir.isEmpty()) return;
@@ -264,7 +287,7 @@ void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
job->start();
}
void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
{
if (col != 0 || _inserting)
return;
@@ -322,10 +345,10 @@ void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
}
}
QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
{
if (!root) {
root = topLevelItem(0);
root = _folderTree->topLevelItem(0);
}
if (!root) return QStringList();
@@ -354,15 +377,15 @@ QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
return result;
}
QStringList SelectiveSyncTreeView::oldBlackList() const
QStringList SelectiveSyncWidget::oldBlackList() const
{
return _oldBlackList;
}
qint64 SelectiveSyncTreeView::estimatedSize(QTreeWidgetItem* root)
qint64 SelectiveSyncWidget::estimatedSize(QTreeWidgetItem* root)
{
if (!root) {
root = topLevelItem(0);
root = _folderTree->topLevelItem(0);
}
if (!root) return -1;
@@ -396,10 +419,10 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, Folder* folder, QWi
_okButton(0) // defined in init()
{
bool ok;
init(account, tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
init(account);
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
if( ok ) {
_treeView->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
_selectiveSync->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
} else {
_okButton->setEnabled(false);
}
@@ -411,22 +434,16 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, const QString &fold
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
: QDialog(parent, f), _folder(0)
{
init(account,
Theme::instance()->wizardSelectiveSyncDefaultNothing() ?
tr("Choose What to Sync: Select remote subfolders you wish to synchronize.") :
tr("Choose What to Sync: Deselect remote subfolders you do not wish to synchronize."));
_treeView->setFolderInfo(folder, folder, blacklist);
init(account);
_selectiveSync->setFolderInfo(folder, folder, blacklist);
}
void SelectiveSyncDialog::init(const AccountPtr &account, const QString &labelText)
void SelectiveSyncDialog::init(const AccountPtr &account)
{
setWindowTitle(tr("Choose What to Sync"));
QVBoxLayout *layout = new QVBoxLayout(this);
_treeView = new SelectiveSyncTreeView(account, this);
auto label = new QLabel(labelText);
label->setWordWrap(true);
layout->addWidget(label);
layout->addWidget(_treeView);
_selectiveSync = new SelectiveSyncWidget(account, this);
layout->addWidget(_selectiveSync);
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
@@ -444,7 +461,7 @@ void SelectiveSyncDialog::accept()
if( ! ok ) {
return;
}
QStringList blackList = _treeView->createBlackList();
QStringList blackList = _selectiveSync->createBlackList();
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
FolderMan *folderMan = FolderMan::instance();
@@ -467,19 +484,18 @@ void SelectiveSyncDialog::accept()
QStringList SelectiveSyncDialog::createBlackList() const
{
return _treeView->createBlackList();
return _selectiveSync->createBlackList();
}
QStringList SelectiveSyncDialog::oldBlackList() const
{
return _treeView->oldBlackList();
return _selectiveSync->oldBlackList();
}
qint64 SelectiveSyncDialog::estimatedSize()
{
return _treeView->estimatedSize();
return _selectiveSync->estimatedSize();
}
}
+17 -7
Ver Arquivo
@@ -26,40 +26,50 @@ namespace OCC {
class Folder;
/**
* @brief The SelectiveSyncTreeView class
* @brief The SelectiveSyncWidget contains a folder tree with labels
* @ingroup gui
*/
class SelectiveSyncTreeView : public QTreeWidget {
class SelectiveSyncWidget : public QWidget {
Q_OBJECT
public:
explicit SelectiveSyncTreeView(AccountPtr account, QWidget* parent = 0);
explicit SelectiveSyncWidget(AccountPtr account, QWidget* parent = 0);
/// Returns a list of blacklisted paths, each including the trailing /
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
/** Returns the oldBlackList passed into setFolderInfo(), except that
* a "/" entry is expanded to all top-level folder names.
*/
QStringList oldBlackList() const;
// Estimates the total size of checked items (recursively)
qint64 estimatedSize(QTreeWidgetItem *root = 0);
void refreshFolders();
// oldBlackList is a list of excluded paths, each including a trailing /
void setFolderInfo(const QString &folderPath, const QString &rootName,
const QStringList &oldBlackList = QStringList());
QSize sizeHint() const Q_DECL_OVERRIDE;
private slots:
void slotUpdateDirectories(QStringList);
void slotItemExpanded(QTreeWidgetItem *);
void slotItemChanged(QTreeWidgetItem*,int);
void slotLscolFinishedWithError(QNetworkReply*);
private:
void refreshFolders();
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
AccountPtr _account;
QString _folderPath;
QString _rootName;
QStringList _oldBlackList;
bool _inserting; // set to true when we are inserting new items on the list
AccountPtr _account;
QLabel *_loading;
QTreeWidget *_folderTree;
};
/**
@@ -85,9 +95,9 @@ public:
private:
void init(const AccountPtr &account, const QString &label);
void init(const AccountPtr &account);
SelectiveSyncTreeView *_treeView;
SelectiveSyncWidget *_selectiveSync;
Folder *_folder;
QPushButton *_okButton;
@@ -29,8 +29,11 @@ OwncloudConnectionMethodDialog::OwncloudConnectionMethodDialog(QWidget *parent)
connect(ui->btnClientSideTLS, SIGNAL(clicked(bool)), this, SLOT(returnClientSideTLS()));
connect(ui->btnBack, SIGNAL(clicked(bool)), this, SLOT(returnBack()));
// DM: TLS Client Cert GUI support disabled for now
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
// We support only from Qt 5.4.x because of https://doc.qt.io/qt-5/qsslcertificate.html#importPkcs12
ui->btnClientSideTLS->hide();
#endif
}
void OwncloudConnectionMethodDialog::setUrl(const QUrl &url)
+1 -1
Ver Arquivo
@@ -192,7 +192,7 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const
{
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->ownCloudCertificatePath, _ocWizard->ownCloudCertificatePasswd);
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->_clientSslCertificate, _ocWizard->_clientSslKey);
}
+32 -31
Ver Arquivo
@@ -21,13 +21,13 @@
#include <QMessageBox>
#include <QSsl>
#include <QSslCertificate>
#include <QNetworkAccessManager>
#include "QProgressIndicator.h"
#include "wizard/owncloudwizardcommon.h"
#include "wizard/owncloudsetuppage.h"
#include "wizard/owncloudconnectionmethoddialog.h"
#include "../3rdparty/certificates/p12topem.h"
#include "theme.h"
#include "account.h"
@@ -71,7 +71,6 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
addCertDial = new AddCertificateDialog(this);
connect(_ocWizard,SIGNAL(needCertificate()),this,SLOT(slotAskSSLClientCertificate()));
}
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
@@ -139,7 +138,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
void OwncloudSetupPage::slotUrlEditFinished()
{
QString url = _ui.leUrl->fullText();
if (QUrl(url).isRelative()) {
if (QUrl(url).isRelative() && !url.isEmpty()) {
// no scheme defined, set one
url.prepend("https://");
}
@@ -256,6 +255,7 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
OwncloudConnectionMethodDialog dialog;
dialog.setUrl(url);
// FIXME: Synchronous dialogs are not so nice because of event loop recursion
int retVal = dialog.exec();
switch (retVal) {
@@ -268,7 +268,10 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
}
break;
case OwncloudConnectionMethodDialog::Client_Side_TLS:
slotAskSSLClientCertificate();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
#endif
break;
case OwncloudConnectionMethodDialog::Closed:
case OwncloudConnectionMethodDialog::Back:
@@ -301,12 +304,6 @@ void OwncloudSetupPage::stopSpinner()
_progressIndi->stopAnimation();
}
void OwncloudSetupPage::slotAskSSLClientCertificate()
{
addCertDial->show();
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
}
QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
@@ -319,36 +316,40 @@ QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
//called during the validation of the client certificate.
void OwncloudSetupPage::slotCertificateAccepted()
{
QSslCertificate sslCertificate;
resultP12ToPem certif = p12ToPem(addCertDial->getCertificatePath().toStdString() , addCertDial->getCertificatePasswd().toStdString());
if(certif.ReturnCode){
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(ba, QSsl::Pem);
sslCertificate = sslCertificateList.takeAt(0);
_ocWizard->ownCloudCertificate = ba;
_ocWizard->ownCloudPrivateKey = certif.PrivateKey.c_str();
_ocWizard->ownCloudCertificatePath = addCertDial->getCertificatePath();
_ocWizard->ownCloudCertificatePasswd = addCertDial->getCertificatePasswd();
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
QList<QSslCertificate> clientCaCertificates;
QFile certFile(addCertDial->getCertificatePath());
certFile.open(QFile::ReadOnly);
if(QSslCertificate::importPkcs12(&certFile,
&_ocWizard->_clientSslKey, &_ocWizard->_clientSslCertificate,
&clientCaCertificates,
addCertDial->getCertificatePasswd().toLocal8Bit())){
AccountPtr acc = _ocWizard->account();
acc->setCertificate(_ocWizard->ownCloudCertificate, _ocWizard->ownCloudPrivateKey);
addCertDial->reinit();
// to re-create the session ticket because we added a key/cert
acc->setSslConfiguration(QSslConfiguration());
QSslConfiguration sslConfiguration = acc->getOrCreateSslConfig();
// We're stuffing the certificate into the configuration form here. Later the
// cert will come via the HttpCredentials
sslConfiguration.setLocalCertificate(_ocWizard->_clientSslCertificate);
sslConfiguration.setPrivateKey(_ocWizard->_clientSslKey);
acc->setSslConfiguration(sslConfiguration);
// Make sure TCP connections get re-established
acc->networkAccessManager()->clearAccessCache();
addCertDial->reinit(); // FIXME: Why not just have this only created on use?
validatePage();
} else {
QString message;
message = certif.Comment.c_str();
addCertDial->showErrorMessage(message);
addCertDial->showErrorMessage("Could not load certificate");
addCertDial->show();
}
#endif
}
OwncloudSetupPage::~OwncloudSetupPage()
{
delete addCertDial;
}
} // namespace OCC
-1
Ver Arquivo
@@ -59,7 +59,6 @@ public slots:
void setErrorString( const QString&, bool retryHTTPonly );
void startSpinner();
void stopSpinner();
void slotAskSSLClientCertificate();
void slotCertificateAccepted();
protected slots:
-7
Ver Arquivo
@@ -224,11 +224,4 @@ AbstractCredentials* OwncloudWizard::getCredentials() const
return 0;
}
// outputs the signal needed to authenticate a certificate
void OwncloudWizard::raiseCertificatePopup()
{
emit needCertificate();
}
} // end namespace
+6 -5
Ver Arquivo
@@ -17,6 +17,8 @@
#define MIRALL_OWNCLOUD_WIZARD_H
#include <QWizard>
#include <QSslKey>
#include <QSslCertificate>
#include "wizard/owncloudwizardcommon.h"
#include "accountfwd.h"
@@ -63,11 +65,10 @@ public:
void displayError( const QString&, bool retryHTTPonly);
AbstractCredentials* getCredentials() const;
void raiseCertificatePopup();
QByteArray ownCloudCertificate;
QString ownCloudPrivateKey;
QString ownCloudCertificatePath;
QString ownCloudCertificatePasswd;
// FIXME: Can those be local variables?
// Set from the OwncloudSetupPage, later used from OwncloudHttpCredsPage
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
public slots:
void setAuthType(WizardCommon::AuthType type);
-1
Ver Arquivo
@@ -70,7 +70,6 @@ set(libsync_SRCS
creds/abstractcredentials.cpp
creds/credentialscommon.cpp
../3rdparty/qjson/json.cpp
../3rdparty/certificates/p12topem.cpp
)
if(TOKEN_AUTH_ONLY)
+20 -37
Ver Arquivo
@@ -18,7 +18,6 @@
#include "configfile.h"
#include "accessmanager.h"
#include "creds/abstractcredentials.h"
#include "../3rdparty/certificates/p12topem.h"
#include "capabilities.h"
#include "theme.h"
@@ -57,6 +56,11 @@ Account::~Account()
QString Account::davPath() const
{
if (capabilities().chunkingNg()) {
// The chunking-ng means the server prefer to use the new webdav URL
return QLatin1String("/remote.php/dav/files/") + davUser() + QLatin1Char('/');
}
// make sure to have a trailing slash
if( !_davPath.endsWith('/') ) {
QString dp(_davPath);
@@ -76,19 +80,19 @@ AccountPtr Account::sharedFromThis()
return _sharedThis.toStrongRef();
}
QString Account::user() const
QString Account::davUser() const
{
return _user.isEmpty() ? _credentials->user() : _user;
return _davUser.isEmpty() ? _credentials->user() : _davUser;
}
void Account::setUser(const QString &user)
void Account::setDavUser(const QString &newDavUser)
{
_user = user;
_davUser = newDavUser;
}
QString Account::displayName() const
{
QString dn = QString("%1@%2").arg(user(), _url.host());
QString dn = QString("%1@%2").arg(_credentials->user(), _url.host());
int port = url().port();
if (port > 0 && port != 80 && port != 443) {
dn.append(QLatin1Char(':'));
@@ -144,10 +148,14 @@ QUrl Account::davUrl() const
return Utility::concatUrlPath(url(), davPath());
}
/**
* clear all cookies. (Session cookies or not)
*/
void Account::clearCookieJar()
{
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
static_cast<CookieJar*>(_am->cookieJar())->clearSessionCookies();
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
emit wantsAccountSaved(this);
}
/*! This shares our official cookie jar (containing all the tasty
@@ -237,12 +245,6 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNet
return _am->sendCustomRequest(req, verb, data);
}
void Account::setCertificate(const QByteArray certficate, const QString privateKey)
{
_pemCertificate=certficate;
_pemPrivateKey=privateKey;
}
void Account::setSslConfiguration(const QSslConfiguration &config)
{
_sslConfiguration = config;
@@ -259,31 +261,7 @@ QSslConfiguration Account::getOrCreateSslConfig()
// if setting the client certificate fails, you will probably get an error similar to this:
// "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
QSslCertificate sslClientCertificate;
ConfigFile cfgFile;
if(!cfgFile.certificatePath().isEmpty() && !cfgFile.certificatePasswd().isEmpty()) {
resultP12ToPem certif = p12ToPem(cfgFile.certificatePath().toStdString(), cfgFile.certificatePasswd().toStdString());
QString s = QString::fromStdString(certif.Certificate);
QByteArray ba = s.toLocal8Bit();
this->setCertificate(ba, QString::fromStdString(certif.PrivateKey));
}
if((!_pemCertificate.isEmpty())&&(!_pemPrivateKey.isEmpty())) {
// Read certificates
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(_pemCertificate, QSsl::Pem);
if(sslCertificateList.length() != 0) {
sslClientCertificate = sslCertificateList.takeAt(0);
}
// Read key from file
QSslKey privateKey(_pemPrivateKey.toLocal8Bit(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey , "");
// SSL configuration
sslConfig.setCaCertificates(QSslSocket::systemCaCertificates());
sslConfig.setLocalCertificate(sslClientCertificate);
sslConfig.setPrivateKey(privateKey);
qDebug() << "Added SSL client certificate to the query";
}
#if QT_VERSION > QT_VERSION_CHECK(5, 2, 0)
// Try hard to re-use session for different requests
sslConfig.setSslOption(QSsl::SslOptionDisableSessionTickets, false);
@@ -374,8 +352,11 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// Keep a ref here on our stackframe to make sure that it doesn't get deleted before
// handleErrors returns.
QSharedPointer<QNetworkAccessManager> qnamLock = _am;
QPointer<QObject> guard = reply;
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
if (!guard) return;
QSslSocket::addDefaultCaCertificates(approvedCerts);
addApprovedCerts(approvedCerts);
emit wantsAccountSaved(this);
@@ -387,6 +368,8 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
// certificate changes.
reply->ignoreSslErrors(errors);
} else {
if (!guard) return;
// Mark all involved certificates as rejected, so we don't ask the user again.
foreach (const QSslError &error, errors) {
if (!_rejectedCertificates.contains(error.certificate())) {
+10 -6
Ver Arquivo
@@ -69,9 +69,14 @@ public:
AccountPtr sharedFromThis();
/// The user that can be used in dav url
QString user() const;
void setUser(const QString &user);
/**
* The user that can be used in dav url.
*
* This can very well be different frome the login user that's
* stored in credentials()->user().
*/
QString davUser() const;
void setDavUser(const QString &newDavUser);
/// The name of the account as shown in the toolbar
QString displayName() const;
@@ -203,7 +208,7 @@ private:
QWeakPointer<Account> _sharedThis;
QString _id;
QString _user;
QString _davUser;
QMap<QString, QVariant> _settingsMap;
QUrl _url;
QList<QSslCertificate> _approvedCerts;
@@ -219,8 +224,7 @@ private:
QList<QSslCertificate> _rejectedCertificates;
static QString _configFileName;
QByteArray _pemCertificate;
QString _pemPrivateKey;
QString _davPath; // defaults to value from theme, might be overwritten in brandings
friend class AccountManager;
};
+7
Ver Arquivo
@@ -110,8 +110,15 @@ QByteArray Capabilities::uploadChecksumType() const
bool Capabilities::chunkingNg() const
{
static const auto chunkng = qgetenv("OWNCLOUD_CHUNKING_NG");
if (chunkng == "0") return false;
if (chunkng == "1") return true;
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
}
bool Capabilities::chunkingParallelUploadDisabled() const
{
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
}
}
+3
Ver Arquivo
@@ -42,6 +42,9 @@ public:
bool shareResharing() const;
bool chunkingNg() const;
/// disable parallel upload in chunking
bool chunkingParallelUploadDisabled() const;
/// returns true if the capabilities report notifications
bool notificationsAvailable() const;
+7 -2
Ver Arquivo
@@ -144,7 +144,12 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
// status.php could not be loaded (network or server issue!).
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString() << reply->peek(1024);
if (reply && !_account->credentials()->ready()) {
// This could be needed for SSL client certificates
// We need to load them from keychain and try
reportResult( CredentialsMissingOrWrong );
} else
if( reply && ! _account->credentials()->stillValid(reply)) {
_errors.append(tr("Authentication error: Either username or password are wrong."));
} else {
@@ -246,7 +251,7 @@ void ConnectionValidator::slotUserFetched(const QVariantMap &json)
{
QString user = json.value("ocs").toMap().value("data").toMap().value("id").toString();
if (!user.isEmpty()) {
_account->setUser(user);
_account->setDavUser(user);
}
reportResult(Connected);
}
+129 -47
Ver Arquivo
@@ -17,6 +17,7 @@
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QSslKey>
#include <keychain.h>
@@ -36,8 +37,8 @@ namespace OCC
namespace
{
const char userC[] = "user";
const char certifPathC[] = "certificatePath";
const char certifPasswdC[] = "certificatePasswd";
const char clientCertificatePEMC[] = "_clientCertificatePEM";
const char clientKeyPEMC[] = "_clientKeyPEM";
const char authenticationFailedC[] = "owncloud-authentication-failed";
} // ns
@@ -50,24 +51,47 @@ protected:
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
//qDebug() << "Request for " << req.url() << "with authorization"
// << QByteArray::fromBase64(credHash)
// << _cred->_clientSslKey << _cred->_clientSslCertificate
// << _cred->_clientSslKey.isNull() << _cred->_clientSslCertificate.isNull();
if (!_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) {
// SSL configuration
QSslConfiguration sslConfiguration = req.sslConfiguration();
sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
sslConfiguration.setPrivateKey(_cred->_clientSslKey);
req.setSslConfiguration(sslConfiguration);
}
return AccessManager::createRequest(op, req, outgoingData);
}
private:
const HttpCredentials *_cred;
};
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account);
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
HttpCredentials::HttpCredentials()
: _ready(false)
{
}
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd)
// From wizard
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key)
: _user(user),
_password(password),
_ready(true),
_certificatePath(certificatePath),
_certificatePasswd(certificatePasswd)
_clientSslKey(key),
_clientSslCertificate(certificate)
{
}
@@ -86,16 +110,6 @@ QString HttpCredentials::password() const
return _password;
}
QString HttpCredentials::certificatePath() const
{
return _certificatePath;
}
QString HttpCredentials::certificatePasswd() const
{
return _certificatePasswd;
}
void HttpCredentials::setAccount(Account* account)
{
AbstractCredentials::setAccount(account);
@@ -129,35 +143,83 @@ void HttpCredentials::fetchFromKeychain()
{
// User must be fetched from config file
fetchUser();
_certificatePath = _account->credentialSetting(QLatin1String(certifPathC)).toString();
_certificatePasswd = _account->credentialSetting(QLatin1String(certifPasswdC)).toString();
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
const QString kck = keychainKey(_account->url().toString(), _user );
QString key = QString::fromLatin1( "%1/data" ).arg( kck );
if( settings && settings->contains(key) ) {
// Clean the password from the config file if it is in there.
// we do not want a security problem.
settings->remove(key);
key = QString::fromLatin1( "%1/type" ).arg( kck );
settings->remove(key);
settings->sync();
}
if (_ready) {
Q_EMIT fetched();
} else {
// Read client cert from keychain
const QString kck = keychainKey(_account->url().toString(), _user + clientCertificatePEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
qDebug() << "-------- ----->" << _clientSslCertificate << _clientSslKey;
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientCertPEMJobDone(QKeychain::Job*)));
job->start();
}
}
void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job* incoming)
{
// Store PEM in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
if(sslCertificateList.length() >= 1) {
_clientSslCertificate = sslCertificateList.at(0);
}
}
// Load key too
const QString kck = keychainKey(_account->url().toString(), _user + clientKeyPEMC);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientKeyPEMJobDone(QKeychain::Job*)));
job->start();
}
void HttpCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job* incoming)
{
// Store key in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QByteArray clientKeyPEM = readJob->binaryData();
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
// load whatever we have. So we try until it works.
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
// ec keys are Qt 5.5
if (_clientSslKey.isNull()) {
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
}
#endif
if (_clientSslKey.isNull()) {
qDebug() << "Warning: Could not load SSL key into Qt!";
}
}
// Now fetch the actual server password
const QString kck = keychainKey(_account->url().toString(), _user );
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start();
}
bool HttpCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
@@ -166,10 +228,10 @@ bool HttpCredentials::stillValid(QNetworkReply *reply)
|| !reply->property(authenticationFailedC).toBool()));
}
void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob)
{
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
_password = readJob->textData();
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob*>(incomingJob);
_password = job->textData();
if( _user.isEmpty()) {
qDebug() << "Strange: User is empty!";
@@ -178,7 +240,6 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
QKeychain::Error error = job->error();
if( !_password.isEmpty() && error == NoError ) {
// All cool, the keychain did not come back with error.
// Still, the password can be empty which indicates a problem and
// the password dialog has to be opened.
@@ -214,9 +275,7 @@ void HttpCredentials::invalidateToken()
}
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
addSettingsToJob(_account, job);
job->setInsecureFallback(true);
job->setKey(kck);
job->start();
@@ -261,14 +320,37 @@ void HttpCredentials::persist()
// We never connected or fetched the user, there is nothing to save.
return;
}
_account->setCredentialSetting(QLatin1String(userC), _user);
_account->setCredentialSetting(QLatin1String(certifPathC), _certificatePath);
_account->setCredentialSetting(QLatin1String(certifPasswdC), _certificatePasswd);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
_account->setCredentialSetting(QLatin1String(userC), _user);
// write cert
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientCertPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC));
job->setBinaryData(_clientSslCertificate.toPem());
job->start();
}
void HttpCredentials::slotWriteClientCertPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
// write ssl key
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientKeyPEMJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC));
job->setBinaryData(_clientSslKey.toPem());
job->start();
}
void HttpCredentials::slotWriteClientKeyPEMJobDone(Job *incomingJob)
{
Q_UNUSED(incomingJob);
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), _user));
+15 -9
Ver Arquivo
@@ -17,7 +17,8 @@
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
#include <QMap>
#include <QSslCertificate>
#include <QSslKey>
#include "creds/abstractcredentials.h"
class QNetworkReply;
@@ -25,6 +26,8 @@ class QAuthenticator;
namespace QKeychain {
class Job;
class WritePasswordJob;
class ReadPasswordJob;
}
namespace OCC
@@ -33,10 +36,10 @@ namespace OCC
class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
{
Q_OBJECT
friend class HttpCredentialsAccessManager;
public:
explicit HttpCredentials();
HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd);
HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate = QSslCertificate(), const QSslKey& key = QSslKey());
QString authType() const Q_DECL_OVERRIDE;
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
@@ -50,15 +53,19 @@ public:
void forgetSensitiveData() Q_DECL_OVERRIDE;
QString fetchUser();
virtual bool sslIsTrusted() { return false; }
QString certificatePath() const;
QString certificatePasswd() const;
// To fetch the user name as early as possible
void setAccount(Account* account) Q_DECL_OVERRIDE;
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
void slotReadClientCertPEMJobDone(QKeychain::Job*);
void slotReadClientKeyPEMJobDone(QKeychain::Job*);
void slotReadJobDone(QKeychain::Job*);
void slotWriteClientCertPEMJobDone(QKeychain::Job*);
void slotWriteClientKeyPEMJobDone(QKeychain::Job*);
void slotWriteJobDone(QKeychain::Job*);
void clearQNAMCache();
@@ -66,12 +73,11 @@ protected:
QString _user;
QString _password;
QString _previousPassword;
QString _fetchErrorString;
bool _ready;
private:
QString _certificatePath;
QString _certificatePasswd;
QSslKey _clientSslKey;
QSslCertificate _clientSslCertificate;
};
} // namespace OCC
+11
Ver Arquivo
@@ -146,6 +146,17 @@ void FileSystem::setFileReadOnly(const QString& filename, bool readonly)
file.setPermissions(permissions);
}
void FileSystem::setFolderMinimumPermissions(const QString& filename)
{
#ifdef Q_OS_MAC
QFile::Permissions perm = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
QFile file(filename);
file.setPermissions(perm);
#else
Q_UNUSED(filename);
#endif
}
void FileSystem::setFileReadOnlyWeak(const QString& filename, bool readonly)
{
+6
Ver Arquivo
@@ -67,6 +67,12 @@ void OWNCLOUDSYNC_EXPORT setFileReadOnly(const QString& filename, bool readonly)
*/
void OWNCLOUDSYNC_EXPORT setFileReadOnlyWeak(const QString& filename, bool readonly);
/**
* @brief Try to set permissions so that other users on the local machine can not
* go into the folder.
*/
void OWNCLOUDSYNC_EXPORT setFolderMinimumPermissions(const QString& filename);
/** convert a "normal" windows path into a path that can be 32k chars long. */
QString OWNCLOUDSYNC_EXPORT longWinPath( const QString& inpath );
+28 -7
Ver Arquivo
@@ -19,6 +19,8 @@
#include <QThread>
#include <qmetaobject.h>
#include "csync.h"
namespace OCC {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
@@ -48,6 +50,14 @@ static void mirallLogCatcher(QtMsgType type, const QMessageLogContext &ctx, cons
}
#endif
static void csyncLogCatcher(int /*verbosity*/,
const char * /*function*/,
const char *buffer,
void * /*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
Logger *Logger::instance()
{
static Logger log;
@@ -55,7 +65,7 @@ Logger *Logger::instance()
}
Logger::Logger( QObject* parent) : QObject(parent),
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
_showTime(true), _logWindowActivated(false), _doFileFlush(false), _logExpire(0)
{
#ifndef NO_MSG_HANDLER
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
@@ -117,12 +127,8 @@ bool Logger::isNoop() const
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
return false;
#else
static auto signal = QMetaMethod::fromSignal(&Logger::newLog);
if (isSignalConnected(signal)) {
return false;
}
QMutexLocker lock(const_cast<QMutex *>(&_mutex));
return !_logstream;
return !_logstream && !_logWindowActivated;
#endif
}
@@ -136,7 +142,7 @@ void Logger::doLog(const QString& msg)
if( _doFileFlush ) _logstream->flush();
}
}
emit newLog(msg);
emit logWindowLog(msg);
}
void Logger::csyncLog( const QString& message )
@@ -164,10 +170,25 @@ void Logger::mirallLog( const QString& message )
Logger::instance()->log( log_ );
}
void Logger::setLogWindowActivated(bool activated)
{
QMutexLocker locker(&_mutex);
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback(csyncLogCatcher);
csync_set_log_level(11);
_logWindowActivated = activated;
}
void Logger::setLogFile(const QString & name)
{
QMutexLocker locker(&_mutex);
// Setup CSYNC logging to forward to our own logger
csync_set_log_callback(csyncLogCatcher);
csync_set_log_level(11);
if( _logstream ) {
_logstream.reset(0);
_logFile.close();
+4 -2
Ver Arquivo
@@ -61,13 +61,15 @@ public:
void postOptionalGuiLog(const QString& title, const QString& message);
void postGuiMessage(const QString& title, const QString& message);
void setLogWindowActivated(bool activated);
void setLogFile( const QString & name );
void setLogExpire( int expire );
void setLogDir( const QString& dir );
void setLogFlush( bool flush );
signals:
void newLog(const QString&);
void logWindowLog(const QString&);
void guiLog(const QString&, const QString&);
void guiMessage(const QString&, const QString&);
void optionalGuiLog(const QString&, const QString&);
@@ -80,7 +82,7 @@ private:
~Logger();
QList<Log> _logs;
bool _showTime;
bool _doLogging;
bool _logWindowActivated;
QFile _logFile;
bool _doFileFlush;
int _logExpire;
+2 -2
Ver Arquivo
@@ -463,7 +463,7 @@ bool CheckServerJob::finished()
}
bool success = false;
QByteArray body = reply()->readAll();
QByteArray body = reply()->peek(4*1024);
int httpStatus = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if( body.isEmpty() || httpStatus != 200) {
qDebug() << "error: status.php replied " << httpStatus << body;
@@ -472,7 +472,7 @@ bool CheckServerJob::finished()
QVariantMap status = QtJson::parse(QString::fromUtf8(body), success).toMap();
// empty or invalid response
if (!success || status.isEmpty()) {
qDebug() << "status.php from server is not valid JSON!";
qDebug() << "status.php from server is not valid JSON!" << body << reply()->request().url();
}
qDebug() << "status.php returns: " << status << " " << reply()->error() << " Reply: " << reply();
+7 -4
Ver Arquivo
@@ -108,6 +108,11 @@ static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
if (newEntry.isValid()) {
journal->updateErrorBlacklistEntry(newEntry);
// Also clear upload info if any so we don't resume from the same transfer-id if there was too many failures (#5344)
// (maybe the reason is that the state for this transfer id is broken on the server.)
if (newEntry._retryCount > 3) {
journal->setUploadInfo(item._file, SyncJournalDb::UploadInfo());
}
} else if (oldEntry.isValid()) {
journal->wipeErrorBlacklistEntry(item._file);
}
@@ -271,9 +276,7 @@ PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItemPtr &item) {
return job;
} else {
PropagateUploadFileCommon *job = 0;
static const auto chunkng = qgetenv("OWNCLOUD_CHUNKING_NG");
if (item->_size > chunkSize()
&& (account()->capabilities().chunkingNg() || chunkng == "1") && chunkng != "0") {
if (item->_size > chunkSize() && account()->capabilities().chunkingNg()) {
job = new PropagateUploadFileNG(this, item);
} else {
job = new PropagateUploadFileV1(this, item);
@@ -314,7 +317,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
if (!removedDirectory.isEmpty() && item->_file.startsWith(removedDirectory)) {
// this is an item in a directory which is going to be removed.
PropagateDirectory *delDirJob = dynamic_cast<PropagateDirectory*>(directoriesToRemove.first());
PropagateDirectory *delDirJob = qobject_cast<PropagateDirectory*>(directoriesToRemove.first());
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
// already taken care of. (by the removal of the parent directory)
+13 -3
Ver Arquivo
@@ -70,7 +70,9 @@ bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags )
bool SqlDatabase::checkDb()
{
SqlQuery quick_check("PRAGMA quick_check;", *this);
// quick_check can fail with a disk IO error when diskspace is low
SqlQuery quick_check(*this);
quick_check.prepare("PRAGMA quick_check;", /*allow_failure=*/true);
if( !quick_check.exec() ) {
qDebug() << "Error running quick_check on database";
return false;
@@ -97,6 +99,14 @@ bool SqlDatabase::openOrCreateReadWrite( const QString& filename )
}
if( !checkDb() ) {
// When disk space is low, checking the db may fail even though it's fine.
qint64 freeSpace = Utility::freeDiskSpace(filename);
if (freeSpace < 1000000) {
qDebug() << "Consistency check failed, disk space is low, aborting" << freeSpace;
close();
return false;
}
qDebug() << "Consistency check failed, removing broken db" << filename;
close();
QFile::remove(filename);
@@ -191,7 +201,7 @@ SqlQuery::SqlQuery(const QString& sql, SqlDatabase& db)
prepare(sql);
}
int SqlQuery::prepare( const QString& sql)
int SqlQuery::prepare( const QString& sql, bool allow_failure )
{
QString s(sql);
_sql = s.trimmed();
@@ -213,7 +223,7 @@ int SqlQuery::prepare( const QString& sql)
if( _errId != SQLITE_OK ) {
_error = QString::fromUtf8(sqlite3_errmsg(_db));
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
Q_ASSERT(!"SQLITE Prepare error");
Q_ASSERT(allow_failure || !"SQLITE Prepare error");
}
}
return _errId;
+1 -1
Ver Arquivo
@@ -80,7 +80,7 @@ public:
bool isSelect();
bool isPragma();
bool exec();
int prepare( const QString& sql );
int prepare( const QString& sql, bool allow_failure = false );
bool next();
void bindValue(int pos, const QVariant& value);
QString lastQuery() const;
+6 -2
Ver Arquivo
@@ -145,8 +145,12 @@ void ProgressInfo::reset()
_sizeProgress = Progress();
_fileProgress = Progress();
_totalSizeOfCompletedJobs = 0;
_maxBytesPerSecond = 100000.0;
_maxFilesPerSecond = 2.0;
// Historically, these starting estimates were way lower, but that lead
// to gross overestimation of ETA when a good estimate wasn't available.
_maxBytesPerSecond = 2000000.0; // 2 MB/s
_maxFilesPerSecond = 10.0;
_updateEstimatesTimer.stop();
_lastCompletedItem = SyncFileItem();
}
+2 -2
Ver Arquivo
@@ -401,7 +401,7 @@ void PropagateDownloadFile::start()
// Normal job, download from oC instance
_job = new GETFileJob(_propagator->account(),
_propagator->_remoteFolder + _item->_file,
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
} else {
// We were provided a direct URL, use that one
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item->_file << _item->_directDownloadUrl;
@@ -413,7 +413,7 @@ void PropagateDownloadFile::start()
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
_job = new GETFileJob(_propagator->account(),
url,
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
}
_job->setBandwidthManager(&_propagator->_bandwidthManager);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
+4 -6
Ver Arquivo
@@ -38,7 +38,7 @@ namespace OCC {
QUrl PropagateUploadFileNG::chunkUrl(int chunk)
{
QString path = QLatin1String("remote.php/dav/uploads/")
+ _propagator->account()->user()
+ _propagator->account()->davUser()
+ QLatin1Char('/') + QString::number(_transferId);
if (chunk >= 0) {
path += QLatin1Char('/') + QString::number(chunk);
@@ -268,10 +268,8 @@ void PropagateUploadFileNG::startNextChunk()
Q_ASSERT(_jobs.isEmpty()); // There should be no running job anymore
_finished = true;
// Finish with a MOVE
QString destination = _propagator->account()->url().path()
+ QLatin1String("/remote.php/dav/files/") + _propagator->account()->user()
+ _propagator->_remoteFolder + _item->_file;
QString destination = QDir::cleanPath(_propagator->account()->url().path() + QLatin1Char('/')
+ _propagator->account()->davPath() + _propagator->_remoteFolder + _item->_file);
auto headers = PropagateUploadFileCommon::headers();
// "If-Match applies to the source, but we are interested in comparing the etag of the destination
@@ -317,7 +315,7 @@ void PropagateUploadFileNG::startNextChunk()
QUrl url = chunkUrl(_currentChunk);
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk);
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk, this);
_jobs.append(job);
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)),
+16 -9
Ver Arquivo
@@ -123,7 +123,7 @@ void PropagateUploadFileV1::startNextChunk()
}
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk, this);
_jobs.append(job);
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
@@ -134,18 +134,25 @@ void PropagateUploadFileV1::startNextChunk()
_currentChunk++;
bool parallelChunkUpload = true;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
if (!env.isEmpty()) {
parallelChunkUpload = env != "false" && env != "0";
if (_propagator->account()->capabilities().chunkingParallelUploadDisabled()) {
// Server may also disable parallel chunked upload for any higher version
parallelChunkUpload = false;
} else {
int versionNum = _propagator->account()->serverVersionInt();
if (versionNum < 0x080003) {
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
// internal sever errors (#2743, #2938)
parallelChunkUpload = false;
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
if (!env.isEmpty()) {
parallelChunkUpload = env != "false" && env != "0";
} else {
int versionNum = _propagator->account()->serverVersionInt();
if (versionNum < 0x080003) {
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
// internal sever errors (#2743, #2938)
parallelChunkUpload = false;
}
}
}
if (_currentChunk + _startChunk >= _chunkCount - 1) {
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
// https://github.com/owncloud/core/issues/11106
+11 -5
Ver Arquivo
@@ -73,11 +73,13 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
, _downloadLimit(0)
, _newBigFolderSizeLimit(-1)
, _checksum_hook(journal)
, _anotherSyncNeeded(false)
, _anotherSyncNeeded(NoFollowUpSync)
{
qRegisterMetaType<SyncFileItem>("SyncFileItem");
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
// Everything in the SyncEngine expects a trailing slash for the localPath.
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
@@ -693,12 +695,13 @@ void SyncEngine::startSync()
Q_ASSERT(!_syncRunning);
s_anySyncRunning = true;
_syncRunning = true;
_anotherSyncNeeded = false;
_anotherSyncNeeded = NoFollowUpSync;
_clearTouchedFilesTimer.stop();
_progressInfo->reset();
if (!QDir(_localPath).exists()) {
_anotherSyncNeeded = DelayedFollowUp;
// No _tr, it should only occur in non-mirall
emit csyncError("Unable to find local sync folder.");
finalize(false);
@@ -712,6 +715,7 @@ void SyncEngine::startSync()
qDebug() << "There are" << freeBytes << "bytes available at" << _localPath
<< "and at least" << minFree << "are required";
if (freeBytes < minFree) {
_anotherSyncNeeded = DelayedFollowUp;
emit csyncError(tr("Only %1 are available, need at least %2 to start",
"Placeholders are postfixed with file sizes using Utility::octetsToString()").arg(
Utility::octetsToString(freeBytes),
@@ -1048,7 +1052,9 @@ void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob
void SyncEngine::slotFinished(bool success)
{
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
if (_propagator->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
_anotherSyncNeeded = ImmediateFollowUp;
}
if (success) {
_journal->setDataFingerprint(_discoveryMainThread->_dataFingerprint);
@@ -1171,7 +1177,7 @@ void SyncEngine::checkForPermission()
// be restored. Do that in the next sync by not considering as a rename
// but delete and upload. It will then be restored if needed.
_journal->avoidRenamesOnNextSync((*it)->_file);
_anotherSyncNeeded = true;
_anotherSyncNeeded = ImmediateFollowUp;
qDebug() << "Moving of " << (*it)->_file << " canceled because no permission to add parent folder";
}
(*it)->_instruction = CSYNC_INSTRUCTION_ERROR;
@@ -1328,7 +1334,7 @@ void SyncEngine::checkForPermission()
// At this point we would need to go back to the propagate phase on both remote to take
// the decision.
_journal->avoidRenamesOnNextSync((*it)->_file);
_anotherSyncNeeded = true;
_anotherSyncNeeded = ImmediateFollowUp;
if ((*it)->_isDirectory) {
+10 -3
Ver Arquivo
@@ -49,6 +49,13 @@ class SyncJournalDb;
class OwncloudPropagator;
class PropagatorJob;
enum AnotherSyncNeeded
{
NoFollowUpSync,
ImmediateFollowUp, // schedule this again immediately (limited amount of times)
DelayedFollowUp // regularly schedule this folder again (around 1/minute, unlimited)
};
/**
* @brief The SyncEngine class
* @ingroup libsync
@@ -82,8 +89,8 @@ public:
Utility::StopWatch &stopWatch() { return _stopWatch; }
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
/* Return true if we detected that another sync is needed to complete the sync */
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
/* Returns whether another sync is needed to complete the sync */
AnotherSyncNeeded isAnotherSyncNeeded() { return _anotherSyncNeeded; }
/** Get the ms since a file was touched, or -1 if it wasn't.
*
@@ -259,7 +266,7 @@ private:
/// Hook for computing checksums from csync_update
CSyncChecksumHook _checksum_hook;
bool _anotherSyncNeeded;
AnotherSyncNeeded _anotherSyncNeeded;
/** Stores the time since a job touched a file. */
QHash<QString, QElapsedTimer> _touchedFiles;
+1 -1
Ver Arquivo
@@ -138,7 +138,7 @@ public:
QString _file;
QString _renameTarget;
Type _type BITFIELD(3);
Direction _direction BITFIELD(2);
Direction _direction BITFIELD(3);
bool _isDirectory BITFIELD(1);
bool _serverHasIgnoredFiles BITFIELD(1);
+1
Ver Arquivo
@@ -131,6 +131,7 @@ SyncJournalErrorBlacklistRecord SyncJournalErrorBlacklistRecord::update(
bool mayBlacklist =
item._errorMayBeBlacklisted // explicitly flagged for blacklisting
|| (item._httpErrorCode != 0 // or non-local error
&& item._httpErrorCode != 507 // Don't blacklist "Insufficient Storage"
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
&& item._httpErrorCode / 100 != 5 // In this configuration, never blacklist error 5xx
#endif
+1 -1
Ver Arquivo
@@ -23,7 +23,7 @@ using namespace OCC;
class HttpCredentialsTest : public HttpCredentials {
public:
HttpCredentialsTest(const QString& user, const QString& password)
: HttpCredentials(user, password, "", "")
: HttpCredentials(user, password)
{}
void askFromUser() Q_DECL_OVERRIDE {
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais