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

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

Issue 1176403006: [1b] Implement FetchBlobDataConsumerHandle (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 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);
yhirano 2015/06/23 07:32:06 Not needed
hiroshige 2015/06/23 08:34:22 Done.
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:
yhirano 2015/06/23 07:32:06 [optional] I like creating |static PassRefPtr<Peer
hiroshige 2015/06/23 08:34:22 Done.
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
yhirano 2015/06/23 07:32:06 This class can be final now.
hiroshige 2015/06/23 08:34:22 Done.
239 : public LoaderContext
240 , public ThreadableLoaderClient {
241 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED(LoaderContext);
yhirano 2015/06/23 07:32:06 I assume this is oilpan related, but this class is
hiroshige 2015/06/23 08:34:22 Done.
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()
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.
yhirano 2015/06/23 07:32:06 s/FetchDataConsumerHandle::Reader/ReaderContext::R
hiroshige 2015/06/23 08:34:22 Done.
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->clearBlobDataHandle();
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->clearBlobDataHandle();
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->drained() || !m_readerContext->blobDataHandle() || m_readerContext->blobDataHandle()->size() == kuint64max)
398 return nullptr;
399 m_readerContext->setDrained();
400 m_readerContext->clearBlobDataHandle();
401 return m_readerContext->blobDataHandle();
402 }
403
404 private:
405 RefPtr<ReaderContext> m_readerContext;
406 OwnPtr<WebDataConsumerHandle::Reader> m_reader;
407 NotifyOnReaderCreationHelper m_notifier;
408 };
409
410 ReaderContext(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory)
411 : m_commonContext(adoptRef(new CommonContext()))
412 , m_loaderStarted(false)
413 , m_blobDataHandle(blobDataHandle)
414 , m_drained(false)
415 {
416 m_commonContext->initialize(executionContext, adoptPtr(new BlobLoaderCon text(m_commonContext, m_blobDataHandle, loaderFactory)));
417 }
418
419 ~ReaderContext()
420 {
421 m_commonContext->clearLoaderContext();
422 }
423
424 PassOwnPtr<FetchDataConsumerHandle::Reader> obtainReader(WebDataConsumerHand le::Client* client)
425 {
426 return adoptPtr(new ReaderImpl(client, this, m_commonContext->handle()-> obtainReader(client)));
427 }
428 bool drained() const { return m_drained; }
429 void setDrained() { m_drained = true; }
430
431 void ensureStartLoader()
432 {
433 if (m_loaderStarted)
434 return;
435 m_loaderStarted = true;
436 m_commonContext->startLoader();
437 }
438
439 private:
440 // Must be called on the reader thread.
yhirano 2015/06/23 07:32:06 [optional] It looks all functions / members are bo
hiroshige 2015/06/23 08:34:22 Done.
441 PassRefPtr<BlobDataHandle> blobDataHandle() const
442 {
443 if (!m_drained)
444 return m_blobDataHandle;
445 return nullptr;
446 }
447 void clearBlobDataHandle() { m_blobDataHandle = nullptr; }
448
449 RefPtr<CommonContext> m_commonContext;
450
451 // |m_loaderStarted| must be accessed only on the reader thread.
452 bool m_loaderStarted;
453
454 // |m_blobDataHandle| must be accessed only on the reader thread.
455 RefPtr<BlobDataHandle> m_blobDataHandle;
456 bool m_drained;
457 };
458
459 FetchBlobDataConsumerHandle::FetchBlobDataConsumerHandle(ExecutionContext* execu tionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFactory* loaderFac tory)
460 : m_readerContext(adoptRef(new ReaderContext(executionContext, blobDataHandl e, loaderFactory)))
461 {
462 }
463
464 PassOwnPtr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Executio nContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFac tory* loaderFactory)
465 {
466 if (!blobDataHandle)
467 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer Handle());
468
469 return adoptPtr(new FetchBlobDataConsumerHandle(executionContext, blobDataHa ndle, loaderFactory));
470 }
471
472 PassOwnPtr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Executio nContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle)
473 {
474 if (!blobDataHandle)
475 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer Handle());
476
477 return adoptPtr(new FetchBlobDataConsumerHandle(executionContext, blobDataHa ndle, new DefaultLoaderFactory));
478 }
479
480 FetchDataConsumerHandle::Reader* FetchBlobDataConsumerHandle::obtainReaderIntern al(Client* client)
481 {
482 return m_readerContext->obtainReader(client).leakPtr();
483 }
484
485 } // 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