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

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_state == PublicState::Closed) {
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 |isClean()|.
47 return Result::Done;
48 }
49
50 if (isClean()) {
51 KURL m_blobURL = BlobURL::createPublicURL(getExecutionContext()->getSecu rityOrigin());
52 if (m_blobURL.isEmpty()) {
53 m_state = PublicState::Errored;
hiroshige 2016/09/15 09:04:34 Can we call error() instead of setting |m_state|?
yhirano 2016/09/15 09:11:22 Done.
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_blobDataHandle = nullptr;
70 }
71 DCHECK_NE(m_state, PublicState::Closed);
72
73 if (m_state == PublicState::Errored)
74 return Result::Error;
75
76 if (!m_body) {
77 // The response has not arrived.
78 return Result::ShouldWait;
79 }
80
81 auto result = m_body->beginRead(buffer, available);
82 switch (result) {
83 case Result::Ok:
84 case Result::ShouldWait:
85 break;
86 case Result::Done:
87 m_hasSeenEndOfData = true;
88 if (m_hasFinishedLoading)
89 close();
90 return m_state == PublicState::Closed ? Result::Done : Result::ShouldWai t;
91 case Result::Error:
92 error();
93 break;
94 }
95 return result;
96 }
97
98 BytesConsumer::Result BlobBytesConsumer::endRead(size_t read)
99 {
100 DCHECK(m_body);
101 return m_body->endRead(read);
102 }
103
104 PassRefPtr<BlobDataHandle> BlobBytesConsumer::drainAsBlobDataHandle(BlobSizePoli cy policy)
105 {
106 if (!isClean())
107 return nullptr;
108 DCHECK(m_blobDataHandle);
109 if (policy == BlobSizePolicy::DisallowBlobWithInvalidSize && m_blobDataHandl e->size() == UINT64_MAX)
110 return nullptr;
111 m_state = PublicState::Closed;
hiroshige 2016/09/15 09:04:34 Can we call close() instead of setting |m_state|?
yhirano 2016/09/15 09:11:22 Done.
112 return m_blobDataHandle.release();
113 }
114
115 PassRefPtr<EncodedFormData> BlobBytesConsumer::drainAsFormData()
116 {
117 RefPtr<BlobDataHandle> handle = drainAsBlobDataHandle(BlobSizePolicy::AllowB lobWithInvalidSize);
118 if (!handle)
119 return nullptr;
120 RefPtr<EncodedFormData> formData = EncodedFormData::create();
121 formData->appendBlob(handle->uuid(), handle);
122 return formData.release();
123 }
124
125 void BlobBytesConsumer::setClient(BytesConsumer::Client* client)
126 {
127 DCHECK(!m_client);
128 DCHECK(client);
129 m_client = client;
130 }
131
132 void BlobBytesConsumer::clearClient()
133 {
134 m_client = nullptr;
135 }
136
137 void BlobBytesConsumer::cancel()
138 {
139 if (m_state == PublicState::Closed || m_state == PublicState::Errored)
140 return;
141 close();
142 if (m_body) {
143 m_body->cancel();
144 m_body = nullptr;
145 }
146 if (!m_blobURL.isEmpty()) {
147 BlobRegistry::revokePublicBlobURL(m_blobURL);
148 m_blobURL = KURL();
149 }
150 m_blobDataHandle = nullptr;
151 }
152
153 BytesConsumer::Error BlobBytesConsumer::getError() const
154 {
155 DCHECK_EQ(PublicState::Errored, m_state);
156 return Error("Failed to load a blob.");
157 }
158
159 BytesConsumer::PublicState BlobBytesConsumer::getPublicState() const
160 {
161 return m_state;
162 }
163
164 void BlobBytesConsumer::contextDestroyed()
165 {
166 if (m_state != PublicState::ReadableOrWaiting)
167 return;
168
169 BytesConsumer::Client* client = m_client;
170 error();
171 if (client)
172 client->onStateChange();
173 }
174
175 void BlobBytesConsumer::onStateChange()
176 {
177 if (m_state != PublicState::ReadableOrWaiting)
178 return;
179 DCHECK(m_body);
180
181 BytesConsumer::Client* client = m_client;
182 switch (m_body->getPublicState()) {
183 case PublicState::ReadableOrWaiting:
184 break;
185 case PublicState::Closed:
186 m_hasSeenEndOfData = true;
187 if (m_hasFinishedLoading)
188 close();
189 break;
190 case PublicState::Errored:
191 error();
192 break;
193 }
194 if (client)
195 client->onStateChange();
196 }
197
198 void BlobBytesConsumer::didReceiveResponse(unsigned long identifier, const Resou rceResponse&, std::unique_ptr<WebDataConsumerHandle> handle)
199 {
200 DCHECK(handle);
201 DCHECK(!m_body);
202 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
203
204 m_body = new BytesConsumerForDataConsumerHandle(getExecutionContext(), creat eFetchDataConsumerHandleFromWebHandle(std::move(handle)));
205 m_body->setClient(this);
206
207 if (isClean()) {
208 // This function is called synchronously in ThreadableLoader::start.
209 return;
210 }
211 onStateChange();
212 }
213
214 void BlobBytesConsumer::didFinishLoading(unsigned long identifier, double finish Time)
215 {
216 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
217 m_hasFinishedLoading = true;
218 m_loader = nullptr;
219 if (!m_hasSeenEndOfData)
220 return;
221 DCHECK(!isClean());
222 m_state = PublicState::Closed;
hiroshige 2016/09/15 09:04:34 Can we call close() instead of setting |m_state|?
yhirano 2016/09/15 09:11:22 Done.
223 if (m_client) {
224 m_client->onStateChange();
225 m_client = nullptr;
226 }
227 }
228
229 void BlobBytesConsumer::didFail(const ResourceError& error)
230 {
231 if (error.isCancellation()) {
232 DCHECK_EQ(PublicState::Closed, m_state);
233 return;
234 }
235 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
236 m_state = PublicState::Errored;
hiroshige 2016/09/15 09:04:34 Can we call error() instead of setting |m_state|?
yhirano 2016/09/15 09:11:22 Done.
237 m_loader = nullptr;
238 if (isClean()) {
239 // This function is called synchronously in ThreadableLoader::start.
240 return;
241 }
242 if (m_client) {
243 m_client->onStateChange();
244 m_client = nullptr;
245 }
246 }
247
248 void BlobBytesConsumer::didFailRedirectCheck()
249 {
250 NOTREACHED();
251 }
252
253 DEFINE_TRACE(BlobBytesConsumer)
254 {
255 visitor->trace(m_body);
256 visitor->trace(m_client);
257 visitor->trace(m_loader);
258 BytesConsumer::trace(visitor);
259 BytesConsumer::Client::trace(visitor);
260 ContextLifecycleObserver::trace(visitor);
261 }
262
263 BlobBytesConsumer* BlobBytesConsumer::createForTesting(ExecutionContext* executi onContext, PassRefPtr<BlobDataHandle> blobDataHandle, ThreadableLoader* loader)
264 {
265 return new BlobBytesConsumer(executionContext, blobDataHandle, loader);
266 }
267
268 ThreadableLoader* BlobBytesConsumer::createLoader()
269 {
270 ThreadableLoaderOptions options;
271 options.preflightPolicy = ConsiderPreflight;
272 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
273 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy ;
274 options.initiator = FetchInitiatorTypeNames::internal;
275
276 ResourceLoaderOptions resourceLoaderOptions;
277 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
278
279 return ThreadableLoader::create(*getExecutionContext(), this, options, resou rceLoaderOptions);
280 }
281
282 void BlobBytesConsumer::close()
283 {
284 DCHECK_EQ(m_state, PublicState::ReadableOrWaiting);
285 m_state = PublicState::Closed;
286 clear();
287 }
288
289 void BlobBytesConsumer::error()
290 {
291 DCHECK_EQ(m_state, PublicState::ReadableOrWaiting);
292 m_state = PublicState::Errored;
293 clear();
294 }
295
296 void BlobBytesConsumer::clear()
297 {
298 DCHECK_NE(m_state, PublicState::ReadableOrWaiting);
299 if (m_loader) {
300 m_loader->cancel();
301 m_loader = nullptr;
302 }
303 m_client = nullptr;
304 }
305
306 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698