OLD | NEW |
| (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 "modules/fetch/FetchBlobDataConsumerHandle.h" | |
6 | |
7 #include "core/dom/ExecutionContext.h" | |
8 #include "core/fetch/FetchInitiatorTypeNames.h" | |
9 #include "core/loader/ThreadableLoaderClient.h" | |
10 #include "modules/fetch/CompositeDataConsumerHandle.h" | |
11 #include "modules/fetch/CrossThreadHolder.h" | |
12 #include "modules/fetch/DataConsumerHandleUtil.h" | |
13 #include "platform/blob/BlobRegistry.h" | |
14 #include "platform/blob/BlobURL.h" | |
15 #include "platform/network/ResourceRequest.h" | |
16 #include "wtf/PtrUtil.h" | |
17 #include <memory> | |
18 | |
19 namespace blink { | |
20 | |
21 using Result = FetchBlobDataConsumerHandle::Result; | |
22 | |
23 namespace { | |
24 | |
25 // Object graph: | |
26 // +-------------+ | |
27 // |ReaderContext| | |
28 // +-------------+ +-----------+ +---+ | | | |
29 // |LoaderContext|<-|CTH::Bridge|<->|CTH|<-| | | |
30 // +-------------+ +-----------+ +---+ +-------------+ | |
31 // | | |
32 // +--> ThreadableLoader | |
33 // | |
34 // When the loader thread is stopped, CrossThreadHolder::Bridge and | |
35 // LoaderContext (and thus ThreadableLoader) is destructed: | |
36 // +-------------+ | |
37 // |ReaderContext| | |
38 // +---+ | | | |
39 // |CTH|<-| | | |
40 // +---+ +-------------+ | |
41 // and the rest will be destructed when ReaderContext is destructed. | |
42 // | |
43 // When ReaderContext is destructed, CrossThreadHolder is destructed: | |
44 // | |
45 // +-------------+ +-----------+ | |
46 // |LoaderContext|<-|CTH::Bridge| | |
47 // +-------------+ +-----------+ | |
48 // | | |
49 // +--> ThreadableLoader | |
50 // and the rest will be shortly destructed when CrossThreadHolder::Bridge | |
51 // is garbage collected. | |
52 | |
53 // LoaderContext is created and destructed on the same thread | |
54 // (call this thread loader thread). | |
55 // All methods must be called on the loader thread. | |
56 class LoaderContext { | |
57 public: | |
58 virtual ~LoaderContext() { } | |
59 virtual void start(ExecutionContext*) = 0; | |
60 }; | |
61 | |
62 // All methods must be called on the loader thread. | |
63 class BlobLoaderContext final | |
64 : public LoaderContext | |
65 , public ThreadableLoaderClient { | |
66 public: | |
67 BlobLoaderContext(CompositeDataConsumerHandle::Updater* updater, PassRefPtr<
BlobDataHandle> blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* load
erFactory) | |
68 : m_updater(updater) | |
69 , m_blobDataHandle(blobDataHandle) | |
70 , m_loaderFactory(loaderFactory) | |
71 , m_receivedResponse(false) { } | |
72 | |
73 ~BlobLoaderContext() override | |
74 { | |
75 if (m_loader && !m_receivedResponse) | |
76 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
77 if (m_loader) { | |
78 m_loader->cancel(); | |
79 m_loader = nullptr; | |
80 } | |
81 if (!m_registeredBlobURL.isEmpty()) | |
82 BlobRegistry::revokePublicBlobURL(m_registeredBlobURL); | |
83 } | |
84 | |
85 void start(ExecutionContext* executionContext) override | |
86 { | |
87 ASSERT(executionContext->isContextThread()); | |
88 ASSERT(!m_loader); | |
89 | |
90 m_registeredBlobURL = BlobURL::createPublicURL(executionContext->getSecu
rityOrigin()); | |
91 if (m_registeredBlobURL.isEmpty()) { | |
92 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
93 return; | |
94 } | |
95 BlobRegistry::registerPublicBlobURL(executionContext->getSecurityOrigin(
), m_registeredBlobURL, m_blobDataHandle); | |
96 | |
97 m_loader = createLoader(executionContext, this); | |
98 ASSERT(m_loader); | |
99 | |
100 ResourceRequest request(m_registeredBlobURL); | |
101 request.setRequestContext(WebURLRequest::RequestContextInternal); | |
102 request.setUseStreamOnResponse(true); | |
103 // We intentionally skip 'setExternalRequestStateFromRequestorAddressSpa
ce', as 'data:' can never be external. | |
104 m_loader->start(request); | |
105 } | |
106 | |
107 private: | |
108 ThreadableLoader* createLoader(ExecutionContext* executionContext, Threadabl
eLoaderClient* client) const | |
109 { | |
110 ThreadableLoaderOptions options; | |
111 options.preflightPolicy = ConsiderPreflight; | |
112 options.crossOriginRequestPolicy = DenyCrossOriginRequests; | |
113 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPo
licy; | |
114 options.initiator = FetchInitiatorTypeNames::internal; | |
115 | |
116 ResourceLoaderOptions resourceLoaderOptions; | |
117 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; | |
118 | |
119 return m_loaderFactory->create(*executionContext, client, options, resou
rceLoaderOptions); | |
120 } | |
121 | |
122 // ThreadableLoaderClient | |
123 void didReceiveResponse(unsigned long, const ResourceResponse&, std::unique_
ptr<WebDataConsumerHandle> handle) override | |
124 { | |
125 ASSERT(!m_receivedResponse); | |
126 m_receivedResponse = true; | |
127 if (!handle) { | |
128 // Here we assume WebURLLoader must return the response body as | |
129 // |WebDataConsumerHandle| since we call | |
130 // request.setUseStreamOnResponse(). | |
131 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
132 return; | |
133 } | |
134 m_updater->update(std::move(handle)); | |
135 } | |
136 | |
137 void didFinishLoading(unsigned long, double) override | |
138 { | |
139 m_loader = nullptr; | |
140 } | |
141 | |
142 void didFail(const ResourceError&) override | |
143 { | |
144 if (!m_receivedResponse) | |
145 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
146 m_loader = nullptr; | |
147 } | |
148 | |
149 void didFailRedirectCheck() override | |
150 { | |
151 // We don't expect redirects for Blob loading. | |
152 ASSERT_NOT_REACHED(); | |
153 } | |
154 | |
155 Persistent<CompositeDataConsumerHandle::Updater> m_updater; | |
156 | |
157 RefPtr<BlobDataHandle> m_blobDataHandle; | |
158 Persistent<FetchBlobDataConsumerHandle::LoaderFactory> m_loaderFactory; | |
159 Persistent<ThreadableLoader> m_loader; | |
160 KURL m_registeredBlobURL; | |
161 | |
162 bool m_receivedResponse; | |
163 }; | |
164 | |
165 class DefaultLoaderFactory final : public FetchBlobDataConsumerHandle::LoaderFac
tory { | |
166 public: | |
167 ThreadableLoader* create( | |
168 ExecutionContext& executionContext, | |
169 ThreadableLoaderClient* client, | |
170 const ThreadableLoaderOptions& options, | |
171 const ResourceLoaderOptions& resourceLoaderOptions) override | |
172 { | |
173 return ThreadableLoader::create(executionContext, client, options, resou
rceLoaderOptions); | |
174 } | |
175 }; | |
176 | |
177 } // namespace | |
178 | |
179 // ReaderContext is referenced from FetchBlobDataConsumerHandle and | |
180 // ReaderContext::ReaderImpl. | |
181 // All functions/members must be called/accessed only on the reader thread, | |
182 // except for constructor, destructor, and obtainReader(). | |
183 class FetchBlobDataConsumerHandle::ReaderContext final : public ThreadSafeRefCou
nted<ReaderContext> { | |
184 public: | |
185 class ReaderImpl : public FetchDataConsumerHandle::Reader { | |
186 public: | |
187 ReaderImpl(Client* client, PassRefPtr<ReaderContext> readerContext, std:
:unique_ptr<WebDataConsumerHandle::Reader> reader) | |
188 : m_readerContext(readerContext) | |
189 , m_reader(std::move(reader)) | |
190 , m_notifier(client) { } | |
191 ~ReaderImpl() override { } | |
192 | |
193 Result read(void* data, size_t size, Flags flags, size_t* readSize) over
ride | |
194 { | |
195 if (m_readerContext->drained()) | |
196 return Done; | |
197 Result r = m_reader->read(data, size, flags, readSize); | |
198 if (!(size == 0 && (r == Ok || r == ShouldWait))) { | |
199 // We read non-empty data, so we cannot use the blob data | |
200 // handle which represents the whole data. | |
201 m_readerContext->clearBlobDataHandleForDrain(); | |
202 m_readerContext->ensureStartLoader(); | |
203 } | |
204 return r; | |
205 } | |
206 | |
207 Result beginRead(const void** buffer, Flags flags, size_t* available) ov
erride | |
208 { | |
209 if (m_readerContext->drained()) | |
210 return Done; | |
211 m_readerContext->ensureStartLoader(); | |
212 m_readerContext->clearBlobDataHandleForDrain(); | |
213 return m_reader->beginRead(buffer, flags, available); | |
214 } | |
215 | |
216 Result endRead(size_t readSize) override | |
217 { | |
218 return m_reader->endRead(readSize); | |
219 } | |
220 | |
221 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy blobSize
Policy) override | |
222 { | |
223 if (!m_readerContext->m_blobDataHandleForDrain) | |
224 return nullptr; | |
225 if (blobSizePolicy == DisallowBlobWithInvalidSize && m_readerContext
->m_blobDataHandleForDrain->size() == UINT64_MAX) | |
226 return nullptr; | |
227 RefPtr<BlobDataHandle> blobDataHandle = m_readerContext->m_blobDataH
andleForDrain; | |
228 m_readerContext->setDrained(); | |
229 m_readerContext->clearBlobDataHandleForDrain(); | |
230 return blobDataHandle.release(); | |
231 } | |
232 | |
233 PassRefPtr<EncodedFormData> drainAsFormData() override | |
234 { | |
235 RefPtr<BlobDataHandle> handle = drainAsBlobDataHandle(AllowBlobWithI
nvalidSize); | |
236 if (!handle) | |
237 return nullptr; | |
238 RefPtr<EncodedFormData> formData = EncodedFormData::create(); | |
239 formData->appendBlob(handle->uuid(), handle); | |
240 return formData.release(); | |
241 } | |
242 | |
243 private: | |
244 RefPtr<ReaderContext> m_readerContext; | |
245 std::unique_ptr<WebDataConsumerHandle::Reader> m_reader; | |
246 NotifyOnReaderCreationHelper m_notifier; | |
247 }; | |
248 | |
249 ReaderContext(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle>
blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory) | |
250 : m_blobDataHandleForDrain(blobDataHandle) | |
251 , m_loaderStarted(false) | |
252 , m_drained(false) | |
253 { | |
254 CompositeDataConsumerHandle::Updater* updater = nullptr; | |
255 m_handle = CompositeDataConsumerHandle::create(createWaitingDataConsumer
Handle(), &updater); | |
256 m_loaderContextHolder = CrossThreadHolder<LoaderContext>::create(executi
onContext, wrapUnique(new BlobLoaderContext(updater, m_blobDataHandleForDrain, l
oaderFactory))); | |
257 } | |
258 | |
259 std::unique_ptr<FetchDataConsumerHandle::Reader> obtainReader(WebDataConsume
rHandle::Client* client) | |
260 { | |
261 return wrapUnique(new ReaderImpl(client, this, m_handle->obtainReader(cl
ient))); | |
262 } | |
263 | |
264 private: | |
265 void ensureStartLoader() | |
266 { | |
267 if (m_loaderStarted) | |
268 return; | |
269 m_loaderStarted = true; | |
270 m_loaderContextHolder->postTask(crossThreadBind(&LoaderContext::start)); | |
271 } | |
272 | |
273 void clearBlobDataHandleForDrain() | |
274 { | |
275 m_blobDataHandleForDrain.clear(); | |
276 } | |
277 | |
278 bool drained() const { return m_drained; } | |
279 void setDrained() { m_drained = true; } | |
280 | |
281 std::unique_ptr<WebDataConsumerHandle> m_handle; | |
282 RefPtr<BlobDataHandle> m_blobDataHandleForDrain; | |
283 std::unique_ptr<CrossThreadHolder<LoaderContext>> m_loaderContextHolder; | |
284 | |
285 bool m_loaderStarted; | |
286 bool m_drained; | |
287 }; | |
288 | |
289 FetchBlobDataConsumerHandle::FetchBlobDataConsumerHandle(ExecutionContext* execu
tionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFactory* loaderFac
tory) | |
290 : m_readerContext(adoptRef(new ReaderContext(executionContext, std::move(blo
bDataHandle), loaderFactory))) | |
291 { | |
292 } | |
293 | |
294 FetchBlobDataConsumerHandle::~FetchBlobDataConsumerHandle() | |
295 { | |
296 } | |
297 | |
298 std::unique_ptr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Exe
cutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, Load
erFactory* loaderFactory) | |
299 { | |
300 if (!blobDataHandle) | |
301 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); | |
302 | |
303 return wrapUnique(new FetchBlobDataConsumerHandle(executionContext, std::mov
e(blobDataHandle), loaderFactory)); | |
304 } | |
305 | |
306 std::unique_ptr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Exe
cutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle) | |
307 { | |
308 if (!blobDataHandle) | |
309 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); | |
310 | |
311 return wrapUnique(new FetchBlobDataConsumerHandle(executionContext, std::mov
e(blobDataHandle), new DefaultLoaderFactory)); | |
312 } | |
313 | |
314 std::unique_ptr<FetchDataConsumerHandle::Reader> FetchBlobDataConsumerHandle::ob
tainFetchDataReader(Client* client) | |
315 { | |
316 return m_readerContext->obtainReader(client); | |
317 } | |
318 | |
319 } // namespace blink | |
OLD | NEW |