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