blob: 88658b433f0950c7ef954e8594777e833fbc6169 [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"
Daniel Cheng9fb887ff2021-10-01 20:27:3821#include "content/public/browser/document_service.h"
Austin Sullivanfc870892021-04-29 18:40:1122#include "mojo/public/cpp/base/big_buffer.h"
danakjc492bf82020-09-09 20:02:4423#include "mojo/public/cpp/bindings/receiver.h"
danakjc492bf82020-09-09 20:02:4424#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
25#include "ui/base/clipboard/clipboard.h"
26
27class GURL;
28
29namespace ui {
30class ScopedClipboardWriter;
31} // namespace ui
32
33namespace content {
34
35class ClipboardHostImplTest;
36
Alexander Timine3383d02021-06-24 19:57:5937class CONTENT_EXPORT ClipboardHostImpl
Daniel Cheng9fb887ff2021-10-01 20:27:3838 : public DocumentService<blink::mojom::ClipboardHost> {
danakjc492bf82020-09-09 20:02:4439 public:
40 ~ClipboardHostImpl() override;
41
42 static void Create(
43 RenderFrameHost* render_frame_host,
44 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
45
Nancy Xiao4f3eae5d62023-04-25 19:38:5946 using ClipboardPasteData = content::ClipboardPasteData;
47
danakjc492bf82020-09-09 20:02:4448 protected:
49 // These types and methods are protected for testing.
50
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5851 using IsClipboardPasteAllowedCallback =
52 RenderFrameHostImpl::IsClipboardPasteAllowedCallback;
danakjc492bf82020-09-09 20:02:4453
Roger Tawac6170262022-10-28 23:48:5254 // Represents the underlying type of the argument passed to
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5855 // IsClipboardPasteAllowedCallback without the const& part.
56 using IsClipboardPasteAllowedCallbackArgType =
Arthur Sonzognic686e8f2024-01-11 08:36:3757 std::optional<ClipboardPasteData>;
Roger Tawac6170262022-10-28 23:48:5258
danakjc492bf82020-09-09 20:02:4459 // Keeps track of a request to see if some clipboard content, identified by
Rakina Zata Amni39d8e7e2022-10-20 18:18:3060 // its sequence number, is allowed to be pasted into the RenderFrameHost
danakjc492bf82020-09-09 20:02:4461 // that owns this clipboard host.
62 //
63 // A request starts in the state incomplete until Complete() is called with
64 // a value. Callbacks can be added to the request before or after it has
65 // completed.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5866 class CONTENT_EXPORT IsPasteAllowedRequest {
danakjc492bf82020-09-09 20:02:4467 public:
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5868 IsPasteAllowedRequest();
69 ~IsPasteAllowedRequest();
danakjc492bf82020-09-09 20:02:4470
71 // Adds |callback| to be notified when the request completes. If the
72 // request is already completed |callback| is invoked immediately. Returns
73 // true if a request should be started after adding this callback.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5874 bool AddCallback(IsClipboardPasteAllowedCallback callback);
danakjc492bf82020-09-09 20:02:4475
76 // Mark this request as completed with the specified result.
77 // Invoke all callbacks now.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:5878 void Complete(IsClipboardPasteAllowedCallbackArgType data);
danakjc492bf82020-09-09 20:02:4479
Roger Tawa34dd57f82022-12-15 23:24:2080 // Returns true if the request has completed.
81 bool is_complete() const { return data_.has_value(); }
82
danakjc492bf82020-09-09 20:02:4483 // Returns true if this request is obsolete. An obsolete request
84 // is one that is completed, all registered callbacks have been
85 // called, and is considered old.
86 //
87 // |now| represents the current time. It is an argument to ease testing.
88 bool IsObsolete(base::Time now);
89
Roger Tawa34dd57f82022-12-15 23:24:2090 // Returns the time at which this request was completed. If called
91 // before the request is completed the return value is undefined.
92 base::Time completed_time();
danakjc492bf82020-09-09 20:02:4493
94 private:
95 // Calls all the callbacks in |callbacks_| with the current value of
96 // |allowed_|. |allowed_| must not be empty.
97 void InvokeCallbacks();
98
Roger Tawa34dd57f82022-12-15 23:24:2099 // The time at which the request was completed. Before completion this
100 // value is undefined.
101 base::Time completed_time_;
Roger Tawac6170262022-10-28 23:48:52102
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58103 // The data argument to pass to the IsClipboardPasteAllowedCallback.
Roger Tawac6170262022-10-28 23:48:52104 // This member is null until Complete() is called.
Arthur Sonzognic686e8f2024-01-11 08:36:37105 std::optional<IsClipboardPasteAllowedCallbackArgType> data_;
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58106 std::vector<IsClipboardPasteAllowedCallback> callbacks_;
danakjc492bf82020-09-09 20:02:44107 };
108
109 // A paste allowed request is obsolete if it is older than this time.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58110 static const base::TimeDelta kIsPasteAllowedRequestTooOld;
danakjc492bf82020-09-09 20:02:44111
Alexander Timine3383d02021-06-24 19:57:59112 explicit ClipboardHostImpl(
danakjc70aec1f2022-07-07 15:48:19113 RenderFrameHost& render_frame_host,
Alexander Timine3383d02021-06-24 19:57:59114 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
danakjc492bf82020-09-09 20:02:44115
Aya ElAttar84e6ef32021-03-02 16:29:19116 // Performs a check to see if pasting `data` is allowed by data transfer
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58117 // policies and invokes FinishPasteIfAllowed upon completion.
Aya ElAttar84e6ef32021-03-02 16:29:19118 void PasteIfPolicyAllowed(ui::ClipboardBuffer clipboard_buffer,
119 const ui::ClipboardFormatType& data_type,
Nancy Xiao4f3eae5d62023-04-25 19:38:59120 ClipboardPasteData clipboard_paste_data,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58121 IsClipboardPasteAllowedCallback callback);
danakjc492bf82020-09-09 20:02:44122
123 // Remove obsolete entries from the outstanding requests map.
124 // A request is obsolete if:
125 // - its sequence number is less than |seqno|
126 // - it has no callbacks
127 // - it is too old
128 void CleanupObsoleteRequests();
129
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58130 // Completion callback of PerformPasteIfAllowed(). Sets the allowed
danakjc492bf82020-09-09 20:02:44131 // status for the clipboard data corresponding to sequence number |seqno|.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58132 void FinishPasteIfAllowed(
Austin Sullivanbfe1af72021-07-20 23:14:14133 const ui::ClipboardSequenceNumberToken& seqno,
Arthur Sonzognic686e8f2024-01-11 08:36:37134 std::optional<ClipboardPasteData> clipboard_paste_data);
danakjc492bf82020-09-09 20:02:44135
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58136 const std::map<ui::ClipboardSequenceNumberToken, IsPasteAllowedRequest>&
danakjc492bf82020-09-09 20:02:44137 is_paste_allowed_requests_for_testing() {
138 return is_allowed_requests_;
139 }
140
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58141 // Called by PerformPasteIfAllowed() when an is allowed request is
142 // needed. Virtual to be overridden in tests.
143 virtual void StartIsPasteAllowedRequest(
144 const ui::ClipboardSequenceNumberToken& seqno,
145 const ui::ClipboardFormatType& data_type,
146 ui::ClipboardBuffer clipboard_buffer,
147 ClipboardPasteData clipboard_paste_data);
148
danakjc492bf82020-09-09 20:02:44149 private:
150 friend class ClipboardHostImplTest;
151 friend class ClipboardHostImplScanTest;
152 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58153 IsPasteAllowedRequest_AddCallback);
danakjc492bf82020-09-09 20:02:44154 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58155 IsPasteAllowedRequest_Complete);
danakjc492bf82020-09-09 20:02:44156 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58157 IsPasteAllowedRequest_IsObsolete);
danakjc492bf82020-09-09 20:02:44158 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58159 PerformPasteIfAllowed_EmptyData);
160 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest, PerformPasteIfAllowed);
Darwin Huang6195d042021-02-12 22:36:00161 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58162 PerformPasteIfAllowed_SameHost_NotStarted);
Roger Tawac774694b2023-03-16 20:44:39163 FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplScanTest,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58164 PerformPasteIfAllowed_External_Started);
danakjc492bf82020-09-09 20:02:44165
166 // mojom::ClipboardHost
167 void GetSequenceNumber(ui::ClipboardBuffer clipboard_buffer,
168 GetSequenceNumberCallback callback) override;
169 void IsFormatAvailable(blink::mojom::ClipboardFormat format,
170 ui::ClipboardBuffer clipboard_buffer,
171 IsFormatAvailableCallback callback) override;
172 void ReadAvailableTypes(ui::ClipboardBuffer clipboard_buffer,
173 ReadAvailableTypesCallback callback) override;
174 void ReadText(ui::ClipboardBuffer clipboard_buffer,
175 ReadTextCallback callback) override;
176 void ReadHtml(ui::ClipboardBuffer clipboard_buffer,
177 ReadHtmlCallback callback) override;
178 void ReadSvg(ui::ClipboardBuffer clipboard_buffer,
179 ReadSvgCallback callback) override;
180 void ReadRtf(ui::ClipboardBuffer clipboard_buffer,
181 ReadRtfCallback callback) override;
Austin Sullivanaa060982021-06-25 17:49:30182 void ReadPng(ui::ClipboardBuffer clipboard_buffer,
183 ReadPngCallback callback) override;
Joel Hockey4c0cb8c2021-02-22 02:59:59184 void ReadFiles(ui::ClipboardBuffer clipboard_buffer,
185 ReadFilesCallback callback) override;
danakjc492bf82020-09-09 20:02:44186 void ReadCustomData(ui::ClipboardBuffer clipboard_buffer,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58187 const std::u16string& type,
danakjc492bf82020-09-09 20:02:44188 ReadCustomDataCallback callback) override;
Anupam Snigdha74b68e42021-08-10 23:35:59189 void ReadAvailableCustomAndStandardFormats(
190 ReadAvailableCustomAndStandardFormatsCallback callback) override;
191 void ReadUnsanitizedCustomFormat(
192 const std::u16string& format,
193 ReadUnsanitizedCustomFormatCallback callback) override;
194 void WriteUnsanitizedCustomFormat(const std::u16string& format,
195 mojo_base::BigBuffer data) override;
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58196 void WriteText(const std::u16string& text) override;
197 void WriteHtml(const std::u16string& markup, const GURL& url) override;
198 void WriteSvg(const std::u16string& markup) override;
danakjc492bf82020-09-09 20:02:44199 void WriteSmartPasteMarker() override;
200 void WriteCustomData(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58201 const base::flat_map<std::u16string, std::u16string>& data) override;
danakjc492bf82020-09-09 20:02:44202 void WriteBookmark(const std::string& url,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58203 const std::u16string& title) override;
danakjbdf1e0a2020-11-10 18:27:47204 void WriteImage(const SkBitmap& unsafe_bitmap) override;
danakjc492bf82020-09-09 20:02:44205 void CommitWrite() override;
Xiaohan Wang7f8052e02022-01-14 18:44:28206#if BUILDFLAG(IS_MAC)
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58207 void WriteStringToFindPboard(const std::u16string& text) override;
danakjc492bf82020-09-09 20:02:44208#endif
209
Roger Tawa34dd57f82022-12-15 23:24:20210 // Checks if the renderer allows pasting. This check is skipped if called
211 // soon after a successful content allowed request.
212 bool IsRendererPasteAllowed(ui::ClipboardBuffer clipboard_buffer,
213 RenderFrameHost& render_frame_host);
214
Anthony Vallee-Duboisac847702021-12-06 21:00:48215 using CopyAllowedCallback = base::OnceCallback<void()>;
216 void CopyIfAllowed(size_t data_size_in_bytes, CopyAllowedCallback callback);
217
Austin Sullivanfc870892021-04-29 18:40:11218 void OnReadPng(ui::ClipboardBuffer clipboard_buffer,
219 ReadPngCallback callback,
220 const std::vector<uint8_t>& data);
danakjc492bf82020-09-09 20:02:44221
Dominique Fauteux-Chapleau3b7738c2024-01-16 21:08:55222 // Creates a `ui::DataTransferEndpoint` representing the last committed URL.
Dominique Fauteux-Chapleau2cdc6a92024-01-29 17:39:37223 std::unique_ptr<ui::DataTransferEndpoint> CreateDataEndpoint();
danakjc492bf82020-09-09 20:02:44224
danakjc492bf82020-09-09 20:02:44225 std::unique_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
226
227 // Outstanding is allowed requests per clipboard contents. Maps a clipboard
228 // sequence number to an outstanding request.
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58229 std::map<ui::ClipboardSequenceNumberToken, IsPasteAllowedRequest>
Austin Sullivanbfe1af72021-07-20 23:14:14230 is_allowed_requests_;
danakjc492bf82020-09-09 20:02:44231
232 base::WeakPtrFactory<ClipboardHostImpl> weak_ptr_factory_{this};
233};
234
235} // namespace content
236
237#endif // CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_