Commit 89797ba0 authored by Yutaka Hirano's avatar Yutaka Hirano Committed by Commit Bot

Make ThreadableLoaderClient GarbageCollectedMixin

ThreadableLoaderClient has not been GarbageCollected mainly for
WorkerThreadableLoader. Now WorkerThreadableLoader is gone, so we can
make it an on-heap class. Doing so brings several benefits:

 - This is a blocker of removing ThreadableLoader after OOR-CORS is
   enabled, as ResourceClient is a GarbageCollectedMixin.
 - As ThreadableLoader holds a reference to its client as a raw
   pointer, each user needs to guarantee to cancel the loader properly
   before the client gets invalid. As most of clietns are already
   on-heap, this requires pre-finalizer for each client. Also, failing
   to keep the contract leads to crashes which are very hard to
   investigate.

Bug: 900506
Change-Id: I67b3e3dab7e0600f06da5222d458ff2d81c36c7b
Reviewed-on: https://chromium-review.googlesource.com/c/1335056Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarTakashi Toyoshima <toyoshim@chromium.org>
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607970}
parent 394bed00
...@@ -94,15 +94,17 @@ void HTTPRequestHeaderValidator::VisitHeader(const WebString& name, ...@@ -94,15 +94,17 @@ void HTTPRequestHeaderValidator::VisitHeader(const WebString& name,
// It forwards its ThreadableLoaderClient notifications to a // It forwards its ThreadableLoaderClient notifications to a
// WebAssociatedURLLoaderClient. // WebAssociatedURLLoaderClient.
class WebAssociatedURLLoaderImpl::ClientAdapter final class WebAssociatedURLLoaderImpl::ClientAdapter final
: public ThreadableLoaderClient { : public GarbageCollectedFinalized<ClientAdapter>,
public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(ClientAdapter);
public: public:
static std::unique_ptr<ClientAdapter> Create( ClientAdapter(WebAssociatedURLLoaderImpl*,
WebAssociatedURLLoaderImpl*, WebAssociatedURLLoaderClient*,
WebAssociatedURLLoaderClient*, const WebAssociatedURLLoaderOptions&,
const WebAssociatedURLLoaderOptions&, network::mojom::FetchRequestMode,
network::mojom::FetchRequestMode, network::mojom::FetchCredentialsMode,
network::mojom::FetchCredentialsMode, scoped_refptr<base::SingleThreadTaskRunner>);
scoped_refptr<base::SingleThreadTaskRunner>);
// ThreadableLoaderClient // ThreadableLoaderClient
void DidSendData(unsigned long long /*bytesSent*/, void DidSendData(unsigned long long /*bytesSent*/,
...@@ -140,13 +142,6 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final ...@@ -140,13 +142,6 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final
} }
private: private:
ClientAdapter(WebAssociatedURLLoaderImpl*,
WebAssociatedURLLoaderClient*,
const WebAssociatedURLLoaderOptions&,
network::mojom::FetchRequestMode,
network::mojom::FetchCredentialsMode,
scoped_refptr<base::SingleThreadTaskRunner>);
void NotifyError(TimerBase*); void NotifyError(TimerBase*);
WebAssociatedURLLoaderImpl* loader_; WebAssociatedURLLoaderImpl* loader_;
...@@ -163,19 +158,6 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final ...@@ -163,19 +158,6 @@ class WebAssociatedURLLoaderImpl::ClientAdapter final
DISALLOW_COPY_AND_ASSIGN(ClientAdapter); DISALLOW_COPY_AND_ASSIGN(ClientAdapter);
}; };
std::unique_ptr<WebAssociatedURLLoaderImpl::ClientAdapter>
WebAssociatedURLLoaderImpl::ClientAdapter::Create(
WebAssociatedURLLoaderImpl* loader,
WebAssociatedURLLoaderClient* client,
const WebAssociatedURLLoaderOptions& options,
network::mojom::FetchRequestMode fetch_request_mode,
network::mojom::FetchCredentialsMode credentials_mode,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
return base::WrapUnique(new ClientAdapter(loader, client, options,
fetch_request_mode,
credentials_mode, task_runner));
}
WebAssociatedURLLoaderImpl::ClientAdapter::ClientAdapter( WebAssociatedURLLoaderImpl::ClientAdapter::ClientAdapter(
WebAssociatedURLLoaderImpl* loader, WebAssociatedURLLoaderImpl* loader,
WebAssociatedURLLoaderClient* client, WebAssociatedURLLoaderClient* client,
...@@ -406,7 +388,7 @@ void WebAssociatedURLLoaderImpl::LoadAsynchronously( ...@@ -406,7 +388,7 @@ void WebAssociatedURLLoaderImpl::LoadAsynchronously(
task_runner = Thread::Current()->GetTaskRunner(); task_runner = Thread::Current()->GetTaskRunner();
} }
client_ = client; client_ = client;
client_adapter_ = ClientAdapter::Create( client_adapter_ = MakeGarbageCollected<ClientAdapter>(
this, client, options_, request.GetFetchRequestMode(), this, client, options_, request.GetFetchRequestMode(),
request.GetFetchCredentialsMode(), std::move(task_runner)); request.GetFetchCredentialsMode(), std::move(task_runner));
...@@ -442,7 +424,7 @@ void WebAssociatedURLLoaderImpl::LoadAsynchronously( ...@@ -442,7 +424,7 @@ void WebAssociatedURLLoaderImpl::LoadAsynchronously(
if (observer_) { if (observer_) {
Document& document = To<Document>(*observer_->LifecycleContext()); Document& document = To<Document>(*observer_->LifecycleContext());
loader_ = new ThreadableLoader(document, client_adapter_.get(), loader_ = new ThreadableLoader(document, client_adapter_,
resource_loader_options); resource_loader_options);
loader_->Start(webcore_request); loader_->Start(webcore_request);
} }
...@@ -477,7 +459,7 @@ void WebAssociatedURLLoaderImpl::CancelLoader() { ...@@ -477,7 +459,7 @@ void WebAssociatedURLLoaderImpl::CancelLoader() {
loader_->Cancel(); loader_->Cancel();
loader_ = nullptr; loader_ = nullptr;
} }
client_adapter_.reset(); client_adapter_ = nullptr;
} }
void WebAssociatedURLLoaderImpl::SetDefersLoading(bool defers_loading) { void WebAssociatedURLLoaderImpl::SetDefersLoading(bool defers_loading) {
......
...@@ -59,7 +59,7 @@ class CORE_EXPORT WebAssociatedURLLoaderImpl final ...@@ -59,7 +59,7 @@ class CORE_EXPORT WebAssociatedURLLoaderImpl final
// An adapter which converts the hreadableLoaderClient method // An adapter which converts the hreadableLoaderClient method
// calls into the WebURLLoaderClient method calls. // calls into the WebURLLoaderClient method calls.
std::unique_ptr<ClientAdapter> client_adapter_; Persistent<ClientAdapter> client_adapter_;
Persistent<ThreadableLoader> loader_; Persistent<ThreadableLoader> loader_;
// A ContextLifecycleObserver for cancelling |m_loader| when the Document // A ContextLifecycleObserver for cancelling |m_loader| when the Document
......
...@@ -201,7 +201,7 @@ class SRIBytesConsumer final : public BytesConsumer { ...@@ -201,7 +201,7 @@ class SRIBytesConsumer final : public BytesConsumer {
class FetchManager::Loader final class FetchManager::Loader final
: public GarbageCollectedFinalized<FetchManager::Loader>, : public GarbageCollectedFinalized<FetchManager::Loader>,
public ThreadableLoaderClient { public ThreadableLoaderClient {
USING_PRE_FINALIZER(FetchManager::Loader, Dispose); USING_GARBAGE_COLLECTED_MIXIN(Loader);
public: public:
static Loader* Create(ExecutionContext* execution_context, static Loader* Create(ExecutionContext* execution_context,
...@@ -215,7 +215,7 @@ class FetchManager::Loader final ...@@ -215,7 +215,7 @@ class FetchManager::Loader final
} }
~Loader() override; ~Loader() override;
virtual void Trace(blink::Visitor*); void Trace(blink::Visitor*) override;
bool WillFollowRedirect(const KURL&, const ResourceResponse&) override; bool WillFollowRedirect(const KURL&, const ResourceResponse&) override;
void DidReceiveResponse(unsigned long, void DidReceiveResponse(unsigned long,
...@@ -413,6 +413,7 @@ void FetchManager::Loader::Trace(blink::Visitor* visitor) { ...@@ -413,6 +413,7 @@ void FetchManager::Loader::Trace(blink::Visitor* visitor) {
visitor->Trace(integrity_verifier_); visitor->Trace(integrity_verifier_);
visitor->Trace(signal_); visitor->Trace(signal_);
visitor->Trace(execution_context_); visitor->Trace(execution_context_);
ThreadableLoaderClient::Trace(visitor);
} }
bool FetchManager::Loader::WillFollowRedirect( bool FetchManager::Loader::WillFollowRedirect(
......
...@@ -663,6 +663,7 @@ void InspectorNetworkAgent::Trace(blink::Visitor* visitor) { ...@@ -663,6 +663,7 @@ void InspectorNetworkAgent::Trace(blink::Visitor* visitor) {
visitor->Trace(inspected_frames_); visitor->Trace(inspected_frames_);
visitor->Trace(worker_global_scope_); visitor->Trace(worker_global_scope_);
visitor->Trace(resources_data_); visitor->Trace(resources_data_);
visitor->Trace(pending_request_);
visitor->Trace(replay_xhrs_); visitor->Trace(replay_xhrs_);
visitor->Trace(replay_xhrs_to_be_deleted_); visitor->Trace(replay_xhrs_to_be_deleted_);
visitor->Trace(pending_xhr_replay_data_); visitor->Trace(pending_xhr_replay_data_);
......
...@@ -269,7 +269,7 @@ class CORE_EXPORT InspectorNetworkAgent final ...@@ -269,7 +269,7 @@ class CORE_EXPORT InspectorNetworkAgent final
// Stores the pending ThreadableLoaderClient till an identifier for // Stores the pending ThreadableLoaderClient till an identifier for
// the load is generated by the loader and passed to the inspector // the load is generated by the loader and passed to the inspector
// via the WillSendRequest() method. // via the WillSendRequest() method.
ThreadableLoaderClient* pending_request_; Member<ThreadableLoaderClient> pending_request_;
InspectorPageAgent::ResourceType pending_request_type_; InspectorPageAgent::ResourceType pending_request_type_;
Member<XHRReplayData> pending_xhr_replay_data_; Member<XHRReplayData> pending_xhr_replay_data_;
......
...@@ -104,6 +104,8 @@ AtomicString CreateAccessControlRequestHeadersHeader( ...@@ -104,6 +104,8 @@ AtomicString CreateAccessControlRequestHeadersHeader(
class ThreadableLoader::DetachedClient final class ThreadableLoader::DetachedClient final
: public GarbageCollectedFinalized<DetachedClient>, : public GarbageCollectedFinalized<DetachedClient>,
public ThreadableLoaderClient { public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(DetachedClient);
public: public:
explicit DetachedClient(ThreadableLoader* loader) explicit DetachedClient(ThreadableLoader* loader)
: self_keep_alive_(this), loader_(loader) {} : self_keep_alive_(this), loader_(loader) {}
...@@ -114,7 +116,10 @@ class ThreadableLoader::DetachedClient final ...@@ -114,7 +116,10 @@ class ThreadableLoader::DetachedClient final
} }
void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); } void DidFail(const ResourceError&) override { self_keep_alive_.Clear(); }
void DidFailRedirectCheck() override { self_keep_alive_.Clear(); } void DidFailRedirectCheck() override { self_keep_alive_.Clear(); }
void Trace(Visitor* visitor) { visitor->Trace(loader_); } void Trace(Visitor* visitor) override {
visitor->Trace(loader_);
ThreadableLoaderClient::Trace(visitor);
}
private: private:
SelfKeepAlive<DetachedClient> self_keep_alive_; SelfKeepAlive<DetachedClient> self_keep_alive_;
...@@ -482,15 +487,7 @@ void ThreadableLoader::MakeCrossOriginAccessRequest( ...@@ -482,15 +487,7 @@ void ThreadableLoader::MakeCrossOriginAccessRequest(
LoadRequest(cross_origin_request, cross_origin_options); LoadRequest(cross_origin_request, cross_origin_options);
} }
ThreadableLoader::~ThreadableLoader() { ThreadableLoader::~ThreadableLoader() {}
// |client_| is a raw pointer and having a non-null |client_| here probably
// means UaF.
// In the detached case, |this| is held by DetachedClient defined above, but
// SelfKeepAlive in DetachedClient is forcibly cancelled on worker thread
// termination. We can safely ignore this case.
CHECK(!client_ || detached_);
DCHECK(!GetResource());
}
void ThreadableLoader::SetTimeout(const TimeDelta& timeout) { void ThreadableLoader::SetTimeout(const TimeDelta& timeout) {
timeout_ = timeout; timeout_ = timeout;
...@@ -1105,6 +1102,7 @@ Document* ThreadableLoader::GetDocument() const { ...@@ -1105,6 +1102,7 @@ Document* ThreadableLoader::GetDocument() const {
void ThreadableLoader::Trace(blink::Visitor* visitor) { void ThreadableLoader::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_); visitor->Trace(execution_context_);
visitor->Trace(client_);
RawResourceClient::Trace(visitor); RawResourceClient::Trace(visitor);
} }
......
...@@ -89,10 +89,6 @@ class CORE_EXPORT ThreadableLoader final ...@@ -89,10 +89,6 @@ class CORE_EXPORT ThreadableLoader final
// After any of these methods is called, the loader won't call any of the // After any of these methods is called, the loader won't call any of the
// ThreadableLoaderClient methods. // ThreadableLoaderClient methods.
// //
// A user must guarantee that the loading completes before the attached
// client gets invalid. Also, a user must guarantee that the loading
// completes before the ThreadableLoader is destructed.
//
// When ThreadableLoader::Cancel() is called, // When ThreadableLoader::Cancel() is called,
// ThreadableLoaderClient::DidFail() is called with a ResourceError // ThreadableLoaderClient::DidFail() is called with a ResourceError
// with IsCancellation() returning true, if any of DidFinishLoading() // with IsCancellation() returning true, if any of DidFinishLoading()
...@@ -100,7 +96,7 @@ class CORE_EXPORT ThreadableLoader final ...@@ -100,7 +96,7 @@ class CORE_EXPORT ThreadableLoader final
// called with a ResourceError with IsCancellation() returning true // called with a ResourceError with IsCancellation() returning true
// also for cancellation happened inside the loader.) // also for cancellation happened inside the loader.)
// //
// ThreadableLoaderClient methods may call cancel(). // ThreadableLoaderClient methods may call Cancel().
ThreadableLoader(ExecutionContext&, ThreadableLoader(ExecutionContext&,
ThreadableLoaderClient*, ThreadableLoaderClient*,
const ResourceLoaderOptions&); const ResourceLoaderOptions&);
...@@ -211,7 +207,7 @@ class CORE_EXPORT ThreadableLoader final ...@@ -211,7 +207,7 @@ class CORE_EXPORT ThreadableLoader final
// TODO(kinuko): Remove dependency to document. // TODO(kinuko): Remove dependency to document.
Document* GetDocument() const; Document* GetDocument() const;
ThreadableLoaderClient* client_; Member<ThreadableLoaderClient> client_;
Member<ExecutionContext> execution_context_; Member<ExecutionContext> execution_context_;
TimeDelta timeout_; TimeDelta timeout_;
......
...@@ -46,7 +46,7 @@ class ResourceError; ...@@ -46,7 +46,7 @@ class ResourceError;
class ResourceResponse; class ResourceResponse;
class ResourceTimingInfo; class ResourceTimingInfo;
class CORE_EXPORT ThreadableLoaderClient { class CORE_EXPORT ThreadableLoaderClient : public GarbageCollectedMixin {
public: public:
virtual void DidSendData(unsigned long long /*bytesSent*/, virtual void DidSendData(unsigned long long /*bytesSent*/,
unsigned long long /*totalBytesToBeSent*/) {} unsigned long long /*totalBytesToBeSent*/) {}
......
...@@ -53,12 +53,13 @@ using Checkpoint = testing::StrictMock<testing::MockFunction<void(int)>>; ...@@ -53,12 +53,13 @@ using Checkpoint = testing::StrictMock<testing::MockFunction<void(int)>>;
constexpr char kFileName[] = "fox-null-terminated.html"; constexpr char kFileName[] = "fox-null-terminated.html";
class MockThreadableLoaderClient : public ThreadableLoaderClient { class MockThreadableLoaderClient final
: public GarbageCollectedFinalized<MockThreadableLoaderClient>,
public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(MockThreadableLoaderClient);
public: public:
static std::unique_ptr<MockThreadableLoaderClient> Create() { MockThreadableLoaderClient() = default;
return base::WrapUnique(
new testing::StrictMock<MockThreadableLoaderClient>);
}
MOCK_METHOD2(DidSendData, void(unsigned long long, unsigned long long)); MOCK_METHOD2(DidSendData, void(unsigned long long, unsigned long long));
MOCK_METHOD3(DidReceiveResponseMock, MOCK_METHOD3(DidReceiveResponseMock,
void(unsigned long, void(unsigned long,
...@@ -77,9 +78,6 @@ class MockThreadableLoaderClient : public ThreadableLoaderClient { ...@@ -77,9 +78,6 @@ class MockThreadableLoaderClient : public ThreadableLoaderClient {
MOCK_METHOD0(DidFailRedirectCheck, void()); MOCK_METHOD0(DidFailRedirectCheck, void());
MOCK_METHOD1(DidReceiveResourceTiming, void(const ResourceTimingInfo&)); MOCK_METHOD1(DidReceiveResourceTiming, void(const ResourceTimingInfo&));
MOCK_METHOD1(DidDownloadData, void(int)); MOCK_METHOD1(DidDownloadData, void(int));
protected:
MockThreadableLoaderClient() = default;
}; };
bool IsCancellation(const ResourceError& error) { bool IsCancellation(const ResourceError& error) {
...@@ -242,19 +240,21 @@ class ThreadableLoaderTest : public testing::Test { ...@@ -242,19 +240,21 @@ class ThreadableLoaderTest : public testing::Test {
void CreateLoader() { helper_->CreateLoader(Client()); } void CreateLoader() { helper_->CreateLoader(Client()); }
MockThreadableLoaderClient* Client() const { return client_.get(); } MockThreadableLoaderClient* Client() const { return client_.Get(); }
private: private:
void SetUp() override { void SetUp() override {
client_ = MockThreadableLoaderClient::Create(); client_ = MakeGarbageCollected<MockThreadableLoaderClient>();
helper_->OnSetUp(); helper_->OnSetUp();
} }
void TearDown() override { void TearDown() override {
helper_->OnTearDown(); helper_->OnTearDown();
client_.reset(); client_ = nullptr;
// We need GC here to avoid gmock flakiness.
ThreadState::Current()->CollectAllGarbage();
} }
std::unique_ptr<MockThreadableLoaderClient> client_; Persistent<MockThreadableLoaderClient> client_;
std::unique_ptr<ThreadableLoaderTestHelper> helper_; std::unique_ptr<ThreadableLoaderTestHelper> helper_;
}; };
......
...@@ -243,6 +243,7 @@ void WorkerClassicScriptLoader::Trace(Visitor* visitor) { ...@@ -243,6 +243,7 @@ void WorkerClassicScriptLoader::Trace(Visitor* visitor) {
visitor->Trace(threadable_loader_); visitor->Trace(threadable_loader_);
visitor->Trace(content_security_policy_); visitor->Trace(content_security_policy_);
visitor->Trace(execution_context_); visitor->Trace(execution_context_);
ThreadableLoaderClient::Trace(visitor);
} }
void WorkerClassicScriptLoader::Cancel() { void WorkerClassicScriptLoader::Cancel() {
......
...@@ -55,11 +55,7 @@ class TextResourceDecoder; ...@@ -55,11 +55,7 @@ class TextResourceDecoder;
class CORE_EXPORT WorkerClassicScriptLoader final class CORE_EXPORT WorkerClassicScriptLoader final
: public GarbageCollectedFinalized<WorkerClassicScriptLoader>, : public GarbageCollectedFinalized<WorkerClassicScriptLoader>,
public ThreadableLoaderClient { public ThreadableLoaderClient {
// We have to cancel |threadable_loader_| before destruction. Otherwise USING_GARBAGE_COLLECTED_MIXIN(WorkerClassicScriptLoader);
// DidFail() of the deleted |this| will be called from
// ThreadableLoader::NotifyFinished() when the associated context will be
// destroyed.
USING_PRE_FINALIZER(WorkerClassicScriptLoader, Cancel);
public: public:
WorkerClassicScriptLoader(); WorkerClassicScriptLoader();
...@@ -122,7 +118,7 @@ class CORE_EXPORT WorkerClassicScriptLoader final ...@@ -122,7 +118,7 @@ class CORE_EXPORT WorkerClassicScriptLoader final
void DidFail(const ResourceError&) override; void DidFail(const ResourceError&) override;
void DidFailRedirectCheck() override; void DidFailRedirectCheck() override;
virtual void Trace(Visitor*); void Trace(Visitor*) override;
private: private:
void NotifyError(); void NotifyError();
......
...@@ -2014,6 +2014,7 @@ void XMLHttpRequest::Trace(blink::Visitor* visitor) { ...@@ -2014,6 +2014,7 @@ void XMLHttpRequest::Trace(blink::Visitor* visitor) {
visitor->Trace(blob_loader_); visitor->Trace(blob_loader_);
visitor->Trace(response_text_); visitor->Trace(response_text_);
XMLHttpRequestEventTarget::Trace(visitor); XMLHttpRequestEventTarget::Trace(visitor);
ThreadableLoaderClient::Trace(visitor);
DocumentParserClient::Trace(visitor); DocumentParserClient::Trace(visitor);
PausableObject::Trace(visitor); PausableObject::Trace(visitor);
} }
......
...@@ -77,12 +77,6 @@ class XMLHttpRequest final : public XMLHttpRequestEventTarget, ...@@ -77,12 +77,6 @@ class XMLHttpRequest final : public XMLHttpRequestEventTarget,
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(XMLHttpRequest); USING_GARBAGE_COLLECTED_MIXIN(XMLHttpRequest);
// In some cases hasPendingActivity doesn't work correctly, i.e.,
// doesn't keep |this| alive. We need to cancel the loader in such cases,
// which is why we need this pre-finalizer.
// TODO(yhirano): Remove this pre-finalizer when the bug is fixed.
USING_PRE_FINALIZER(XMLHttpRequest, Dispose);
public: public:
static XMLHttpRequest* Create(ScriptState*); static XMLHttpRequest* Create(ScriptState*);
static XMLHttpRequest* Create(ExecutionContext*); static XMLHttpRequest* Create(ExecutionContext*);
......
...@@ -23,6 +23,8 @@ struct WebSize; ...@@ -23,6 +23,8 @@ struct WebSize;
class MODULES_EXPORT BackgroundFetchIconLoader final class MODULES_EXPORT BackgroundFetchIconLoader final
: public GarbageCollectedFinalized<BackgroundFetchIconLoader>, : public GarbageCollectedFinalized<BackgroundFetchIconLoader>,
public ThreadableLoaderClient { public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(BackgroundFetchIconLoader);
public: public:
// The bitmap may be empty if the request failed or the image data could not // The bitmap may be empty if the request failed or the image data could not
// be decoded. The int64_t returned is the scale of the ideal to chosen icon, // be decoded. The int64_t returned is the scale of the ideal to chosen icon,
...@@ -50,9 +52,10 @@ class MODULES_EXPORT BackgroundFetchIconLoader final ...@@ -50,9 +52,10 @@ class MODULES_EXPORT BackgroundFetchIconLoader final
void DidFail(const ResourceError& error) override; void DidFail(const ResourceError& error) override;
void DidFailRedirectCheck() override; void DidFailRedirectCheck() override;
void Trace(blink::Visitor* visitor) { void Trace(blink::Visitor* visitor) override {
visitor->Trace(threadable_loader_); visitor->Trace(threadable_loader_);
visitor->Trace(icons_); visitor->Trace(icons_);
ThreadableLoaderClient::Trace(visitor);
} }
private: private:
......
...@@ -359,6 +359,7 @@ void EventSource::Trace(blink::Visitor* visitor) { ...@@ -359,6 +359,7 @@ void EventSource::Trace(blink::Visitor* visitor) {
visitor->Trace(parser_); visitor->Trace(parser_);
visitor->Trace(loader_); visitor->Trace(loader_);
EventTargetWithInlineData::Trace(visitor); EventTargetWithInlineData::Trace(visitor);
ThreadableLoaderClient::Trace(visitor);
ContextLifecycleObserver::Trace(visitor); ContextLifecycleObserver::Trace(visitor);
EventSourceParser::Client::Trace(visitor); EventSourceParser::Client::Trace(visitor);
} }
......
...@@ -27,6 +27,8 @@ class ResourceError; ...@@ -27,6 +27,8 @@ class ResourceError;
class MODULES_EXPORT NotificationImageLoader final class MODULES_EXPORT NotificationImageLoader final
: public GarbageCollectedFinalized<NotificationImageLoader>, : public GarbageCollectedFinalized<NotificationImageLoader>,
public ThreadableLoaderClient { public ThreadableLoaderClient {
USING_GARBAGE_COLLECTED_MIXIN(NotificationImageLoader);
public: public:
// Type names are used in UMAs, so do not rename. // Type names are used in UMAs, so do not rename.
enum class Type { kImage, kIcon, kBadge, kActionIcon }; enum class Type { kImage, kIcon, kBadge, kActionIcon };
...@@ -59,7 +61,10 @@ class MODULES_EXPORT NotificationImageLoader final ...@@ -59,7 +61,10 @@ class MODULES_EXPORT NotificationImageLoader final
void DidFail(const ResourceError& error) override; void DidFail(const ResourceError& error) override;
void DidFailRedirectCheck() override; void DidFailRedirectCheck() override;
void Trace(blink::Visitor* visitor) { visitor->Trace(threadable_loader_); } void Trace(blink::Visitor* visitor) override {
visitor->Trace(threadable_loader_);
ThreadableLoaderClient::Trace(visitor);
}
private: private:
void RunCallbackWithEmptyBitmap(); void RunCallbackWithEmptyBitmap();
......
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