From 0828a05dfbc3babb8719b984145027f677ce9686 Mon Sep 17 00:00:00 2001
From: Allan Sandfeld Jensen <allan.jensen@qt.io>
Date: Mon, 25 Mar 2019 13:51:14 +0100
Subject: [PATCH] Switch DevTools.loadNetworkResource to using SimpleURLLoader
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Follow similar Chromium changes.

Change-Id: Idb0ab52517004c8bee7e7f7a919233b3f1b3ff59
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
---
 src/core/devtools_frontend_qt.cpp | 160 +++++++++++++++---------------
 src/core/devtools_frontend_qt.h   |  15 ++-
 2 files changed, 88 insertions(+), 87 deletions(-)

diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp
index 4531f80a8..9eedee42a 100644
--- a/src/core/devtools_frontend_qt.cpp
+++ b/src/core/devtools_frontend_qt.cpp
@@ -48,6 +48,7 @@
 #include "profile_qt.h"
 #include "web_contents_adapter.h"
 
+#include "base/base64.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/json/string_escape.h"
@@ -73,12 +74,10 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
 #include "ipc/ipc_channel.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_response_writer.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
 
 #include <QDebug>
 using namespace QtWebEngineCore;
@@ -103,66 +102,77 @@ std::unique_ptr<base::DictionaryValue> BuildObjectForResponse(const net::HttpRes
     return response;
 }
 
-// ResponseWriter -------------------------------------------------------------
-
-class ResponseWriter : public net::URLFetcherResponseWriter {
-public:
-    ResponseWriter(base::WeakPtr<DevToolsFrontendQt> shell_devtools_, int stream_id);
-    ~ResponseWriter() override;
-
-    // URLFetcherResponseWriter overrides:
-    int Initialize(net::CompletionOnceCallback callback) override;
-    int Write(net::IOBuffer *buffer, int num_bytes, net::CompletionOnceCallback callback) override;
-    int Finish(int net_error, net::CompletionOnceCallback callback) override;
+static std::string GetFrontendURL()
+{
+    return "chrome-devtools://devtools/bundled/devtools_app.html";
+}
 
-private:
-    base::WeakPtr<DevToolsFrontendQt> shell_devtools_;
-    int stream_id_;
+}  // namespace
 
-    DISALLOW_COPY_AND_ASSIGN(ResponseWriter);
-};
+namespace QtWebEngineCore {
 
-ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsFrontendQt> shell_devtools, int stream_id)
-        : shell_devtools_(shell_devtools), stream_id_(stream_id)
-{}
+class DevToolsFrontendQt::NetworkResourceLoader
+        : public network::SimpleURLLoaderStreamConsumer {
+public:
+    NetworkResourceLoader(int stream_id,
+                          int request_id,
+                          DevToolsFrontendQt *bindings,
+                          std::unique_ptr<network::SimpleURLLoader> loader,
+                          network::mojom::URLLoaderFactory *url_loader_factory)
+        : stream_id_(stream_id),
+          request_id_(request_id),
+          bindings_(bindings),
+          loader_(std::move(loader))
+    {
+        loader_->SetOnResponseStartedCallback(base::BindOnce(
+                                                  &NetworkResourceLoader::OnResponseStarted, base::Unretained(this)));
+        loader_->DownloadAsStream(url_loader_factory, this);
+    }
 
-ResponseWriter::~ResponseWriter() {}
+private:
+    void OnResponseStarted(const GURL &final_url,
+                           const network::ResourceResponseHead &response_head)
+    {
+        response_headers_ = response_head.headers;
+    }
 
-int ResponseWriter::Initialize(net::CompletionOnceCallback callback)
-{
-    return net::OK;
-}
+    void OnDataReceived(base::StringPiece chunk, base::OnceClosure resume) override
+    {
+        base::Value chunkValue;
+
+        bool encoded = !base::IsStringUTF8(chunk);
+        if (encoded) {
+            std::string encoded_string;
+            base::Base64Encode(chunk, &encoded_string);
+            chunkValue = base::Value(std::move(encoded_string));
+        } else {
+            chunkValue = base::Value(chunk);
+        }
+        base::Value id(stream_id_);
+        base::Value encodedValue(encoded);
 
-int ResponseWriter::Write(net::IOBuffer *buffer, int num_bytes, net::CompletionOnceCallback callback)
-{
-    std::string chunk = std::string(buffer->data(), num_bytes);
-    if (!base::IsStringUTF8(chunk))
-        return num_bytes;
-
-    base::Value *id = new base::Value(stream_id_);
-    base::Value *chunkValue = new base::Value(chunk);
-
-    base::PostTaskWithTraits(
-                FROM_HERE, {content::BrowserThread::UI},
-                base::BindOnce(&DevToolsFrontendQt::CallClientFunction,
-                               shell_devtools_, "DevToolsAPI.streamWrite",
-                               base::Owned(id), base::Owned(chunkValue), nullptr));
-    return num_bytes;
-}
+        bindings_->CallClientFunction("DevToolsAPI.streamWrite", &id, &chunkValue, &encodedValue);
+        std::move(resume).Run();
+    }
 
-int ResponseWriter::Finish(int net_error, net::CompletionOnceCallback callback)
-{
-    return net::OK;
-}
+    void OnComplete(bool success) override
+    {
+        Q_UNUSED(success);
+        auto response = BuildObjectForResponse(response_headers_.get());
+        bindings_->SendMessageAck(request_id_, response.get());
+        bindings_->m_loaders.erase(bindings_->m_loaders.find(this));
+    }
 
-static std::string GetFrontendURL()
-{
-    return "chrome-devtools://devtools/bundled/devtools_app.html";
-}
+    void OnRetry(base::OnceClosure start_retry) override { NOTREACHED(); }
 
-}  // namespace
+    const int stream_id_;
+    const int request_id_;
+    DevToolsFrontendQt *const bindings_;
+    std::unique_ptr<network::SimpleURLLoader> loader_;
+    scoped_refptr<net::HttpResponseHeaders> response_headers_;
 
-namespace QtWebEngineCore {
+    DISALLOW_COPY_AND_ASSIGN(NetworkResourceLoader);
+};
 
 // This constant should be in sync with
 // the constant at devtools_ui_bindings.cc.
@@ -222,8 +232,6 @@ DevToolsFrontendQt::DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webCon
 
 DevToolsFrontendQt::~DevToolsFrontendQt()
 {
-    for (const auto &pair : m_pendingRequests)
-        delete pair.first;
 }
 
 void DevToolsFrontendQt::Activate()
@@ -406,14 +414,23 @@ void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(const std::string &me
                     }
                   }
                 })");
-        net::URLFetcher *fetcher = net::URLFetcher::Create(gurl, net::URLFetcher::GET, this, traffic_annotation).release();
-        m_pendingRequests[fetcher] = request_id;
-        fetcher->SetRequestContext(content::BrowserContext::GetDefaultStoragePartition(
-                                       web_contents()->GetBrowserContext())->GetURLRequestContext());
-        fetcher->SetExtraRequestHeaders(headers);
-        fetcher->SaveResponseWithWriter(std::unique_ptr<net::URLFetcherResponseWriter>(
-                                            new ResponseWriter(m_weakFactory.GetWeakPtr(), stream_id)));
-        fetcher->Start();
+        auto resource_request = std::make_unique<network::ResourceRequest>();
+        resource_request->url = gurl;
+        // TODO(caseq): this preserves behavior of URLFetcher-based implementation.
+        // We really need to pass proper first party origin from the front-end.
+        resource_request->site_for_cookies = gurl;
+        resource_request->headers.AddHeadersFromString(headers);
+
+        auto *partition = content::BrowserContext::GetStoragePartitionForSite(
+                    web_contents()->GetBrowserContext(), gurl);
+        auto factory = partition->GetURLLoaderFactoryForBrowserProcess();
+
+        auto simple_url_loader = network::SimpleURLLoader::Create(
+                    std::move(resource_request), traffic_annotation);
+        auto resource_loader = std::make_unique<NetworkResourceLoader>(
+                    stream_id, request_id, this, std::move(simple_url_loader),
+                    factory.get());
+        m_loaders.insert(std::move(resource_loader));
         return;
     } else if (method == "getPreferences") {
         m_preferences = std::move(*m_prefStore->GetValues());
@@ -493,21 +510,6 @@ void DevToolsFrontendQt::DispatchProtocolMessage(content::DevToolsAgentHost *age
     }
 }
 
-void DevToolsFrontendQt::OnURLFetchComplete(const net::URLFetcher *source)
-{
-    // TODO(pfeldman): this is a copy of chrome's devtools_ui_bindings.cc.
-    // We should handle some of the commands including this one in content.
-    DCHECK(source);
-    PendingRequestsMap::iterator it = m_pendingRequests.find(source);
-    DCHECK(it != m_pendingRequests.end());
-
-    auto response = BuildObjectForResponse(source->GetResponseHeaders());
-
-    SendMessageAck(it->second, response.get());
-    m_pendingRequests.erase(it);
-    delete source;
-}
-
 void DevToolsFrontendQt::CallClientFunction(const std::string &function_name,
                                             const base::Value *arg1,
                                             const base::Value *arg2,
diff --git a/src/core/devtools_frontend_qt.h b/src/core/devtools_frontend_qt.h
index 88cc7aeac..fed2d47fc 100644
--- a/src/core/devtools_frontend_qt.h
+++ b/src/core/devtools_frontend_qt.h
@@ -41,10 +41,12 @@
 #define DEVTOOLS_FRONTEND_QT_H
 
 #include <memory>
+#include <set>
 
 #include "web_contents_delegate_qt.h"
 
 #include "base/compiler_specific.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -52,7 +54,6 @@
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_frontend_host.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "net/url_request/url_fetcher_delegate.h"
 
 namespace base {
 class Value;
@@ -69,8 +70,7 @@ class PersistentPrefStore;
 namespace QtWebEngineCore {
 
 class DevToolsFrontendQt : public content::WebContentsObserver
-                         , public content::DevToolsAgentHostClient
-                         , public net::URLFetcherDelegate {
+                         , public content::DevToolsAgentHostClient {
 public:
     static DevToolsFrontendQt *Show(QSharedPointer<WebContentsAdapter> frontendAdapter, content::WebContents *inspectedContents);
 
@@ -108,9 +108,6 @@ private:
     void DocumentAvailableInMainFrame() override;
     void WebContentsDestroyed() override;
 
-    // net::URLFetcherDelegate overrides.
-    void OnURLFetchComplete(const net::URLFetcher* source) override;
-
     void SendMessageAck(int request_id, const base::Value* arg1);
     void SetPreference(const std::string &name, const std::string &value);
     void RemovePreference(const std::string &name);
@@ -125,8 +122,10 @@ private:
     int m_inspect_element_at_x;
     int m_inspect_element_at_y;
     std::unique_ptr<content::DevToolsFrontendHost> m_frontendHost;
-    using PendingRequestsMap = std::map<const net::URLFetcher*, int>;
-    PendingRequestsMap m_pendingRequests;
+
+    class NetworkResourceLoader;
+    std::set<std::unique_ptr<NetworkResourceLoader>, base::UniquePtrComparator> m_loaders;
+
     base::DictionaryValue m_preferences;
     scoped_refptr<PersistentPrefStore> m_prefStore;
     base::WeakPtrFactory<DevToolsFrontendQt> m_weakFactory;
-- 
GitLab