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

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

Powered by Google App Engine
This is Rietveld 408576698