OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/fetch/FetchDataLoader.h" | 5 #include "modules/fetch/FetchDataLoader.h" |
6 | 6 |
7 #include "core/html/parser/TextResourceDecoder.h" | 7 #include "core/html/parser/TextResourceDecoder.h" |
| 8 #include "modules/fetch/BytesConsumer.h" |
8 #include "wtf/PtrUtil.h" | 9 #include "wtf/PtrUtil.h" |
9 #include "wtf/text/StringBuilder.h" | 10 #include "wtf/text/StringBuilder.h" |
10 #include "wtf/text/WTFString.h" | 11 #include "wtf/text/WTFString.h" |
11 #include "wtf/typed_arrays/ArrayBufferBuilder.h" | 12 #include "wtf/typed_arrays/ArrayBufferBuilder.h" |
12 #include <memory> | 13 #include <memory> |
13 | 14 |
14 namespace blink { | 15 namespace blink { |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
18 class FetchDataLoaderAsBlobHandle | 19 class FetchDataLoaderAsBlobHandle final : public FetchDataLoader, public BytesCo
nsumer::Client { |
19 : public FetchDataLoader | 20 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsBlobHandle); |
20 , public WebDataConsumerHandle::Client { | |
21 public: | 21 public: |
22 explicit FetchDataLoaderAsBlobHandle(const String& mimeType) | 22 explicit FetchDataLoaderAsBlobHandle(const String& mimeType) |
23 : m_client(nullptr) | 23 : m_mimeType(mimeType) |
24 , m_mimeType(mimeType) { } | 24 { |
25 | 25 } |
26 DEFINE_INLINE_VIRTUAL_TRACE() | 26 |
27 { | 27 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
28 FetchDataLoader::trace(visitor); | 28 { |
29 visitor->trace(m_client); | 29 DCHECK(!m_client); |
30 } | 30 DCHECK(!m_consumer); |
31 | 31 |
32 private: | 32 m_client = client; |
33 void start(FetchDataConsumerHandle* handle, FetchDataLoader::Client* client)
override | 33 m_consumer = consumer; |
34 { | 34 |
35 ASSERT(!m_client); | 35 RefPtr<BlobDataHandle> blobHandle = m_consumer->drainAsBlobDataHandle(); |
36 ASSERT(!m_reader); | |
37 | |
38 m_client = client; | |
39 // Passing |this| here is safe because |this| owns |m_reader|. | |
40 m_reader = handle->obtainFetchDataReader(this); | |
41 RefPtr<BlobDataHandle> blobHandle = m_reader->drainAsBlobDataHandle(); | |
42 if (blobHandle) { | 36 if (blobHandle) { |
43 ASSERT(blobHandle->size() != UINT64_MAX); | 37 DCHECK_NE(UINT64_MAX, blobHandle->size()); |
44 m_reader.reset(); | |
45 if (blobHandle->type() != m_mimeType) { | 38 if (blobHandle->type() != m_mimeType) { |
46 // A new BlobDataHandle is created to override the Blob's type. | 39 // A new BlobDataHandle is created to override the Blob's type. |
47 m_client->didFetchDataLoadedBlobHandle(BlobDataHandle::create(bl
obHandle->uuid(), m_mimeType, blobHandle->size())); | 40 m_client->didFetchDataLoadedBlobHandle(BlobDataHandle::create(bl
obHandle->uuid(), m_mimeType, blobHandle->size())); |
48 } else { | 41 } else { |
49 m_client->didFetchDataLoadedBlobHandle(blobHandle); | 42 m_client->didFetchDataLoadedBlobHandle(std::move(blobHandle)); |
50 } | 43 } |
51 m_client.clear(); | |
52 return; | 44 return; |
53 } | 45 } |
54 | 46 |
55 // We read data from |m_reader| and create a new blob. | |
56 m_blobData = BlobData::create(); | 47 m_blobData = BlobData::create(); |
57 m_blobData->setContentType(m_mimeType); | 48 m_blobData->setContentType(m_mimeType); |
58 } | 49 m_consumer->setClient(this); |
59 | 50 onStateChange(); |
60 void didGetReadable() override | 51 } |
61 { | 52 |
62 ASSERT(m_client); | 53 void cancel() override |
63 ASSERT(m_reader); | 54 { |
64 | 55 m_consumer->cancel(); |
65 while (true) { | 56 } |
66 const void* buffer; | 57 |
67 size_t available; | 58 void onStateChange() override |
68 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer,
WebDataConsumerHandle::FlagNone, &available); | 59 { |
69 | 60 while (true) { |
70 switch (result) { | 61 const char* buffer; |
71 case WebDataConsumerHandle::Ok: | 62 size_t available; |
| 63 switch (m_consumer->beginRead(&buffer, &available)) { |
| 64 case BytesConsumer::Result::Ok: |
72 m_blobData->appendBytes(buffer, available); | 65 m_blobData->appendBytes(buffer, available); |
73 m_reader->endRead(available); | 66 m_consumer->endRead(available); |
74 break; | 67 break; |
75 | 68 case BytesConsumer::Result::ShouldWait: |
76 case WebDataConsumerHandle::Done: { | 69 return; |
77 m_reader.reset(); | 70 case BytesConsumer::Result::Done: { |
78 long long size = m_blobData->length(); | 71 auto size = m_blobData->length(); |
79 m_client->didFetchDataLoadedBlobHandle(BlobDataHandle::create(st
d::move(m_blobData), size)); | 72 m_client->didFetchDataLoadedBlobHandle(BlobDataHandle::create(st
d::move(m_blobData), size)); |
80 m_client.clear(); | 73 return; |
81 return; | 74 } |
82 } | 75 case BytesConsumer::Result::Error: |
83 | 76 m_client->didFetchDataLoadFailed(); |
84 case WebDataConsumerHandle::ShouldWait: | 77 return; |
85 return; | 78 } |
86 | 79 } |
87 case WebDataConsumerHandle::Busy: | 80 } |
88 case WebDataConsumerHandle::ResourceExhausted: | 81 |
89 case WebDataConsumerHandle::UnexpectedError: | 82 DEFINE_INLINE_TRACE() |
90 m_reader.reset(); | 83 { |
91 m_blobData.reset(); | 84 visitor->trace(m_consumer); |
92 m_client->didFetchDataLoadFailed(); | 85 visitor->trace(m_client); |
93 m_client.clear(); | 86 FetchDataLoader::trace(visitor); |
94 return; | 87 BytesConsumer::Client::trace(visitor); |
95 } | 88 } |
96 } | 89 |
97 } | 90 private: |
98 | 91 Member<BytesConsumer> m_consumer; |
99 void cancel() override | |
100 { | |
101 m_reader.reset(); | |
102 m_blobData.reset(); | |
103 m_client.clear(); | |
104 } | |
105 | |
106 std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; | |
107 Member<FetchDataLoader::Client> m_client; | 92 Member<FetchDataLoader::Client> m_client; |
108 | 93 |
109 String m_mimeType; | 94 String m_mimeType; |
110 std::unique_ptr<BlobData> m_blobData; | 95 std::unique_ptr<BlobData> m_blobData; |
111 }; | 96 }; |
112 | 97 |
113 class FetchDataLoaderAsArrayBuffer | 98 class FetchDataLoaderAsArrayBuffer final : public FetchDataLoader, public BytesC
onsumer::Client { |
114 : public FetchDataLoader | 99 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsArrayBuffer) |
115 , public WebDataConsumerHandle::Client { | 100 public: |
116 public: | 101 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
117 FetchDataLoaderAsArrayBuffer() | 102 { |
118 : m_client(nullptr) { } | 103 DCHECK(!m_client); |
119 | 104 DCHECK(!m_rawData); |
120 DEFINE_INLINE_VIRTUAL_TRACE() | 105 DCHECK(!m_consumer); |
121 { | |
122 FetchDataLoader::trace(visitor); | |
123 visitor->trace(m_client); | |
124 } | |
125 | |
126 protected: | |
127 void start(FetchDataConsumerHandle* handle, FetchDataLoader::Client* client)
override | |
128 { | |
129 ASSERT(!m_client); | |
130 ASSERT(!m_rawData); | |
131 ASSERT(!m_reader); | |
132 m_client = client; | 106 m_client = client; |
133 m_rawData = wrapUnique(new ArrayBufferBuilder()); | 107 m_rawData = wrapUnique(new ArrayBufferBuilder()); |
134 m_reader = handle->obtainFetchDataReader(this); | 108 m_consumer = consumer; |
135 } | 109 m_consumer->setClient(this); |
136 | 110 onStateChange(); |
137 void didGetReadable() override | 111 } |
138 { | 112 |
139 ASSERT(m_client); | 113 void cancel() override |
140 ASSERT(m_rawData); | 114 { |
141 ASSERT(m_reader); | 115 m_consumer->cancel(); |
142 | 116 } |
143 while (true) { | 117 |
144 const void* buffer; | 118 void onStateChange() override |
145 size_t available; | 119 { |
146 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer,
WebDataConsumerHandle::FlagNone, &available); | 120 while (true) { |
147 | 121 const char* buffer; |
148 switch (result) { | 122 size_t available; |
149 case WebDataConsumerHandle::Ok: | 123 switch (m_consumer->beginRead(&buffer, &available)) { |
| 124 case BytesConsumer::Result::Ok: |
150 if (available > 0) { | 125 if (available > 0) { |
151 unsigned bytesAppended = m_rawData->append(static_cast<const
char*>(buffer), available); | 126 unsigned bytesAppended = m_rawData->append(buffer, available
); |
152 if (!bytesAppended) { | 127 if (!bytesAppended) { |
153 m_reader->endRead(0); | 128 m_consumer->endRead(0); |
154 error(); | 129 m_consumer->cancel(); |
| 130 m_client->didFetchDataLoadFailed(); |
155 return; | 131 return; |
156 } | 132 } |
157 ASSERT(bytesAppended == available); | 133 DCHECK_EQ(bytesAppended, available); |
158 } | 134 } |
159 m_reader->endRead(available); | 135 m_consumer->endRead(available); |
160 break; | 136 break; |
161 | 137 case BytesConsumer::Result::ShouldWait: |
162 case WebDataConsumerHandle::Done: | 138 return; |
163 m_reader.reset(); | 139 case BytesConsumer::Result::Done: |
164 m_client->didFetchDataLoadedArrayBuffer(DOMArrayBuffer::create(m
_rawData->toArrayBuffer())); | 140 m_client->didFetchDataLoadedArrayBuffer(DOMArrayBuffer::create(m
_rawData->toArrayBuffer())); |
165 m_rawData.reset(); | 141 return; |
166 m_client.clear(); | 142 case BytesConsumer::Result::Error: |
167 return; | 143 m_client->didFetchDataLoadFailed(); |
168 | 144 return; |
169 case WebDataConsumerHandle::ShouldWait: | 145 } |
170 return; | 146 } |
171 | 147 } |
172 case WebDataConsumerHandle::Busy: | 148 |
173 case WebDataConsumerHandle::ResourceExhausted: | 149 DEFINE_INLINE_TRACE() |
174 case WebDataConsumerHandle::UnexpectedError: | 150 { |
175 error(); | 151 visitor->trace(m_consumer); |
176 return; | 152 visitor->trace(m_client); |
177 } | 153 FetchDataLoader::trace(visitor); |
178 } | 154 BytesConsumer::Client::trace(visitor); |
179 } | 155 } |
180 | 156 |
181 void error() | 157 private: |
182 { | 158 Member<BytesConsumer> m_consumer; |
183 m_reader.reset(); | |
184 m_rawData.reset(); | |
185 m_client->didFetchDataLoadFailed(); | |
186 m_client.clear(); | |
187 } | |
188 | |
189 void cancel() override | |
190 { | |
191 m_reader.reset(); | |
192 m_rawData.reset(); | |
193 m_client.clear(); | |
194 } | |
195 | |
196 std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; | |
197 Member<FetchDataLoader::Client> m_client; | 159 Member<FetchDataLoader::Client> m_client; |
198 | 160 |
199 std::unique_ptr<ArrayBufferBuilder> m_rawData; | 161 std::unique_ptr<ArrayBufferBuilder> m_rawData; |
200 }; | 162 }; |
201 | 163 |
202 class FetchDataLoaderAsString | 164 class FetchDataLoaderAsString final : public FetchDataLoader, public BytesConsum
er::Client { |
203 : public FetchDataLoader | 165 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsString); |
204 , public WebDataConsumerHandle::Client { | 166 public: |
205 public: | 167 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
206 FetchDataLoaderAsString() | 168 { |
207 : m_client(nullptr) { } | 169 DCHECK(!m_client); |
208 | 170 DCHECK(!m_decoder); |
209 DEFINE_INLINE_VIRTUAL_TRACE() | 171 DCHECK(!m_consumer); |
210 { | |
211 FetchDataLoader::trace(visitor); | |
212 visitor->trace(m_client); | |
213 } | |
214 | |
215 protected: | |
216 void start(FetchDataConsumerHandle* handle, FetchDataLoader::Client* client)
override | |
217 { | |
218 ASSERT(!m_client); | |
219 ASSERT(!m_decoder); | |
220 ASSERT(!m_reader); | |
221 m_client = client; | 172 m_client = client; |
222 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText(); | 173 m_decoder = TextResourceDecoder::createAlwaysUseUTF8ForText(); |
223 m_reader = handle->obtainFetchDataReader(this); | 174 m_consumer = consumer; |
224 } | 175 m_consumer->setClient(this); |
225 | 176 onStateChange(); |
226 void didGetReadable() override | 177 } |
227 { | 178 |
228 ASSERT(m_client); | 179 void onStateChange() override |
229 ASSERT(m_decoder); | 180 { |
230 ASSERT(m_reader); | 181 while (true) { |
231 | 182 const char* buffer; |
232 while (true) { | 183 size_t available; |
233 const void* buffer; | 184 switch (m_consumer->beginRead(&buffer, &available)) { |
234 size_t available; | 185 case BytesConsumer::Result::Ok: |
235 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer,
WebDataConsumerHandle::FlagNone, &available); | |
236 | |
237 switch (result) { | |
238 case WebDataConsumerHandle::Ok: | |
239 if (available > 0) | 186 if (available > 0) |
240 m_builder.append(m_decoder->decode(static_cast<const char*>(
buffer), available)); | 187 m_builder.append(m_decoder->decode(buffer, available)); |
241 m_reader->endRead(available); | 188 m_consumer->endRead(available); |
242 break; | 189 break; |
243 | 190 case BytesConsumer::Result::ShouldWait: |
244 case WebDataConsumerHandle::Done: | 191 return; |
245 m_reader.reset(); | 192 case BytesConsumer::Result::Done: |
246 m_builder.append(m_decoder->flush()); | 193 m_builder.append(m_decoder->flush()); |
247 m_client->didFetchDataLoadedString(m_builder.toString()); | 194 m_client->didFetchDataLoadedString(m_builder.toString()); |
248 m_builder.clear(); | 195 return; |
249 m_decoder.reset(); | 196 case BytesConsumer::Result::Error: |
250 m_client.clear(); | 197 m_client->didFetchDataLoadFailed(); |
251 return; | 198 return; |
252 | 199 } |
253 case WebDataConsumerHandle::ShouldWait: | 200 } |
254 return; | |
255 | |
256 case WebDataConsumerHandle::Busy: | |
257 case WebDataConsumerHandle::ResourceExhausted: | |
258 case WebDataConsumerHandle::UnexpectedError: | |
259 error(); | |
260 return; | |
261 } | |
262 } | |
263 } | |
264 | |
265 void error() | |
266 { | |
267 m_reader.reset(); | |
268 m_builder.clear(); | |
269 m_decoder.reset(); | |
270 m_client->didFetchDataLoadFailed(); | |
271 m_client.clear(); | |
272 } | 201 } |
273 | 202 |
274 void cancel() override | 203 void cancel() override |
275 { | 204 { |
276 m_reader.reset(); | 205 m_consumer->cancel(); |
277 m_builder.clear(); | 206 } |
278 m_decoder.reset(); | 207 |
279 m_client.clear(); | 208 DEFINE_INLINE_TRACE() |
280 } | 209 { |
281 | 210 visitor->trace(m_consumer); |
282 std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; | 211 visitor->trace(m_client); |
| 212 FetchDataLoader::trace(visitor); |
| 213 BytesConsumer::Client::trace(visitor); |
| 214 } |
| 215 |
| 216 private: |
| 217 Member<BytesConsumer> m_consumer; |
283 Member<FetchDataLoader::Client> m_client; | 218 Member<FetchDataLoader::Client> m_client; |
284 | 219 |
285 std::unique_ptr<TextResourceDecoder> m_decoder; | 220 std::unique_ptr<TextResourceDecoder> m_decoder; |
286 StringBuilder m_builder; | 221 StringBuilder m_builder; |
287 }; | 222 }; |
288 | 223 |
289 class FetchDataLoaderAsStream | 224 class FetchDataLoaderAsStream final : public FetchDataLoader, public BytesConsum
er::Client { |
290 : public FetchDataLoader | 225 USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsStream); |
291 , public WebDataConsumerHandle::Client { | |
292 public: | 226 public: |
293 explicit FetchDataLoaderAsStream(Stream* outStream) | 227 explicit FetchDataLoaderAsStream(Stream* outStream) |
294 : m_client(nullptr) | 228 : m_outStream(outStream) |
295 , m_outStream(outStream) { } | 229 { |
296 | 230 } |
297 DEFINE_INLINE_VIRTUAL_TRACE() | 231 |
298 { | 232 void start(BytesConsumer* consumer, FetchDataLoader::Client* client) overrid
e |
299 FetchDataLoader::trace(visitor); | 233 { |
300 visitor->trace(m_client); | 234 DCHECK(!m_client); |
301 visitor->trace(m_outStream); | 235 DCHECK(!m_consumer); |
302 } | 236 m_client = client; |
303 | 237 m_consumer = consumer; |
304 protected: | 238 m_consumer->setClient(this); |
305 void start(FetchDataConsumerHandle* handle, FetchDataLoader::Client* client)
override | 239 onStateChange(); |
306 { | 240 } |
307 ASSERT(!m_client); | 241 |
308 ASSERT(!m_reader); | 242 void onStateChange() override |
309 m_client = client; | 243 { |
310 m_reader = handle->obtainFetchDataReader(this); | |
311 } | |
312 | |
313 void didGetReadable() override | |
314 { | |
315 ASSERT(m_client); | |
316 ASSERT(m_reader); | |
317 | |
318 bool needToFlush = false; | 244 bool needToFlush = false; |
319 while (true) { | 245 while (true) { |
320 const void* buffer; | 246 const char* buffer; |
321 size_t available; | 247 size_t available; |
322 WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer,
WebDataConsumerHandle::FlagNone, &available); | 248 switch (m_consumer->beginRead(&buffer, &available)) { |
323 | 249 case BytesConsumer::Result::Ok: |
324 switch (result) { | 250 m_outStream->addData(buffer, available); |
325 case WebDataConsumerHandle::Ok: | 251 m_consumer->endRead(available); |
326 m_outStream->addData(static_cast<const char*>(buffer), available
); | |
327 m_reader->endRead(available); | |
328 needToFlush = true; | 252 needToFlush = true; |
329 break; | 253 break; |
330 | 254 case BytesConsumer::Result::ShouldWait: |
331 case WebDataConsumerHandle::Done: | 255 if (needToFlush) |
332 m_reader.reset(); | 256 m_outStream->flush(); |
| 257 return; |
| 258 case BytesConsumer::Result::Done: |
333 if (needToFlush) | 259 if (needToFlush) |
334 m_outStream->flush(); | 260 m_outStream->flush(); |
335 m_outStream->finalize(); | 261 m_outStream->finalize(); |
336 m_client->didFetchDataLoadedStream(); | 262 m_client->didFetchDataLoadedStream(); |
337 cleanup(); | 263 return; |
338 return; | 264 case BytesConsumer::Result::Error: |
339 | |
340 case WebDataConsumerHandle::ShouldWait: | |
341 if (needToFlush) | |
342 m_outStream->flush(); | |
343 return; | |
344 | |
345 case WebDataConsumerHandle::Busy: | |
346 case WebDataConsumerHandle::ResourceExhausted: | |
347 case WebDataConsumerHandle::UnexpectedError: | |
348 // If the stream is aborted soon after the stream is registered | 265 // If the stream is aborted soon after the stream is registered |
349 // to the StreamRegistry, ServiceWorkerURLRequestJob may not | 266 // to the StreamRegistry, ServiceWorkerURLRequestJob may not |
350 // notice the error and continue waiting forever. | 267 // notice the error and continue waiting forever. |
351 // FIXME: Add new message to report the error to the browser | 268 // TODO(yhirano): Add new message to report the error to the |
352 // process. | 269 // browser process. |
353 m_reader.reset(); | |
354 m_outStream->abort(); | 270 m_outStream->abort(); |
355 m_client->didFetchDataLoadFailed(); | 271 m_client->didFetchDataLoadFailed(); |
356 cleanup(); | 272 return; |
357 return; | 273 } |
358 } | 274 } |
359 } | |
360 } | 275 } |
361 | 276 |
362 void cancel() override | 277 void cancel() override |
363 { | 278 { |
364 cleanup(); | 279 m_consumer->cancel(); |
365 } | 280 } |
366 | 281 |
367 void cleanup() | 282 DEFINE_INLINE_TRACE() |
368 { | 283 { |
369 m_reader.reset(); | 284 visitor->trace(m_consumer); |
370 m_client.clear(); | 285 visitor->trace(m_client); |
371 m_outStream.clear(); | 286 visitor->trace(m_outStream); |
| 287 FetchDataLoader::trace(visitor); |
| 288 BytesConsumer::Client::trace(visitor); |
372 } | 289 } |
373 | 290 |
374 std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; | 291 Member<BytesConsumer> m_consumer; |
375 Member<FetchDataLoader::Client> m_client; | 292 Member<FetchDataLoader::Client> m_client; |
376 | |
377 Member<Stream> m_outStream; | 293 Member<Stream> m_outStream; |
378 }; | 294 }; |
379 | 295 |
380 | |
381 } // namespace | 296 } // namespace |
382 | 297 |
383 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp
e) | 298 FetchDataLoader* FetchDataLoader::createLoaderAsBlobHandle(const String& mimeTyp
e) |
384 { | 299 { |
385 return new FetchDataLoaderAsBlobHandle(mimeType); | 300 return new FetchDataLoaderAsBlobHandle(mimeType); |
386 } | 301 } |
387 | 302 |
388 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() | 303 FetchDataLoader* FetchDataLoader::createLoaderAsArrayBuffer() |
389 { | 304 { |
390 return new FetchDataLoaderAsArrayBuffer(); | 305 return new FetchDataLoaderAsArrayBuffer(); |
391 } | 306 } |
392 | 307 |
393 FetchDataLoader* FetchDataLoader::createLoaderAsString() | 308 FetchDataLoader* FetchDataLoader::createLoaderAsString() |
394 { | 309 { |
395 return new FetchDataLoaderAsString(); | 310 return new FetchDataLoaderAsString(); |
396 } | 311 } |
397 | 312 |
398 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) | 313 FetchDataLoader* FetchDataLoader::createLoaderAsStream(Stream* outStream) |
399 { | 314 { |
400 return new FetchDataLoaderAsStream(outStream); | 315 return new FetchDataLoaderAsStream(outStream); |
401 } | 316 } |
402 | 317 |
403 } // namespace blink | 318 } // namespace blink |
OLD | NEW |