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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/BlobBytesConsumer.cpp

Issue 2287323002: Implement BlobBytesConsumer (Closed)
Patch Set: fix Created 4 years, 3 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 2016 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/BlobBytesConsumer.h"
6
7 #include "core/fetch/FetchInitiatorTypeNames.h"
8 #include "core/loader/ThreadableLoader.h"
9 #include "modules/fetch/BytesConsumerForDataConsumerHandle.h"
10 #include "modules/fetch/DataConsumerHandleUtil.h"
11 #include "platform/blob/BlobData.h"
12 #include "platform/blob/BlobRegistry.h"
13 #include "platform/blob/BlobURL.h"
14 #include "platform/network/ResourceError.h"
15 #include "platform/network/ResourceRequest.h"
16 #include "platform/weborigin/KURL.h"
17 #include "platform/weborigin/SecurityOrigin.h"
18
19 namespace blink {
20
21 BlobBytesConsumer::BlobBytesConsumer(ExecutionContext* executionContext, PassRef Ptr<BlobDataHandle> blobDataHandle, ThreadableLoader* loader)
22 : ContextLifecycleObserver(executionContext)
23 , m_blobDataHandle(blobDataHandle)
24 , m_loader(loader)
25 {
26 ThreadState::current()->registerPreFinalizer(this);
27 }
28
29 BlobBytesConsumer::BlobBytesConsumer(ExecutionContext* executionContext, PassRef Ptr<BlobDataHandle> blobDataHandle)
30 : BlobBytesConsumer(executionContext, blobDataHandle, nullptr)
31 {
32 }
33
34 BlobBytesConsumer::~BlobBytesConsumer()
35 {
36 }
37
38 BytesConsumer::Result BlobBytesConsumer::beginRead(const char** buffer, size_t* available)
39 {
40 *buffer = nullptr;
41 *available = 0;
42
43 if (m_hasSeenEndOfData && m_hasFinishedLoading) {
44 // It's possible that |cancel| has been called before the first
45 // |beginRead| call. That's why we need to check this condition
46 // before checking |m_hasStarted|.
47 return Result::Done;
48 }
49
50 if (!m_hasStarted) {
51 m_hasStarted = true;
52
53 SecurityOrigin* origin = getExecutionContext()->getSecurityOrigin();
hiroshige 2016/09/13 03:57:23 SecurityOrigin is RefCounted and thus using a raw
yhirano 2016/09/13 05:13:51 Done.
54 KURL m_blobURL = BlobURL::createPublicURL(origin);
55 if (m_blobURL.isEmpty()) {
56 m_hasFailedToLoad = true;
57 } else {
58 BlobRegistry::registerPublicBlobURL(origin, m_blobURL, m_blobDataHan dle);
59
60 // m_loader is non-null only in tests.
61 if (!m_loader)
62 m_loader = createLoader();
63
64 ResourceRequest request(m_blobURL);
65 request.setRequestContext(WebURLRequest::RequestContextInternal);
66 request.setUseStreamOnResponse(true);
67 // We intentionally skip
68 // 'setExternalRequestStateFromRequestorAddressSpace', as 'data:'
hiroshige 2016/09/13 03:57:23 'blob:' instead of 'data:'? (not sure)
yhirano 2016/09/13 05:13:51 Done.
69 // can never be external.
70 m_loader->start(request);
71 }
72 }
73
74 if (m_hasFailedToLoad)
75 return Result::Error;
76
77 if (m_hasSeenEndOfData && m_hasFinishedLoading) {
78 // We need to check this condition again because the loader can
79 // call a callback synchronously.
80 return Result::Done;
81 }
82
83 if (!m_hasReceivedResponse)
84 return Result::ShouldWait;
85
86 auto result = m_body->beginRead(buffer, available);
87 switch (result) {
88 case Result::Ok:
89 case Result::ShouldWait:
90 break;
91 case Result::Done:
92 m_hasSeenEndOfData = true;
93 clearIfNecessary();
94 return m_hasFinishedLoading ? Result::Done : Result::ShouldWait;
95 case Result::Error:
96 m_hasFinishedLoading = true;
97 clearIfNecessary();
98 break;
99 }
100 return result;
101 }
102
103 BytesConsumer::Result BlobBytesConsumer::endRead(size_t read)
104 {
105 DCHECK(m_body);
106 m_body->endRead(read);
107 if (m_hasFailedToLoad || (m_hasSeenEndOfData && m_hasFinishedLoading))
108 m_body = nullptr;
109 return Result::Ok;
110 }
111
112 PassRefPtr<BlobDataHandle> BlobBytesConsumer::drainAsBlobDataHandle(BlobSizePoli cy policy)
113 {
114 if (m_hasStarted || m_hasFinishedLoading)
115 return nullptr;
116 DCHECK(m_blobDataHandle);
117 if (policy == BlobSizePolicy::DisallowBlobWithInvalidSize && m_blobDataHandl e->size() == UINT64_MAX)
118 return nullptr;
119 m_hasFinishedLoading = true;
120 m_hasSeenEndOfData = true;
121 return m_blobDataHandle.release();
122 }
123
124 PassRefPtr<EncodedFormData> BlobBytesConsumer::drainAsFormData()
125 {
126 RefPtr<BlobDataHandle> handle = drainAsBlobDataHandle(BlobSizePolicy::AllowB lobWithInvalidSize);
127 if (!handle)
128 return nullptr;
129 RefPtr<EncodedFormData> formData = EncodedFormData::create();
130 formData->appendBlob(handle->uuid(), handle);
131 return formData.release();
132 }
133
134 void BlobBytesConsumer::setClient(BytesConsumer::Client* client)
135 {
136 DCHECK(!m_client);
137 DCHECK(client);
138 m_client = client;
139 }
140
141 void BlobBytesConsumer::clearClient()
142 {
143 m_client = nullptr;
144 }
145
146 void BlobBytesConsumer::cancel()
hiroshige 2016/09/13 03:57:23 Is it safe to cancel ThreadableLoader in a prefina
yhirano 2016/09/13 05:13:51 I think so.
147 {
148 m_hasSeenEndOfData = true;
149 m_hasFinishedLoading = true;
150 clearIfNecessary();
151 if (!m_blobURL.isEmpty()) {
152 BlobRegistry::revokePublicBlobURL(m_blobURL);
153 m_blobURL = KURL();
154 }
155 }
156
157 BytesConsumer::Error BlobBytesConsumer::getError() const
158 {
159 DCHECK_EQ(PublicState::Errored, getPublicState());
160 return Error("Failed to load a blob.");
161 }
162
163 BytesConsumer::PublicState BlobBytesConsumer::getPublicState() const
164 {
165 if (m_hasSeenEndOfData)
166 return m_hasFinishedLoading ? PublicState::Closed : PublicState::Readabl eOrWaiting;
167 if (m_hasFailedToLoad)
168 return PublicState::Errored;
169 if (!m_hasReceivedResponse)
170 return PublicState::ReadableOrWaiting;
171 // As we monitor the state change at onStateChange, |m_body|'s state
172 // must be ReadableOrWaiting.
173 DCHECK_EQ(PublicState::ReadableOrWaiting, m_body->getPublicState());
174 return PublicState::ReadableOrWaiting;
175 }
176
177 void BlobBytesConsumer::contextDestroyed()
178 {
179 if (m_loader) {
180 m_loader->cancel();
181 m_loader = nullptr;
182 }
183
184 if (getPublicState() != PublicState::ReadableOrWaiting)
185 return;
186
187 m_hasFailedToLoad = true;
188 if (m_client)
189 m_client->onStateChange();
190 clearIfNecessary();
191 }
192
193 void BlobBytesConsumer::onStateChange()
194 {
195 DCHECK(!m_hasFailedToLoad);
196 DCHECK(!m_hasSeenEndOfData);
197 DCHECK(m_body);
198
199 switch (m_body->getPublicState()) {
200 case PublicState::ReadableOrWaiting:
201 break;
202 case PublicState::Closed:
203 m_hasSeenEndOfData = true;
204 break;
205 case PublicState::Errored:
206 m_hasFailedToLoad = true;
207 break;
208 }
209
210 if (m_client)
211 m_client->onStateChange();
212 clearIfNecessary();
213 }
214
215 void BlobBytesConsumer::didReceiveResponse(unsigned long identifier, const Resou rceResponse&, std::unique_ptr<WebDataConsumerHandle> handle)
216 {
217 DCHECK(handle);
218 DCHECK(!m_hasReceivedResponse);
219
220 m_hasReceivedResponse = true;
221 m_body = new BytesConsumerForDataConsumerHandle(getExecutionContext(), creat eFetchDataConsumerHandleFromWebHandle(std::move(handle)));
222 m_body->setClient(this);
223
224 if (!m_hasStarted) {
225 // This function is called synchronously in ThreadableLoader::start.
hiroshige 2016/09/13 03:57:23 According to beginRead(), ThreadableLoader::start(
yhirano 2016/09/13 05:13:51 Done.
226 return;
227 }
228 onStateChange();
229 }
230
231 void BlobBytesConsumer::didFinishLoading(unsigned long identifier, double finish Time)
232 {
233 DCHECK(!m_hasFailedToLoad);
234 DCHECK(!m_hasFinishedLoading);
235 m_hasFinishedLoading = true;
236 m_loader = nullptr;
237 if (!m_hasStarted) {
hiroshige 2016/09/13 03:57:23 ditto.
yhirano 2016/09/13 05:13:51 Done.
238 // This function is called synchronously in ThreadableLoader::start.
239 return;
240 }
241 if (!m_hasSeenEndOfData)
242 return;
243 m_body = nullptr;
244 if (m_client) {
245 m_client->onStateChange();
246 m_client = nullptr;
247 }
248 }
249
250 void BlobBytesConsumer::didFail(const ResourceError& error)
251 {
252 if (error.isCancellation()) {
253 DCHECK(m_hasSeenEndOfData);
254 DCHECK(m_hasFinishedLoading);
255 return;
256 }
257 didFailInternal();
258 }
259
260 void BlobBytesConsumer::didFailAccessControlCheck(const ResourceError&)
261 {
262 didFailInternal();
263 }
264
265 void BlobBytesConsumer::didFailRedirectCheck()
266 {
267 didFailInternal();
268 }
269
270 DEFINE_TRACE(BlobBytesConsumer)
271 {
272 visitor->trace(m_body);
273 visitor->trace(m_client);
274 visitor->trace(m_loader);
275 BytesConsumer::trace(visitor);
276 BytesConsumer::Client::trace(visitor);
277 ContextLifecycleObserver::trace(visitor);
278 }
279
280 BlobBytesConsumer* BlobBytesConsumer::createForTesting(ExecutionContext* executi onContext, PassRefPtr<BlobDataHandle> blobDataHandle, ThreadableLoader* loader)
281 {
282 return new BlobBytesConsumer(executionContext, blobDataHandle, loader);
283 }
284
285 ThreadableLoader* BlobBytesConsumer::createLoader()
286 {
287 ThreadableLoaderOptions options;
288 options.preflightPolicy = ConsiderPreflight;
289 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
290 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy ;
291 options.initiator = FetchInitiatorTypeNames::internal;
292
293 ResourceLoaderOptions resourceLoaderOptions;
294 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
295
296 return ThreadableLoader::create(*getExecutionContext(), this, options, resou rceLoaderOptions);
297 }
298
299 void BlobBytesConsumer::didFailInternal()
300 {
301 DCHECK(!m_hasFailedToLoad);
302 DCHECK(!m_hasFinishedLoading);
303 m_hasFailedToLoad = true;
304 m_loader = nullptr;
305 m_body = nullptr;
306 if (!m_hasStarted) {
hiroshige 2016/09/13 03:57:23 ditto.
yhirano 2016/09/13 05:13:51 Done.
307 // This function is called synchronously in ThreadableLoader::start.
308 return;
309 }
310 if (m_client) {
311 m_client->onStateChange();
312 m_client = nullptr;
313 }
314 }
315
316 void BlobBytesConsumer::clearIfNecessary()
317 {
318 if (m_hasFailedToLoad || (m_hasFinishedLoading && m_hasSeenEndOfData)) {
319 if (m_loader) {
320 m_loader->cancel();
321 m_loader = nullptr;
322 }
323 m_body = nullptr;
324 m_client = nullptr;
325 }
326 }
327
328 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698