blob: a8aad24e7bf911a715cd6c90ace12c4eba5ff0bd [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
danakjc492bf82020-09-09 20:02:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_
6#define CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_
7
8#include <map>
9#include <memory>
Arthur Sonzognic686e8f2024-01-11 08:36:3710#include <optional>
danakjc492bf82020-09-09 20:02:4411#include <string>
12#include <vector>
13
Avi Drissmanadac21992023-01-11 23:46:3914#include "base/functional/callback_forward.h"
Daniel Chengd4c3eab2021-08-31 18:39:0115#include "base/gtest_prod_util.h"
danakjc492bf82020-09-09 20:02:4416#include "base/memory/weak_ptr.h"
danakjc492bf82020-09-09 20:02:4417#include "base/time/time.h"
18#include "build/build_config.h"
19#include "content/browser/renderer_host/render_frame_host_impl.h"
20#include "content/common/content_export.h"
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:1021#include "content/public/browser/clipboard_types.h"
Daniel Cheng9fb887ff2021-10-01 20:27:3822#include "content/public/browser/document_service.h"
Austin Sullivanfc870892021-04-29 18:40:1123#include "mojo/public/cpp/base/big_buffer.h"
danakjc492bf82020-09-09 20:02:4424#include "mojo/public/cpp/bindings/receiver.h"
danakjc492bf82020-09-09 20:02:4425#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
26#include "ui/base/clipboard/clipboard.h"
27
28class GURL;
29
30namespace ui {
31class ScopedClipboardWriter;
32} // namespace ui
33
34namespace content {
35
36class ClipboardHostImplTest;
37
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:2438// Returns a representation of the last source ClipboardEndpoint. This will
39// either match the last clipboard write if `seqno` matches the last browser tab
40// write, or an endpoint built from `Clipboard::GetSource()` called with
41// `clipboard_buffer` otherwise.
42//
43// //content maintains additional metadata on top of what the //ui layer already
44// tracks about clipboard data's source, e.g. the WebContents that provided the
45// data. This function allows retrieving both the //ui metadata and the
46// //content metadata in a single call.
47//
48// To avoid returning stale //content metadata if the writer has changed, the
49// sequence number is used to validate if the writer has changed or not since
50// the //content metadata was last updated.
51CONTENT_EXPORT ClipboardEndpoint
52GetSourceClipboardEndpoint(ui::ClipboardSequenceNumberToken seqno,
53 ui::ClipboardBuffer clipboard_buffer);
54
Alexander Timine3383d02021-06-24 19:57:5955class CONTENT_EXPORT ClipboardHostImpl
Daniel Cheng9fb887ff2021-10-01 20:27:3856 : public DocumentService<blink::mojom::ClipboardHost> {
danakjc492bf82020-09-09 20:02:4457 public:
58 ~ClipboardHostImpl() override;
59
60 static void Create(
61 RenderFrameHost* render_frame_host,
62 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
63
Nancy Xiao4f3eae5d62023-04-25 19:38:5964 using ClipboardPasteData = content::ClipboardPasteData;
65
danakjc492bf82020-09-09 20:02:4466 protected:
67 // These types and methods are protected for testing.
68
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5869 using IsClipboardPasteAllowedCallback =
70 RenderFrameHostImpl::IsClipboardPasteAllowedCallback;
danakjc492bf82020-09-09 20:02:4471
Roger Tawac6170262022-10-28 23:48:5272 // Represents the underlying type of the argument passed to
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5873 // IsClipboardPasteAllowedCallback without the const& part.
74 using IsClipboardPasteAllowedCallbackArgType =
Arthur Sonzognic686e8f2024-01-11 08:36:3775 std::optional<ClipboardPasteData>;
Roger Tawac6170262022-10-28 23:48:5276
danakjc492bf82020-09-09 20:02:4477 // Keeps track of a request to see if some clipboard content, identified by
Rakina Zata Amni39d8e7e2022-10-20 18:18:3078 // its sequence number, is allowed to be pasted into the RenderFrameHost
danakjc492bf82020-09-09 20:02:4479 // that owns this clipboard host.
80 //
81 // A request starts in the state incomplete until Complete() is called with
82 // a value. Callbacks can be added to the request before or after it has
83 // completed.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5884 class CONTENT_EXPORT IsPasteAllowedRequest {
danakjc492bf82020-09-09 20:02:4485 public:
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5886 IsPasteAllowedRequest();
87 ~IsPasteAllowedRequest();
danakjc492bf82020-09-09 20:02:4488
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:4189 // Adds `callback` to be notified when the request completes. Returns true
90 // if this is the first callback added and a request should be started,
91 // returns false otherwise.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5892 bool AddCallback(IsClipboardPasteAllowedCallback callback);
danakjc492bf82020-09-09 20:02:4493
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:4194 // Merge `data` into the existing internal `data_` member so that the
95 // currently pending request will have the appropriate fields for all added
96 // callbacks, not just the initial one that created the request.
97 void AddData(ClipboardPasteData data);
98
danakjc492bf82020-09-09 20:02:4499 // Mark this request as completed with the specified result.
100 // Invoke all callbacks now.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58101 void Complete(IsClipboardPasteAllowedCallbackArgType data);
danakjc492bf82020-09-09 20:02:44102
Roger Tawa34dd57f82022-12-15 23:24:20103 // Returns true if the request has completed.
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41104 bool is_complete() const { return data_allowed_.has_value(); }
Roger Tawa34dd57f82022-12-15 23:24:20105
danakjc492bf82020-09-09 20:02:44106 // Returns true if this request is obsolete. An obsolete request
107 // is one that is completed, all registered callbacks have been
108 // called, and is considered old.
109 //
110 // |now| represents the current time. It is an argument to ease testing.
111 bool IsObsolete(base::Time now);
112
Roger Tawa34dd57f82022-12-15 23:24:20113 // Returns the time at which this request was completed. If called
114 // before the request is completed the return value is undefined.
115 base::Time completed_time();
danakjc492bf82020-09-09 20:02:44116
117 private:
118 // Calls all the callbacks in |callbacks_| with the current value of
119 // |allowed_|. |allowed_| must not be empty.
120 void InvokeCallbacks();
121
Roger Tawa34dd57f82022-12-15 23:24:20122 // The time at which the request was completed. Before completion this
123 // value is undefined.
124 base::Time completed_time_;
Roger Tawac6170262022-10-28 23:48:52125
Roger Tawac6170262022-10-28 23:48:52126 // This member is null until Complete() is called.
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41127 std::optional<bool> data_allowed_;
128
129 // The data argument to pass to the IsClipboardPasteAllowedCallback.
130 ClipboardPasteData data_;
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58131 std::vector<IsClipboardPasteAllowedCallback> callbacks_;
danakjc492bf82020-09-09 20:02:44132 };
133
134 // A paste allowed request is obsolete if it is older than this time.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58135 static const base::TimeDelta kIsPasteAllowedRequestTooOld;
danakjc492bf82020-09-09 20:02:44136
Alexander Timine3383d02021-06-24 19:57:59137 explicit ClipboardHostImpl(
danakjc70aec1f2022-07-07 15:48:19138 RenderFrameHost& render_frame_host,
Alexander Timine3383d02021-06-24 19:57:59139 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
danakjc492bf82020-09-09 20:02:44140
Aya ElAttar84e6ef32021-03-02 16:29:19141 // Performs a check to see if pasting `data` is allowed by data transfer
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58142 // policies and invokes FinishPasteIfAllowed upon completion.
Aya ElAttar84e6ef32021-03-02 16:29:19143 void PasteIfPolicyAllowed(ui::ClipboardBuffer clipboard_buffer,
144 const ui::ClipboardFormatType& data_type,
Nancy Xiao4f3eae5d62023-04-25 19:38:59145 ClipboardPasteData clipboard_paste_data,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58146 IsClipboardPasteAllowedCallback callback);
danakjc492bf82020-09-09 20:02:44147
148 // Remove obsolete entries from the outstanding requests map.
149 // A request is obsolete if:
150 // - its sequence number is less than |seqno|
151 // - it has no callbacks
152 // - it is too old
153 void CleanupObsoleteRequests();
154
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58155 // Completion callback of PerformPasteIfAllowed(). Sets the allowed
danakjc492bf82020-09-09 20:02:44156 // status for the clipboard data corresponding to sequence number |seqno|.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58157 void FinishPasteIfAllowed(
Austin Sullivanbfe1af72021-07-20 23:14:14158 const ui::ClipboardSequenceNumberToken& seqno,
Arthur Sonzognic686e8f2024-01-11 08:36:37159 std::optional<ClipboardPasteData> clipboard_paste_data);
danakjc492bf82020-09-09 20:02:44160
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58161 const std::map<ui::ClipboardSequenceNumberToken, IsPasteAllowedRequest>&
danakjc492bf82020-09-09 20:02:44162 is_paste_allowed_requests_for_testing() {
163 return is_allowed_requests_;
164 }
165
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58166 // Called by PerformPasteIfAllowed() when an is allowed request is
167 // needed. Virtual to be overridden in tests.
168 virtual void StartIsPasteAllowedRequest(
169 const ui::ClipboardSequenceNumberToken& seqno,
170 const ui::ClipboardFormatType& data_type,
171 ui::ClipboardBuffer clipboard_buffer,
172 ClipboardPasteData clipboard_paste_data);
173
danakjc492bf82020-09-09 20:02:44174 private:
175 friend class ClipboardHostImplTest;
176 friend class ClipboardHostImplScanTest;
177 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58178 IsPasteAllowedRequest_AddCallback);
danakjc492bf82020-09-09 20:02:44179 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58180 IsPasteAllowedRequest_Complete);
danakjc492bf82020-09-09 20:02:44181 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58182 IsPasteAllowedRequest_IsObsolete);
danakjc492bf82020-09-09 20:02:44183 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58184 PerformPasteIfAllowed_EmptyData);
185 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest, PerformPasteIfAllowed);
Darwin Huang6195d042021-02-12 22:36:00186 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58187 PerformPasteIfAllowed_SameHost_NotStarted);
Roger Tawac774694b2023-03-16 20:44:39188 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58189 PerformPasteIfAllowed_External_Started);
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24190 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest, GetSourceEndpoint);
danakjc492bf82020-09-09 20:02:44191
192 // mojom::ClipboardHost
193 void GetSequenceNumber(ui::ClipboardBuffer clipboard_buffer,
194 GetSequenceNumberCallback callback) override;
195 void IsFormatAvailable(blink::mojom::ClipboardFormat format,
196 ui::ClipboardBuffer clipboard_buffer,
197 IsFormatAvailableCallback callback) override;
198 void ReadAvailableTypes(ui::ClipboardBuffer clipboard_buffer,
199 ReadAvailableTypesCallback callback) override;
200 void ReadText(ui::ClipboardBuffer clipboard_buffer,
201 ReadTextCallback callback) override;
202 void ReadHtml(ui::ClipboardBuffer clipboard_buffer,
203 ReadHtmlCallback callback) override;
204 void ReadSvg(ui::ClipboardBuffer clipboard_buffer,
205 ReadSvgCallback callback) override;
206 void ReadRtf(ui::ClipboardBuffer clipboard_buffer,
207 ReadRtfCallback callback) override;
Austin Sullivanaa060982021-06-25 17:49:30208 void ReadPng(ui::ClipboardBuffer clipboard_buffer,
209 ReadPngCallback callback) override;
Joel Hockey4c0cb8c2021-02-22 02:59:59210 void ReadFiles(ui::ClipboardBuffer clipboard_buffer,
211 ReadFilesCallback callback) override;
danakjc492bf82020-09-09 20:02:44212 void ReadCustomData(ui::ClipboardBuffer clipboard_buffer,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58213 const std::u16string& type,
danakjc492bf82020-09-09 20:02:44214 ReadCustomDataCallback callback) override;
Anupam Snigdha74b68e42021-08-10 23:35:59215 void ReadAvailableCustomAndStandardFormats(
216 ReadAvailableCustomAndStandardFormatsCallback callback) override;
217 void ReadUnsanitizedCustomFormat(
218 const std::u16string& format,
219 ReadUnsanitizedCustomFormatCallback callback) override;
220 void WriteUnsanitizedCustomFormat(const std::u16string& format,
221 mojo_base::BigBuffer data) override;
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58222 void WriteText(const std::u16string& text) override;
223 void WriteHtml(const std::u16string& markup, const GURL& url) override;
224 void WriteSvg(const std::u16string& markup) override;
danakjc492bf82020-09-09 20:02:44225 void WriteSmartPasteMarker() override;
226 void WriteCustomData(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58227 const base::flat_map<std::u16string, std::u16string>& data) override;
danakjc492bf82020-09-09 20:02:44228 void WriteBookmark(const std::string& url,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58229 const std::u16string& title) override;
danakjbdf1e0a2020-11-10 18:27:47230 void WriteImage(const SkBitmap& unsafe_bitmap) override;
danakjc492bf82020-09-09 20:02:44231 void CommitWrite() override;
Xiaohan Wang7f8052e02022-01-14 18:44:28232#if BUILDFLAG(IS_MAC)
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58233 void WriteStringToFindPboard(const std::u16string& text) override;
danakjc492bf82020-09-09 20:02:44234#endif
235
Roger Tawa34dd57f82022-12-15 23:24:20236 // Checks if the renderer allows pasting. This check is skipped if called
237 // soon after a successful content allowed request.
238 bool IsRendererPasteAllowed(ui::ClipboardBuffer clipboard_buffer,
239 RenderFrameHost& render_frame_host);
240
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53241 // Helpers to be used when checking if data is allowed to be copied.
242 // If `replacement_data` is null, `clipboard_writer_` will be used to write
243 // the corresponding text/markup data to the clipboard. If it is not, instead
244 // write the replacement string to the clipboard as plaintext. This can be
245 // called asynchronously.
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10246 void OnCopyTextAllowedResult(const ClipboardPasteData& data,
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53247 std::optional<std::u16string> replacement_data);
248 void OnCopyHtmlAllowedResult(const GURL& url,
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10249 const ClipboardPasteData& data,
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53250 std::optional<std::u16string> replacement_data);
Anthony Vallee-Duboisac847702021-12-06 21:00:48251
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53252 using CopyAllowedCallback = base::OnceCallback<void()>;
Dominique Fauteux-Chapleaudbb4b7092024-02-01 15:42:37253
Austin Sullivanfc870892021-04-29 18:40:11254 void OnReadPng(ui::ClipboardBuffer clipboard_buffer,
255 ReadPngCallback callback,
256 const std::vector<uint8_t>& data);
danakjc492bf82020-09-09 20:02:44257
Dominique Fauteux-Chapleau3b7738c2024-01-16 21:08:55258 // Creates a `ui::DataTransferEndpoint` representing the last committed URL.
Dominique Fauteux-Chapleau2cdc6a92024-01-29 17:39:37259 std::unique_ptr<ui::DataTransferEndpoint> CreateDataEndpoint();
danakjc492bf82020-09-09 20:02:44260
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53261 // Creates a `content::ClipboardEndpoint` representing the last committed URL.
262 ClipboardEndpoint CreateClipboardEndpoint();
263
danakjc492bf82020-09-09 20:02:44264 std::unique_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
265
266 // Outstanding is allowed requests per clipboard contents. Maps a clipboard
267 // sequence number to an outstanding request.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58268 std::map<ui::ClipboardSequenceNumberToken, IsPasteAllowedRequest>
Austin Sullivanbfe1af72021-07-20 23:14:14269 is_allowed_requests_;
danakjc492bf82020-09-09 20:02:44270
271 base::WeakPtrFactory<ClipboardHostImpl> weak_ptr_factory_{this};
272};
273
274} // namespace content
275
276#endif // CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_