summaryrefslogtreecommitdiffstats
path: root/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
diff options
context:
space:
mode:
authorSzabolcs David <davidsz@inf.u-szeged.hu>2021-02-04 14:48:52 +0100
committerSzabolcs David <davidsz@inf.u-szeged.hu>2021-03-06 08:28:04 +0100
commit8f56ea6806d9a72d4b705da5f6f90fa5a6873567 (patch)
treed4f5d01cde73e34973990ae5a5f3cb271516db15 /src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
parent84104b7d100553c1550c525759ef6fb4446c31be (diff)
Show PDF viewer in a guest view
This is the basic support of guest views, implemented based on Chrome. - Embed PDF as a child frame instead of navigating to its extension WebUI. Keep the original URL (pointing to the file) to extend functionality of PDF viewer with URL parameters. - Make RenderWidgetHostInputEventRouter to work and modify most of the event forwarding logic to use that. This way WebEngine supports pages with multiple RenderWidgetHost and guest views can be interactive with user input. [ChangeLog] PDF files are opened as embedded objects, WebEngine will not navigate the content away from the requested file to present it. PDF viewer can accept URL parameters (e.g. to control zooming or fitting to view). Also, PDF viewer is interactive when displayed in a subframe. Task-number: QTBUG-80463 Task-number: QTBUG-86152 Task-number: QTBUG-90712 Change-Id: Ib1591fbd9a594891cdeace8e9dae0d3cc21a9f8e Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/core/net/plugin_response_interceptor_url_loader_throttle.cpp')
-rw-r--r--src/core/net/plugin_response_interceptor_url_loader_throttle.cpp151
1 files changed, 101 insertions, 50 deletions
diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
index bd03d3083..326bdabb1 100644
--- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
+++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
@@ -40,27 +40,50 @@
#include "plugin_response_interceptor_url_loader_throttle.h"
#include "base/bind.h"
+#include "base/guid.h"
#include "base/task/post_task.h"
+#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/download_utils.h"
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handlers/mime_types_handler.h"
+#include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
+#include "extensions/extension_system_qt.h"
#include "web_contents_delegate_qt.h"
#include <string>
namespace QtWebEngineCore {
-void onPdfStreamIntercepted(const GURL &original_url, std::string extension_id, int frame_tree_node_id)
+PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle(
+ content::BrowserContext *browser_context, int resource_type, int frame_tree_node_id)
+ : m_browser_context(browser_context), m_resource_type(resource_type), m_frame_tree_node_id(frame_tree_node_id)
+{}
+
+void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL &response_url,
+ network::mojom::URLResponseHead *response_head,
+ bool *defer)
{
- content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (content::download_utils::MustDownload(response_url, response_head->headers.get(), response_head->mime_type))
+ return;
+
+ content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(m_frame_tree_node_id);
if (!web_contents)
return;
+ std::string extension_id;
+ if (response_head->mime_type == "application/pdf")
+ extension_id = extension_misc::kPdfExtensionId;
+ if (extension_id.empty())
+ return;
+
WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate());
if (!contentsDelegate)
return;
@@ -71,62 +94,90 @@ void onPdfStreamIntercepted(const GURL &original_url, std::string extension_id,
// If the applications has been set up to always download PDF files to open them in an
// external viewer, trigger the download.
std::unique_ptr<download::DownloadUrlParameters> params(
- content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(web_contents, original_url,
+ content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(web_contents, response_url,
MISSING_TRAFFIC_ANNOTATION));
content::BrowserContext::GetDownloadManager(web_contents->GetBrowserContext())->DownloadUrl(std::move(params));
return;
}
- // The URL passes the original pdf resource url, that will be requested
- // by the pdf viewer extension page.
- content::NavigationController::LoadURLParams params(
- GURL(base::StringPrintf("%s://%s/index.html?%s", extensions::kExtensionScheme,
- extension_id.c_str(), original_url.spec().c_str())));
-
- params.frame_tree_node_id = frame_tree_node_id;
- web_contents->GetController().LoadURLWithParams(params);
-}
-
-
-PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle(
- content::ResourceContext *resource_context, int resource_type, int frame_tree_node_id)
- : m_resource_context(resource_context), m_resource_type(resource_type), m_frame_tree_node_id(frame_tree_node_id)
-{}
-
-PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle(
- content::BrowserContext *browser_context, int resource_type, int frame_tree_node_id)
- : m_browser_context(browser_context), m_resource_type(resource_type), m_frame_tree_node_id(frame_tree_node_id)
-{}
-
-void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL &response_url,
- network::mojom::URLResponseHead *response_head,
- bool *defer)
-{
- Q_UNUSED(defer);
- if (content::download_utils::MustDownload(response_url, response_head->headers.get(), response_head->mime_type))
- return;
-
- if (m_resource_context) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- } else {
- DCHECK(m_browser_context);
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Chrome's PDF Extension does not work properly in the face of a restrictive
+ // Content-Security-Policy, and does not currently respect the policy anyway.
+ // Ignore CSP served on a PDF response. https://crbug.com/271452
+ if (extension_id == extension_misc::kPdfExtensionId && response_head->headers)
+ response_head->headers->RemoveHeader("Content-Security-Policy");
+
+ MimeTypesHandler::ReportUsedHandler(extension_id);
+
+ std::string view_id = base::GenerateGUID();
+ // The string passed down to the original client with the response body.
+ std::string payload = view_id;
+
+ mojo::PendingRemote<network::mojom::URLLoader> dummy_new_loader;
+ ignore_result(dummy_new_loader.InitWithNewPipeAndPassReceiver());
+ mojo::Remote<network::mojom::URLLoaderClient> new_client;
+ mojo::PendingReceiver<network::mojom::URLLoaderClient> new_client_receiver =
+ new_client.BindNewPipeAndPassReceiver();
+
+
+ uint32_t data_pipe_size = 64U;
+ // Provide the MimeHandlerView code a chance to override the payload. This is
+ // the case where the resource is handled by frame-based MimeHandlerView.
+ *defer = extensions::MimeHandlerViewAttachHelper::OverrideBodyForInterceptedResponse(
+ m_frame_tree_node_id, response_url, response_head->mime_type, view_id,
+ &payload, &data_pipe_size,
+ base::BindOnce(
+ &PluginResponseInterceptorURLLoaderThrottle::ResumeLoad,
+ weak_factory_.GetWeakPtr()));
+
+ mojo::DataPipe data_pipe(data_pipe_size);
+ uint32_t len = static_cast<uint32_t>(payload.size());
+ CHECK_EQ(MOJO_RESULT_OK,
+ data_pipe.producer_handle->WriteData(
+ payload.c_str(), &len, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
+
+
+ new_client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
+
+ network::URLLoaderCompletionStatus status(net::OK);
+ status.decoded_body_length = len;
+ new_client->OnComplete(status);
+
+ mojo::PendingRemote<network::mojom::URLLoader> original_loader;
+ mojo::PendingReceiver<network::mojom::URLLoaderClient> original_client;
+ delegate_->InterceptResponse(std::move(dummy_new_loader),
+ std::move(new_client_receiver), &original_loader,
+ &original_client);
+
+ // Make a deep copy of URLResponseHead before passing it cross-thread.
+ auto deep_copied_response = response_head->Clone();
+ if (response_head->headers) {
+ deep_copied_response->headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(
+ response_head->headers->raw_headers());
}
- std::string extension_id;
- // FIXME: We should use extensions::InfoMap in the future:
- if (response_head->mime_type == "application/pdf")
- extension_id = extension_misc::kPdfExtensionId;
- if (extension_id.empty())
- return;
-
- *defer = true;
+ auto transferrable_loader = blink::mojom::TransferrableURLLoader::New();
+ transferrable_loader->url = GURL(
+ extensions::Extension::GetBaseURLFromExtensionId(extension_id).spec() +
+ base::GenerateGUID());
+ transferrable_loader->url_loader = std::move(original_loader);
+ transferrable_loader->url_loader_client = std::move(original_client);
+ transferrable_loader->head = std::move(deep_copied_response);
+ transferrable_loader->head->intercepted_by_plugin = true;
+
+ bool embedded = m_resource_type !=
+ static_cast<int>(blink::mojom::ResourceType::kMainFrame);
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &extensions::StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent,
+ extension_id, view_id, embedded, m_frame_tree_node_id,
+ -1 /* render_process_id */, -1 /* render_frame_id */,
+ std::move(transferrable_loader), response_url));
+}
- base::PostTask(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&onPdfStreamIntercepted,
- response_url,
- extension_id,
- m_frame_tree_node_id));
+void PluginResponseInterceptorURLLoaderThrottle::ResumeLoad() {
+ delegate_->Resume();
}
} // namespace QtWebEngineCore