Commit cdfc80b5 authored by Darwin Huang's avatar Darwin Huang Committed by Commit Bot

Clipboard: Add more detailed comments to ClipboardWriter.

Bug: 1145787
Change-Id: I8d4b1edfbdf2dc739d2b545cb828c35b62a5cfd5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2520321
Auto-Submit: Darwin Huang <huangdarwin@chromium.org>
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828101}
parent 4becd6bf
...@@ -20,8 +20,10 @@ class ClipboardPromise; ...@@ -20,8 +20,10 @@ class ClipboardPromise;
// Reading a type from the system clipboard to a Blob is accomplished by: // Reading a type from the system clipboard to a Blob is accomplished by:
// (1) Reading - the format from the system clipboard. // (1) Reading - the format from the system clipboard.
// (2) Encoding - the system clipboard's contents for a format. Encoding may be // (2) Encoding - the system clipboard's contents for a format. Encoding may be
// time-consuming, and so is done on a background thread whenever possible. // time-consuming, so it is done on a background thread whenever possible.
// (3) Writing - the decoded contents to a Blob. // An example where encoding is done on the main thread is HTML, where
// Blink's HTML encoder can only be used on the main thread.
// (3) Writing - the encoded contents to a Blob.
// //
// ClipboardReader takes as input a ClipboardPromise, from which it expects // ClipboardReader takes as input a ClipboardPromise, from which it expects
// a clipboard format, and to which it provides a Blob containing an encoded // a clipboard format, and to which it provides a Blob containing an encoded
...@@ -59,9 +61,12 @@ class ClipboardReader : public GarbageCollected<ClipboardReader> { ...@@ -59,9 +61,12 @@ class ClipboardReader : public GarbageCollected<ClipboardReader> {
virtual void NextRead(Vector<uint8_t> utf8_bytes) = 0; virtual void NextRead(Vector<uint8_t> utf8_bytes) = 0;
SystemClipboard* system_clipboard() { return system_clipboard_; } SystemClipboard* system_clipboard() { return system_clipboard_; }
// This ClipboardPromise owns this ClipboardReader. // This ClipboardPromise owns this ClipboardReader. Subclasses use `promise_`
// to report the Blob output, or to obtain the execution context.
Member<ClipboardPromise> promise_; Member<ClipboardPromise> promise_;
// Every subclass method that runs on the main thread should
// DCHECK_CALLED_ON_VALID_SEQUENCE with this checker.
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
private: private:
......
...@@ -28,7 +28,7 @@ namespace blink { ...@@ -28,7 +28,7 @@ namespace blink {
namespace { // anonymous namespace for ClipboardWriter's derived classes. namespace { // anonymous namespace for ClipboardWriter's derived classes.
// Writes a blob with image/png content to the System Clipboard. // Writes a Blob with image/png content to the System Clipboard.
class ClipboardImageWriter final : public ClipboardWriter { class ClipboardImageWriter final : public ClipboardWriter {
public: public:
ClipboardImageWriter(SystemClipboard* system_clipboard, ClipboardImageWriter(SystemClipboard* system_clipboard,
...@@ -59,7 +59,7 @@ class ClipboardImageWriter final : public ClipboardWriter { ...@@ -59,7 +59,7 @@ class ClipboardImageWriter final : public ClipboardWriter {
true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth,
ColorBehavior::Tag()); ColorBehavior::Tag());
sk_sp<SkImage> image = nullptr; sk_sp<SkImage> image = nullptr;
// |decoder| is nullptr if |png_data| doesn't begin with the PNG signature. // `decoder` is nullptr if `png_data` doesn't begin with the PNG signature.
if (decoder) if (decoder)
image = ImageBitmap::GetSkImageFromDecoder(std::move(decoder)); image = ImageBitmap::GetSkImageFromDecoder(std::move(decoder));
...@@ -81,7 +81,7 @@ class ClipboardImageWriter final : public ClipboardWriter { ...@@ -81,7 +81,7 @@ class ClipboardImageWriter final : public ClipboardWriter {
} }
}; };
// Writes a blob with text/plain content to the System Clipboard. // Writes a Blob with text/plain content to the System Clipboard.
class ClipboardTextWriter final : public ClipboardWriter { class ClipboardTextWriter final : public ClipboardWriter {
public: public:
ClipboardTextWriter(SystemClipboard* system_clipboard, ClipboardTextWriter(SystemClipboard* system_clipboard,
...@@ -173,8 +173,6 @@ class ClipboardSvgWriter final : public ClipboardWriter { ...@@ -173,8 +173,6 @@ class ClipboardSvgWriter final : public ClipboardWriter {
~ClipboardSvgWriter() override = default; ~ClipboardSvgWriter() override = default;
private: private:
// This must be called on the main thread because XML DOM nodes can
// only be used on the main thread
void StartWrite( void StartWrite(
DOMArrayBuffer* svg_data, DOMArrayBuffer* svg_data,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override { scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
...@@ -184,7 +182,8 @@ class ClipboardSvgWriter final : public ClipboardWriter { ...@@ -184,7 +182,8 @@ class ClipboardSvgWriter final : public ClipboardWriter {
String::FromUTF8(reinterpret_cast<const LChar*>(svg_data->Data()), String::FromUTF8(reinterpret_cast<const LChar*>(svg_data->Data()),
svg_data->ByteLength()); svg_data->ByteLength());
// Now sanitize the SVG string. // Sanitizing on the main thread because SVG/XML DOM nodes can only be used
// on the main thread.
KURL url; KURL url;
unsigned fragment_start = 0; unsigned fragment_start = 0;
unsigned fragment_end = svg_string.length(); unsigned fragment_end = svg_string.length();
...@@ -204,7 +203,7 @@ class ClipboardSvgWriter final : public ClipboardWriter { ...@@ -204,7 +203,7 @@ class ClipboardSvgWriter final : public ClipboardWriter {
} }
}; };
// Writes a blob with arbitrary, unsanitized content to the System Clipboard. // Writes a Blob with arbitrary, unsanitized content to the System Clipboard.
class ClipboardRawDataWriter final : public ClipboardWriter { class ClipboardRawDataWriter final : public ClipboardWriter {
public: public:
ClipboardRawDataWriter(RawSystemClipboard* raw_system_clipboard, ClipboardRawDataWriter(RawSystemClipboard* raw_system_clipboard,
......
...@@ -19,15 +19,33 @@ class FileReaderLoader; ...@@ -19,15 +19,33 @@ class FileReaderLoader;
class SystemClipboard; class SystemClipboard;
class RawSystemClipboard; class RawSystemClipboard;
// Interface for writing async-clipboard-compatible types as a Blob to the // Interface for writing an individual Clipboard API format as a Blob to the
// System Clipboard, asynchronously. // System Clipboard, safely and asynchronously.
//
// ClipboardWriter takes as input a ClipboardPromise, which manages writing
// multiple formats and passes in unsanitized clipboard payloads.
// ClipboardWriter then sanitizes a Blob payload and writes it onto the
// underlying system clipboard. All System Clipboard operations should be
// called from the main thread.
// //
// Writing a Blob's data to the system clipboard is accomplished by: // Writing a Blob's data to the system clipboard is accomplished by:
// (1) Reading the blob's contents using a FileReaderLoader. // (1) Reading - the Blob's contents using a FileReaderLoader.
// (2) Decoding the blob's contents to avoid RCE in native applications that may // (2) Decoding - or sanitizing the Blob's contents to avoid RCE in native
// take advantage of vulnerabilities in their decoders. In // applications that may take advantage of vulnerabilities in their
// ClipboardRawDataWriter, this decoding is skipped. // decoders, whenever possible. Decoding may be time-consuming, so it
// (3) Writing the blob's decoded contents to the system clipboard. // is done on a background thread whenever possible. An example where
// decoding is done on the main thread is HTML, where Blink's HTML decoder
// can only be used on the main thread.
// (3) Writing - the Blob's decoded contents to the system clipboard.
//
// Subclasses of ClipboardWriter should be implemented for each supported
// format. Subclasses should:
// (1) Begin execution by implementing ClipboardWriter::StartWrite().
// (2) Decode the payload on a background thread (if possible) by implementing
// a static DecodeOnBackgroundThread() function. This function is called by
// StartWrite() via worker_pool::PostTask().
// (3) Write the decoded content to the system clipboard by implementing
// ClipboardWriter::Write();
// //
// ClipboardWriter is owned only by itself and ClipboardPromise. It keeps // ClipboardWriter is owned only by itself and ClipboardPromise. It keeps
// itself alive for the duration of FileReaderLoader's async operations using // itself alive for the duration of FileReaderLoader's async operations using
...@@ -36,20 +54,23 @@ class RawSystemClipboard; ...@@ -36,20 +54,23 @@ class RawSystemClipboard;
class ClipboardWriter : public GarbageCollected<ClipboardWriter>, class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
public FileReaderLoaderClient { public FileReaderLoaderClient {
public: public:
// For writing sanitized MIME types.
static ClipboardWriter* Create(SystemClipboard* system_clipboard, static ClipboardWriter* Create(SystemClipboard* system_clipboard,
const String& mime_type, const String& mime_type,
ClipboardPromise* promise); ClipboardPromise* promise);
// For writing unsanitized types.
static ClipboardWriter* Create(RawSystemClipboard* raw_system_clipboard, static ClipboardWriter* Create(RawSystemClipboard* raw_system_clipboard,
const String& mime_type, const String& mime_type,
ClipboardPromise* promise); ClipboardPromise* promise);
static ClipboardWriter* Create(SystemClipboard* system_clipboard,
const String& mime_type,
ClipboardPromise* promise,
LocalFrame* frame);
~ClipboardWriter() override; ~ClipboardWriter() override;
static bool IsValidType(const String& type, bool is_raw); // Returns whether ClipboardWriter has implemented support for this type.
void WriteToSystem(Blob*); //
// If this API returns false for a `mime_type`, Create() must not be called
// with that `mime_type`.
static bool IsValidType(const String& mime_type, bool is_raw);
// Begins the sequence of writing the Blob to the system clipbaord.
void WriteToSystem(Blob* blob);
// FileReaderLoaderClient. // FileReaderLoaderClient.
void DidStartLoading() override; void DidStartLoading() override;
...@@ -69,15 +90,18 @@ class ClipboardWriter : public GarbageCollected<ClipboardWriter>, ...@@ -69,15 +90,18 @@ class ClipboardWriter : public GarbageCollected<ClipboardWriter>,
virtual void StartWrite( virtual void StartWrite(
DOMArrayBuffer* raw_data, DOMArrayBuffer* raw_data,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0; scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
// This ClipboardPromise owns this ClipboardWriter.
Member<ClipboardPromise> promise_;
// Ensure that System Clipboard operations occur on the main thread.
SEQUENCE_CHECKER(sequence_checker_);
SystemClipboard* system_clipboard() { return system_clipboard_; } SystemClipboard* system_clipboard() { return system_clipboard_; }
RawSystemClipboard* raw_system_clipboard() { return raw_system_clipboard_; } RawSystemClipboard* raw_system_clipboard() { return raw_system_clipboard_; }
// This ClipboardPromise owns this ClipboardWriter. Subclasses use `promise_`
// to report success or failure, or to obtain the execution context.
Member<ClipboardPromise> promise_;
// Every subclass method that runs on the main thread should
// DCHECK_CALLED_ON_VALID_SEQUENCE with this checker.
SEQUENCE_CHECKER(sequence_checker_);
private: private:
ClipboardWriter(SystemClipboard* system_clipboard, ClipboardWriter(SystemClipboard* system_clipboard,
RawSystemClipboard* raw_system_clipboard, RawSystemClipboard* raw_system_clipboard,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment