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

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

Powered by Google App Engine
This is Rietveld 408576698