Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: Source/modules/fetch/FetchBlobDataConsumerHandle.cpp

Issue 1171913003: **** [WIP] Blink-side: Implement FetchBlobDataConsumerHandle **** (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Clean up. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/fetch/FetchBlobDataConsumerHandle.h"
7
8 #include "core/dom/ActiveDOMObject.h"
9 #include "core/dom/CrossThreadTask.h"
10 #include "core/dom/ExecutionContext.h"
11 #include "core/fetch/FetchInitiatorTypeNames.h"
12 #include "core/loader/ThreadableLoaderClient.h"
13 #include "modules/fetch/CompositeDataConsumerHandle.h"
14 #include "modules/fetch/DataConsumerHandleUtil.h"
15 #include "platform/Task.h"
16 #include "platform/blob/BlobRegistry.h"
17 #include "platform/blob/BlobURL.h"
18 #include "platform/network/ResourceRequest.h"
19 #include "public/platform/Platform.h"
20 #include "public/platform/WebTraceLocation.h"
21 #include "wtf/Locker.h"
22 #include "wtf/ThreadingPrimitives.h"
23
24 namespace blink {
25
26 using Result = FetchBlobDataConsumerHandle::Result;
27
28 namespace {
29
30 // CrossThreadHolder<T> provides cross-thread access to |obj| of class T.
31 // CrossThreadHolder<T> can be passed across threads while |obj|'s methods
32 // are called on the fixed thread of |executionContext| via
33 // CrossThreadHolder<T>::postTask().
34 // |obj| is destructed when |executionContext| is stopped or
35 // CrossThreadHolder is destructed (earlier of them).
36 template<typename T>
37 class CrossThreadHolder {
38 public:
39 static PassOwnPtr<CrossThreadHolder<T>> create(ExecutionContext* executionCo ntext, PassOwnPtr<T> obj)
40 {
41 return adoptPtr(new CrossThreadHolder(executionContext, obj));
42 }
43
44 // Can be called from any thread.
45 // Executes |task| with |obj| and |executionContext| on the thread of
46 // |executionContext|.
47 // NOTE: |task| might be silently ignored (i.e. not executed) when
48 // |executionContext| is stopped.
49 void postTask(PassOwnPtr<WTF::Function<void(T*, ExecutionContext*)>> task)
50 {
51 m_peer->postTask(task);
52 }
53
54 ~CrossThreadHolder()
55 {
56 m_peer->clear();
57 }
58
59 private:
60 CrossThreadHolder(ExecutionContext* executionContext, PassOwnPtr<T> obj)
61 : m_peer(adoptRef(new Peer()))
62 {
63 m_peer->initialize(new Bridge(executionContext, m_peer, obj));
64 }
65
66 // Bridge and Peer have a reference cycle:
67 // T <-OwnPtr- |Bridge| ---------RefPtr--------> |Peer| <-(RefPtr)- CTH
68 // | | <-CrossThreadPersistent- | |
69 // CTH: CrossThreadHolder<T>
70 // The reference from Peer to Bridge is protected by |Peer::m_mutex| and
71 // cleared when Peer::clear() is called, i.e.:
72 // [1] when |executionContext| is stopped:
73 // T <-OwnPtr- |Bridge| ---------RefPtr--------> |Peer| <-(RefPtr)- CTH
74 // [2] or when CrossThreadHolder is destructed:
75 // T <-OwnPtr- |Bridge| ---------RefPtr--------> |Peer|
76 // in either case, Bridge is shortly garbage collected.
77
78 class Peer;
79
80 // All methods must be called on |executionContext|'s thread.
81 class Bridge
82 : public GarbageCollectedFinalized<Bridge>
83 , public ActiveDOMObject {
84 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(Bridge);
85 public:
86 Bridge(ExecutionContext* executionContext, PassRefPtr<Peer> peer, PassOw nPtr<T> obj)
87 : ActiveDOMObject(executionContext)
88 , m_peer(peer)
89 , m_obj(obj)
90 {
91 suspendIfNeeded();
92 }
93
94 DEFINE_INLINE_TRACE()
95 {
96 visitor->trace(m_obj);
97 ActiveDOMObject::trace(visitor);
98 }
99
100 T* getObject() const { return m_obj.get(); }
101
102 private:
103 // ActiveDOMObject
104 void stop() override
105 {
106 ASSERT(executionContext()->isContextThread());
107 m_obj.clear();
108 m_peer->clear();
109 }
110
111 RefPtr<Peer> m_peer;
112 OwnPtr<T> m_obj;
113 };
114
115 class Peer : public ThreadSafeRefCounted<Peer> {
116 public:
117 // initialize() must be called only just after construction to create a
118 // reference cycle.
119 void initialize(Bridge* bridge)
120 {
121 m_bridge = bridge;
122 }
123
124 void clear()
125 {
126 MutexLocker locker(m_mutex);
127 m_bridge.clear();
128 }
129
130 void postTask(PassOwnPtr<WTF::Function<void(T*, ExecutionContext*)>> tas k)
131 {
132 MutexLocker locker(m_mutex);
133 if (!m_bridge) {
134 // The bridge has already disappeared.
135 return;
136 }
137 m_bridge->executionContext()->postTask(FROM_HERE, createCrossThreadT ask(&Peer::runTask, this, task));
138 }
139
140 private:
141 // Must be called on the loader thread.
142 void runTask(PassOwnPtr<WTF::Function<void(T*, ExecutionContext*)>> task )
143 {
144 Bridge* bridge;
145 {
146 MutexLocker locker(m_mutex);
147 bridge = m_bridge.get();
148 if (!bridge) {
149 // LoaderContext has already disappeared.
150 return;
151 }
152 ASSERT(bridge->executionContext()->isContextThread());
153 }
154
155 // |bridge| can be set to nullptr by another thread after the
156 // mutex is unlocked, but we can still use |loaderContext| here beca use
157 // the LoaderContext belongs to the current thread (== the loader th read).
158 (*task)(bridge->getObject(), bridge->executionContext());
159 }
160
161 // |m_brige| is protected by |m_mutex|.
162 CrossThreadPersistent<Bridge> m_bridge;
163 Mutex m_mutex;
164 };
165
166 RefPtr<Peer> m_peer;
167 };
168
169 // LoaderContext and associated ThreadableLoader is created and
170 // destructed on the same thread (call this thread loader thread).
171 // All methods must be called on the loader thread.
172 // CommonContext and LoaderContext have a reference cycle:
173 // CTH <-----(OwnPtr)----+
174 // | |
175 // (CrossThreadPersistent) |
176 // v |
177 // LC ----(RefPtr)----> CC <-- RC
178 // LC: LoaderContext
179 // CC: CommonContext
180 // RC: ReaderContext
181 // CTH: CrossThreadHolder<LoaderContext>
182 // This cycle is broken when CommonContext::clearLoaderContext() is called
183 // (which clears the reference to CrossThreadHolder),
184 // or ExecutionContext of the loader thread is stopped
185 // (CrossThreadHolder clears the reference to LoaderContext).
186
187 class LoaderContext {
188 public:
189 virtual ~LoaderContext() { }
190 virtual void start(ExecutionContext*) = 0;
191 };
192
193 class CommonContext
194 : public ThreadSafeRefCounted<CommonContext> {
195 public:
196 CommonContext()
197 : m_handle(CompositeDataConsumerHandle::create(createWaitingDataConsumer Handle())) { }
198
199 // initialize() must be called only just after construction to create a
200 // reference cycle.
201 void initialize(ExecutionContext* executionContext, PassOwnPtr<LoaderContext > loaderContext)
202 {
203 m_loaderContextHolder = CrossThreadHolder<LoaderContext>::create(executi onContext, loaderContext);
204 }
205
206 CompositeDataConsumerHandle* handle() { return m_handle.get(); }
207
208 void startLoader()
209 {
210 MutexLocker locker(m_mutex);
211 if (m_loaderContextHolder)
212 m_loaderContextHolder->postTask(threadSafeBind<LoaderContext*, Execu tionContext*>(&LoaderContext::start));
213 }
214
215 void clearLoaderContext()
216 {
217 MutexLocker locker(m_mutex);
218 m_loaderContextHolder.clear();
219 }
220
221 // Must be called on the loader thread.
222 void error()
223 {
224 clearLoaderContext();
225 handle()->update(createUnexpectedErrorDataConsumerHandle());
226 }
227
228 private:
229 OwnPtr<CompositeDataConsumerHandle> m_handle;
230
231 // |m_loaderContextHolder| is protected by |m_mutex|.
232 OwnPtr<CrossThreadHolder<LoaderContext>> m_loaderContextHolder;
233 Mutex m_mutex;
234 };
235
236 // All methods must be called on the loader thread.
237 // This class is not final for testing.
238 class BlobLoaderContext
239 : public LoaderContext
240 , public ThreadableLoaderClient {
241 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(LoaderContext);
242 public:
243 BlobLoaderContext(PassRefPtr<CommonContext> commonContext, PassRefPtr<BlobDa taHandle> blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* loaderFact ory)
244 : m_commonContext(commonContext)
245 , m_blobDataHandle(blobDataHandle)
246 , m_loaderFactory(loaderFactory)
247 , m_receivedResponse(false) { }
248
249 ~BlobLoaderContext() override
250 {
251 if (m_loader && !m_receivedResponse)
252 m_commonContext->handle()->update(createUnexpectedErrorDataConsumerH andle());
253 if (m_loader) {
254 m_loader->cancel();
255 m_loader.clear();
256 }
257 }
258
259 void start(ExecutionContext* executionContext) override
260 {
261 ASSERT(executionContext->isContextThread());
262 ASSERT(!m_loader);
263
264 m_loader = createLoader(executionContext, this);
265 if (!m_loader)
266 m_commonContext->error();
267 }
268
269 private:
270 virtual PassRefPtr<ThreadableLoader> createLoader(ExecutionContext* executio nContext, ThreadableLoaderClient* client) const
271 {
272 KURL url = BlobURL::createPublicURL(executionContext->securityOrigin());
273 if (url.isEmpty()) {
274 return nullptr;
275 }
276 BlobRegistry::registerPublicBlobURL(executionContext->securityOrigin(), url, m_blobDataHandle);
277
278 ResourceRequest request(url);
279 request.setRequestContext(WebURLRequest::RequestContextInternal);
280 request.setUseStreamOnResponse(true);
281
282 ThreadableLoaderOptions options;
283 options.preflightPolicy = ConsiderPreflight;
284 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
285 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPo licy;
286 options.initiator = FetchInitiatorTypeNames::internal;
287
288 ResourceLoaderOptions resourceLoaderOptions;
289 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
290
291 return m_loaderFactory->create(*executionContext, client, request, optio ns, resourceLoaderOptions);
292 }
293
294 // ThreadableLoaderClient
295 void didReceiveResponse(unsigned long, const ResourceResponse&, PassOwnPtr<W ebDataConsumerHandle> handle) override
296 {
297 ASSERT(!m_receivedResponse);
298 m_receivedResponse = true;
299 if (!handle) {
300 // Here we assume WebURLLoader must return the response body as
301 // |WebDataConsumerHandle| since we call
302 // request.setUseStreamOnResponse().
303 m_commonContext->handle()->update(createUnexpectedErrorDataConsumerH andle());
304 return;
305 }
306 m_commonContext->handle()->update(handle);
307 }
308 void didFinishLoading(unsigned long, double) override
309 {
310 m_commonContext->clearLoaderContext();
311 }
312 void didFail(const ResourceError&) override
313 {
314 if (m_receivedResponse)
315 m_commonContext->clearLoaderContext();
316 else
317 m_commonContext->error();
318 }
319 void didFailRedirectCheck() override
320 {
321 if (m_receivedResponse)
322 m_commonContext->clearLoaderContext();
323 else
324 m_commonContext->error();
325 }
326
327 RefPtr<CommonContext> m_commonContext;
328 RefPtr<BlobDataHandle> m_blobDataHandle;
329 Persistent<FetchBlobDataConsumerHandle::LoaderFactory> m_loaderFactory;
330 RefPtr<ThreadableLoader> m_loader;
331
332 bool m_receivedResponse;
333 };
334
335 class DefaultLoaderFactory final : public FetchBlobDataConsumerHandle::LoaderFac tory {
336 public:
337 PassRefPtr<ThreadableLoader> create(
338 ExecutionContext& executionContext,
339 ThreadableLoaderClient* client,
340 const ResourceRequest& request,
341 const ThreadableLoaderOptions& options,
342 const ResourceLoaderOptions& resourceLoaderOptions) override
343 {
344 return ThreadableLoader::create(executionContext, client, request, optio ns, resourceLoaderOptions);
345 }
346 };
347
348 } // namespace
349
350 // ReaderContext is referenced from FetchBlobDataConsumerHandle and
351 // FetchDataConsumerHandle::Reader.
352 class FetchBlobDataConsumerHandle::ReaderContext : public ThreadSafeRefCounted<R eaderContext> {
353 public:
354 class ReaderImpl : public FetchDataConsumerHandle::Reader {
355 public:
356 ReaderImpl(Client* client, PassRefPtr<ReaderContext> readerContext, Pass OwnPtr<WebDataConsumerHandle::Reader> reader)
357 : m_readerContext(readerContext)
358 , m_reader(reader)
359 , m_notifier(client) { }
360 ~ReaderImpl() override { }
361
362 Result read(void* data, size_t size, Flags flags, size_t* readSize) over ride
363 {
364 if (m_readerContext->drained())
365 return Done;
366 m_readerContext->ensureStartLoader();
367 Result r = m_reader->read(data, size, flags, readSize);
368 if (r != ShouldWait) {
369 // We read non-empty data, so we cannot use the blob data handle which
370 // represents the whole data.
371 m_readerContext->clearBlobDataHandleForDrain();
372 }
373 return r;
374 }
375
376 Result beginRead(const void** buffer, Flags flags, size_t* available) ov erride
377 {
378 if (m_readerContext->drained())
379 return Done;
380 m_readerContext->ensureStartLoader();
381 Result r = m_reader->beginRead(buffer, flags, available);
382 if (r != ShouldWait) {
383 // We read non-empty data, so we cannot use the blob data handle which
384 // represents the whole data.
385 m_readerContext->clearBlobDataHandleForDrain();
386 }
387 return r;
388 }
389
390 Result endRead(size_t readSize) override
391 {
392 return m_reader->endRead(readSize);
393 }
394
395 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle() override
396 {
397 if (!m_readerContext->m_blobDataHandleForDrain || m_readerContext->m _blobDataHandleForDrain->size() == kuint64max)
398 return nullptr;
399 RefPtr<BlobDataHandle> blobDataHandle = m_readerContext->m_blobDataH andleForDrain;
400 m_readerContext->setDrained();
401 m_readerContext->clearBlobDataHandleForDrain();
402 return blobDataHandle.release();
403 }
404
405 private:
406 RefPtr<ReaderContext> m_readerContext;
407 OwnPtr<WebDataConsumerHandle::Reader> m_reader;
408 NotifyOnReaderCreationHelper m_notifier;
409 };
410
411 ReaderContext(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory)
412 : m_commonContext(adoptRef(new CommonContext()))
413 , m_loaderStarted(false)
414 , m_drained(false)
415 , m_blobDataHandleForDrain(blobDataHandle)
416 {
417 m_commonContext->initialize(executionContext, adoptPtr(new BlobLoaderCon text(m_commonContext, m_blobDataHandleForDrain, loaderFactory)));
418 }
419
420 ~ReaderContext()
421 {
422 m_commonContext->clearLoaderContext();
423 }
424
425 PassOwnPtr<FetchDataConsumerHandle::Reader> obtainReader(WebDataConsumerHand le::Client* client)
426 {
427 return adoptPtr(new ReaderImpl(client, this, m_commonContext->handle()-> obtainReader(client)));
428 }
429
430 void ensureStartLoader()
431 {
432 if (m_loaderStarted)
433 return;
434 m_loaderStarted = true;
435 m_commonContext->startLoader();
436 }
437
438 void clearBlobDataHandleForDrain()
439 {
440 m_blobDataHandleForDrain.clear();
441 }
442
443 private:
444 bool drained() const { return m_drained; }
445 void setDrained() { m_drained = true; }
446
447 RefPtr<CommonContext> m_commonContext;
448
449 // Following members must be accessed only on the reader thread.
450 bool m_loaderStarted;
451 bool m_drained;
452 RefPtr<BlobDataHandle> m_blobDataHandleForDrain;
453 };
454
455 FetchBlobDataConsumerHandle::FetchBlobDataConsumerHandle(ExecutionContext* execu tionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFactory* loaderFac tory)
456 : m_readerContext(adoptRef(new ReaderContext(executionContext, blobDataHandl e, loaderFactory)))
457 {
458 }
459
460 PassOwnPtr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Executio nContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFac tory* loaderFactory)
461 {
462 if (!blobDataHandle)
463 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer Handle());
464
465 return adoptPtr(new FetchBlobDataConsumerHandle(executionContext, blobDataHa ndle, loaderFactory));
466 }
467
468 PassOwnPtr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Executio nContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle)
469 {
470 if (!blobDataHandle)
471 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer Handle());
472
473 return adoptPtr(new FetchBlobDataConsumerHandle(executionContext, blobDataHa ndle, new DefaultLoaderFactory));
474 }
475
476 FetchDataConsumerHandle::Reader* FetchBlobDataConsumerHandle::obtainReaderIntern al(Client* client)
477 {
478 return m_readerContext->obtainReader(client).leakPtr();
479 }
480
481 } // namespace blink
OLDNEW
« no previous file with comments | « Source/modules/fetch/FetchBlobDataConsumerHandle.h ('k') | Source/modules/fetch/FetchBlobDataConsumerHandleTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698