From eef0ba60200d8039c05073ce707c2352ac0944a8 Mon Sep 17 00:00:00 2001
From: Pierre Rossi <pierre.rossi@digia.com>
Date: Wed, 3 Sep 2014 17:25:07 +0200
Subject: [PATCH] Don't spin a nested event loop for loading schemas
 synchronously over HTTP.

Instead, use the internal synchronous load API in QNAM that relies on a
separate thread with a blocking queued connection, just like QtWebKit
does for synchronous XHR. FTP doesn't support this attribute, so we have
to keep the event loop trick for that one.

Change-Id: I785fa6d967160552b31778fcfc120d7ec4194a08
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
---
 .../acceltree/qacceltreeresourceloader.cpp    | 20 ++++++-----
 .../acceltree/qacceltreeresourceloader_p.h    | 34 -------------------
 2 files changed, 12 insertions(+), 42 deletions(-)

diff --git a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
index 7c877c62..85ea41ab 100644
--- a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
+++ b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
@@ -110,15 +110,20 @@ QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri,
     Q_ASSERT(networkManager);
     Q_ASSERT(uri.isValid());
 
-    NetworkLoop networkLoop;
-
+    const bool ftpSchemeUsed = (uri.scheme() == QStringLiteral("ftp"));
+    // QNAM doesn't have support for SynchronousRequestAttribute in its ftp backend.
+    QEventLoop ftpNetworkLoop;
     QNetworkRequest request(uri);
+    if (!ftpSchemeUsed)
+        request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
     QNetworkReply *const reply = networkManager->get(request);
-    networkLoop.connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(error(QNetworkReply::NetworkError)));
-    networkLoop.connect(reply, SIGNAL(finished()), SLOT(finished()));
+    if (ftpSchemeUsed) {
+        ftpNetworkLoop.connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(quit()));
+        ftpNetworkLoop.connect(reply, SIGNAL(finished()), SLOT(quit()));
+        ftpNetworkLoop.exec(QEventLoop::ExcludeUserInputEvents);
+    }
 
-    if(networkLoop.exec(QEventLoop::ExcludeUserInputEvents))
-    {
+    if (reply->error() != QNetworkReply::NoError) {
         const QString errorMessage(escape(reply->errorString()));
 
         /* Note, we delete reply before we exit this function with error(). */
@@ -130,8 +135,7 @@ QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri,
             context->error(errorMessage, ReportContext::FODC0002, location);
 
         return 0;
-    }
-    else
+    } else
         return reply;
 }
 
diff --git a/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h b/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h
index 0adc8c82..7ac43896 100644
--- a/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h
+++ b/src/xmlpatterns/acceltree/qacceltreeresourceloader_p.h
@@ -61,40 +61,6 @@ class QIODevice;
 
 namespace QPatternist
 {
-    /**
-     * @short An helper class which enables QNetworkAccessManager
-     * to be used in a blocking manner.
-     *
-     * @see AccelTreeResourceLoader::load()
-     * @author Frans Englich <frans.englich@nokia.com>
-     */
-    class NetworkLoop : public QEventLoop
-    {
-        Q_OBJECT
-    public:
-        NetworkLoop() : m_hasReceivedError(false)
-        {
-        }
-
-    public Q_SLOTS:
-        void error(QNetworkReply::NetworkError code)
-        {
-            Q_UNUSED(code);
-            m_hasReceivedError = true;
-            exit(1);
-        }
-
-        void finished()
-        {
-            if(m_hasReceivedError)
-                exit(1);
-            else
-                exit(0);
-        }
-    private:
-        bool m_hasReceivedError;
-    };
-
     /**
      * @short Handles requests for documents, and instantiates
      * them as AccelTree instances.
-- 
GitLab