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

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

Issue 2287323002: Implement BlobBytesConsumer (Closed)
Patch Set: fix Created 4 years, 2 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 if (!m_blobDataHandle) {
28 if (m_loader) {
hiroshige 2016/09/27 07:26:23 nit: Could you add a comment that says this if blo
yhirano 2016/09/27 07:30:06 Done.
29 m_loader->cancel();
30 m_loader = nullptr;
31 }
32 m_state = PublicState::Closed;
33 }
34 }
35
36 BlobBytesConsumer::BlobBytesConsumer(ExecutionContext* executionContext, PassRef Ptr<BlobDataHandle> blobDataHandle)
37 : BlobBytesConsumer(executionContext, blobDataHandle, nullptr)
38 {
39 }
40
41 BlobBytesConsumer::~BlobBytesConsumer()
42 {
43 }
44
45 BytesConsumer::Result BlobBytesConsumer::beginRead(const char** buffer, size_t* available)
46 {
47 *buffer = nullptr;
48 *available = 0;
49
50 if (m_state == PublicState::Closed) {
51 // It's possible that |cancel| has been called before the first
52 // |beginRead| call. That's why we need to check this condition
53 // before checking |isClean()|.
54 return Result::Done;
55 }
56
57 if (isClean()) {
58 KURL m_blobURL = BlobURL::createPublicURL(getExecutionContext()->getSecu rityOrigin());
59 if (m_blobURL.isEmpty()) {
60 error();
61 } else {
62 BlobRegistry::registerPublicBlobURL(getExecutionContext()->getSecuri tyOrigin(), m_blobURL, m_blobDataHandle);
63
64 // m_loader is non-null only in tests.
65 if (!m_loader)
66 m_loader = createLoader();
67
68 ResourceRequest request(m_blobURL);
69 request.setRequestContext(WebURLRequest::RequestContextInternal);
70 request.setUseStreamOnResponse(true);
71 // We intentionally skip
72 // 'setExternalRequestStateFromRequestorAddressSpace', as 'blob:'
73 // can never be external.
74 m_loader->start(request);
75 }
76 m_blobDataHandle = nullptr;
77 }
78 DCHECK_NE(m_state, PublicState::Closed);
79
80 if (m_state == PublicState::Errored)
81 return Result::Error;
82
83 if (!m_body) {
84 // The response has not arrived.
85 return Result::ShouldWait;
86 }
87
88 auto result = m_body->beginRead(buffer, available);
89 switch (result) {
90 case Result::Ok:
91 case Result::ShouldWait:
92 break;
93 case Result::Done:
94 m_hasSeenEndOfData = true;
95 if (m_hasFinishedLoading)
96 close();
97 return m_state == PublicState::Closed ? Result::Done : Result::ShouldWai t;
98 case Result::Error:
99 error();
100 break;
101 }
102 return result;
103 }
104
105 BytesConsumer::Result BlobBytesConsumer::endRead(size_t read)
106 {
107 DCHECK(m_body);
108 return m_body->endRead(read);
109 }
110
111 PassRefPtr<BlobDataHandle> BlobBytesConsumer::drainAsBlobDataHandle(BlobSizePoli cy policy)
112 {
113 if (!isClean())
114 return nullptr;
115 DCHECK(m_blobDataHandle);
116 if (policy == BlobSizePolicy::DisallowBlobWithInvalidSize && m_blobDataHandl e->size() == UINT64_MAX)
117 return nullptr;
118 close();
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 if (m_state == PublicState::Closed || m_state == PublicState::Errored)
147 return;
148 close();
149 if (m_body) {
150 m_body->cancel();
151 m_body = nullptr;
152 }
153 if (!m_blobURL.isEmpty()) {
154 BlobRegistry::revokePublicBlobURL(m_blobURL);
155 m_blobURL = KURL();
156 }
157 m_blobDataHandle = nullptr;
158 }
159
160 BytesConsumer::Error BlobBytesConsumer::getError() const
161 {
162 DCHECK_EQ(PublicState::Errored, m_state);
163 return Error("Failed to load a blob.");
164 }
165
166 BytesConsumer::PublicState BlobBytesConsumer::getPublicState() const
167 {
168 return m_state;
169 }
170
171 void BlobBytesConsumer::contextDestroyed()
172 {
173 if (m_state != PublicState::ReadableOrWaiting)
174 return;
175
176 BytesConsumer::Client* client = m_client;
177 error();
178 if (client)
179 client->onStateChange();
180 }
181
182 void BlobBytesConsumer::onStateChange()
183 {
184 if (m_state != PublicState::ReadableOrWaiting)
185 return;
186 DCHECK(m_body);
187
188 BytesConsumer::Client* client = m_client;
189 switch (m_body->getPublicState()) {
190 case PublicState::ReadableOrWaiting:
191 break;
192 case PublicState::Closed:
193 m_hasSeenEndOfData = true;
194 if (m_hasFinishedLoading)
195 close();
196 break;
197 case PublicState::Errored:
198 error();
199 break;
200 }
201 if (client)
202 client->onStateChange();
203 }
204
205 void BlobBytesConsumer::didReceiveResponse(unsigned long identifier, const Resou rceResponse&, std::unique_ptr<WebDataConsumerHandle> handle)
206 {
207 DCHECK(handle);
208 DCHECK(!m_body);
209 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
210
211 m_body = new BytesConsumerForDataConsumerHandle(getExecutionContext(), creat eFetchDataConsumerHandleFromWebHandle(std::move(handle)));
212 m_body->setClient(this);
213
214 if (isClean()) {
215 // This function is called synchronously in ThreadableLoader::start.
216 return;
217 }
218 onStateChange();
219 }
220
221 void BlobBytesConsumer::didFinishLoading(unsigned long identifier, double finish Time)
222 {
223 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
224 m_hasFinishedLoading = true;
225 m_loader = nullptr;
226 if (!m_hasSeenEndOfData)
227 return;
228 DCHECK(!isClean());
229 BytesConsumer::Client* client = m_client;
230 close();
231 if (client)
232 client->onStateChange();
233 }
234
235 void BlobBytesConsumer::didFail(const ResourceError& e)
236 {
237 if (e.isCancellation()) {
238 DCHECK_EQ(PublicState::Closed, m_state);
239 return;
240 }
241 DCHECK_EQ(PublicState::ReadableOrWaiting, m_state);
242 m_loader = nullptr;
243 BytesConsumer::Client* client = m_client;
244 error();
245 if (isClean()) {
246 // This function is called synchronously in ThreadableLoader::start.
247 return;
248 }
249 if (client) {
250 client->onStateChange();
251 client = nullptr;
252 }
253 }
254
255 void BlobBytesConsumer::didFailRedirectCheck()
256 {
257 NOTREACHED();
258 }
259
260 DEFINE_TRACE(BlobBytesConsumer)
261 {
262 visitor->trace(m_body);
263 visitor->trace(m_client);
264 visitor->trace(m_loader);
265 BytesConsumer::trace(visitor);
266 BytesConsumer::Client::trace(visitor);
267 ContextLifecycleObserver::trace(visitor);
268 }
269
270 BlobBytesConsumer* BlobBytesConsumer::createForTesting(ExecutionContext* executi onContext, PassRefPtr<BlobDataHandle> blobDataHandle, ThreadableLoader* loader)
271 {
272 return new BlobBytesConsumer(executionContext, blobDataHandle, loader);
273 }
274
275 ThreadableLoader* BlobBytesConsumer::createLoader()
276 {
277 ThreadableLoaderOptions options;
278 options.preflightPolicy = ConsiderPreflight;
279 options.crossOriginRequestPolicy = DenyCrossOriginRequests;
280 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy ;
281 options.initiator = FetchInitiatorTypeNames::internal;
282
283 ResourceLoaderOptions resourceLoaderOptions;
284 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
285
286 return ThreadableLoader::create(*getExecutionContext(), this, options, resou rceLoaderOptions);
287 }
288
289 void BlobBytesConsumer::close()
290 {
291 DCHECK_EQ(m_state, PublicState::ReadableOrWaiting);
292 m_state = PublicState::Closed;
293 clear();
294 }
295
296 void BlobBytesConsumer::error()
297 {
298 DCHECK_EQ(m_state, PublicState::ReadableOrWaiting);
299 m_state = PublicState::Errored;
300 clear();
301 }
302
303 void BlobBytesConsumer::clear()
304 {
305 DCHECK_NE(m_state, PublicState::ReadableOrWaiting);
306 if (m_loader) {
307 m_loader->cancel();
308 m_loader = nullptr;
309 }
310 m_client = nullptr;
311 }
312
313 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698