OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "modules/fetch/FetchBlobDataConsumerHandle.h" | |
6 | |
7 #include "core/dom/ExecutionContext.h" | |
8 #include "core/fetch/ResourceLoaderOptions.h" | |
9 #include "core/loader/MockThreadableLoader.h" | |
10 #include "core/loader/ThreadableLoaderClient.h" | |
11 #include "core/testing/DummyPageHolder.h" | |
12 #include "modules/fetch/DataConsumerHandleTestUtil.h" | |
13 #include "platform/blob/BlobData.h" | |
14 #include "platform/blob/BlobURL.h" | |
15 #include "platform/network/ResourceError.h" | |
16 #include "platform/network/ResourceRequest.h" | |
17 #include "platform/network/ResourceResponse.h" | |
18 #include "platform/testing/UnitTestHelpers.h" | |
19 #include "testing/gmock/include/gmock/gmock.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 #include "wtf/PassRefPtr.h" | |
22 #include "wtf/PtrUtil.h" | |
23 #include "wtf/RefPtr.h" | |
24 #include <memory> | |
25 #include <string.h> | |
26 | |
27 namespace blink { | |
28 namespace { | |
29 | |
30 using Result = WebDataConsumerHandle::Result; | |
31 const Result kShouldWait = WebDataConsumerHandle::ShouldWait; | |
32 const Result kUnexpectedError = WebDataConsumerHandle::UnexpectedError; | |
33 const Result kDone = WebDataConsumerHandle::Done; | |
34 using Flags = WebDataConsumerHandle::Flags; | |
35 const Flags kNone = WebDataConsumerHandle::FlagNone; | |
36 using Thread = DataConsumerHandleTestUtil::Thread; | |
37 using HandleReader = DataConsumerHandleTestUtil::HandleReader; | |
38 using HandleTwoPhaseReader = DataConsumerHandleTestUtil::HandleTwoPhaseReader; | |
39 using HandleReadResult = DataConsumerHandleTestUtil::HandleReadResult; | |
40 using ReplayingHandle = DataConsumerHandleTestUtil::ReplayingHandle; | |
41 using Command = DataConsumerHandleTestUtil::Command; | |
42 template <typename T> | |
43 using HandleReaderRunner = DataConsumerHandleTestUtil::HandleReaderRunner<T>; | |
44 | |
45 using ::testing::_; | |
46 using ::testing::DoAll; | |
47 using ::testing::InSequence; | |
48 using ::testing::Ref; | |
49 using ::testing::Return; | |
50 using ::testing::SaveArg; | |
51 using ::testing::StrictMock; | |
52 using Checkpoint = StrictMock<::testing::MockFunction<void(int)>>; | |
53 | |
54 class MockLoaderFactory : public FetchBlobDataConsumerHandle::LoaderFactory { | |
55 public: | |
56 MOCK_METHOD4(create, ThreadableLoader*(ExecutionContext&, ThreadableLoaderCl
ient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&)); | |
57 }; | |
58 | |
59 PassRefPtr<BlobDataHandle> createBlobDataHandle(const char* s) | |
60 { | |
61 std::unique_ptr<BlobData> data = BlobData::create(); | |
62 data->appendText(s, false); | |
63 auto size = data->length(); | |
64 return BlobDataHandle::create(std::move(data), size); | |
65 } | |
66 | |
67 String toString(const Vector<char>& data) | |
68 { | |
69 return String(data.data(), data.size()); | |
70 } | |
71 | |
72 class FetchBlobDataConsumerHandleTest : public ::testing::Test { | |
73 public: | |
74 FetchBlobDataConsumerHandleTest() | |
75 : m_dummyPageHolder(DummyPageHolder::create(IntSize(1, 1))) {} | |
76 ~FetchBlobDataConsumerHandleTest() override | |
77 { | |
78 m_dummyPageHolder = nullptr; | |
79 // We need this to collect garbage-collected mocks. | |
80 ThreadState::current()-> collectAllGarbage(); | |
81 } | |
82 | |
83 Document& document() { return m_dummyPageHolder->document(); } | |
84 | |
85 private: | |
86 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; | |
87 }; | |
88 | |
89 TEST_F(FetchBlobDataConsumerHandleTest, CreateLoader) | |
90 { | |
91 auto factory = new StrictMock<MockLoaderFactory>; | |
92 Checkpoint checkpoint; | |
93 | |
94 ResourceRequest request; | |
95 ThreadableLoaderOptions options; | |
96 ResourceLoaderOptions resourceLoaderOptions; | |
97 | |
98 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
99 | |
100 InSequence s; | |
101 EXPECT_CALL(checkpoint, Call(1)); | |
102 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll( | |
103 SaveArg<2>(&options), | |
104 SaveArg<3>(&resourceLoaderOptions), | |
105 Return(loader.get()))); | |
106 EXPECT_CALL(*loader, start(_)).WillOnce(SaveArg<0>(&request)); | |
107 EXPECT_CALL(checkpoint, Call(2)); | |
108 EXPECT_CALL(*loader, cancel()); | |
109 | |
110 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
111 std::unique_ptr<WebDataConsumerHandle> handle | |
112 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
113 testing::runPendingTasks(); | |
114 | |
115 char buffer[1]; | |
116 size_t size = 0; | |
117 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
118 checkpoint.Call(1); | |
119 testing::runPendingTasks(); | |
120 checkpoint.Call(2); | |
121 | |
122 EXPECT_TRUE(request.url().getString().startsWith("blob:")); | |
123 EXPECT_TRUE(request.useStreamOnResponse()); | |
124 | |
125 EXPECT_EQ(ConsiderPreflight, options.preflightPolicy); | |
126 EXPECT_EQ(DenyCrossOriginRequests, options.crossOriginRequestPolicy); | |
127 EXPECT_EQ(DoNotEnforceContentSecurityPolicy, options.contentSecurityPolicyEn
forcement); | |
128 | |
129 EXPECT_EQ(DoNotBufferData, resourceLoaderOptions.dataBufferingPolicy); | |
130 EXPECT_EQ(DoNotAllowStoredCredentials, resourceLoaderOptions.allowCredential
s); | |
131 EXPECT_EQ(ClientDidNotRequestCredentials, resourceLoaderOptions.credentialsR
equested); | |
132 EXPECT_EQ(CheckContentSecurityPolicy, resourceLoaderOptions.contentSecurityP
olicyOption); | |
133 EXPECT_EQ(DocumentContext, resourceLoaderOptions.requestInitiatorContext); | |
134 EXPECT_EQ(RequestAsynchronously, resourceLoaderOptions.synchronousPolicy); | |
135 EXPECT_EQ(NotCORSEnabled, resourceLoaderOptions.corsEnabled); | |
136 } | |
137 | |
138 TEST_F(FetchBlobDataConsumerHandleTest, ZeroByteReadDoesNotCreateLoader) | |
139 { | |
140 auto factory = new StrictMock<MockLoaderFactory>; | |
141 Checkpoint checkpoint; | |
142 | |
143 InSequence s; | |
144 EXPECT_CALL(checkpoint, Call(1)); | |
145 EXPECT_CALL(checkpoint, Call(2)); | |
146 | |
147 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
148 std::unique_ptr<WebDataConsumerHandle> handle | |
149 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
150 testing::runPendingTasks(); | |
151 | |
152 size_t size = 0; | |
153 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(nullptr, 0, kNone
, &size)); | |
154 checkpoint.Call(1); | |
155 testing::runPendingTasks(); | |
156 checkpoint.Call(2); | |
157 } | |
158 | |
159 TEST_F(FetchBlobDataConsumerHandleTest, CancelLoaderWhenStopped) | |
160 { | |
161 auto factory = new StrictMock<MockLoaderFactory>; | |
162 Checkpoint checkpoint; | |
163 | |
164 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
165 | |
166 InSequence s; | |
167 EXPECT_CALL(checkpoint, Call(1)); | |
168 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(Return(load
er.get())); | |
169 EXPECT_CALL(*loader, start(_)); | |
170 EXPECT_CALL(checkpoint, Call(2)); | |
171 EXPECT_CALL(*loader, cancel()); | |
172 EXPECT_CALL(checkpoint, Call(3)); | |
173 | |
174 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
175 std::unique_ptr<WebDataConsumerHandle> handle | |
176 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
177 testing::runPendingTasks(); | |
178 | |
179 char buffer[1]; | |
180 size_t size = 0; | |
181 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
182 checkpoint.Call(1); | |
183 testing::runPendingTasks(); | |
184 checkpoint.Call(2); | |
185 document().stopActiveDOMObjects(); | |
186 checkpoint.Call(3); | |
187 } | |
188 | |
189 TEST_F(FetchBlobDataConsumerHandleTest, CancelLoaderWhenDestinationDetached) | |
190 { | |
191 auto factory = new StrictMock<MockLoaderFactory>; | |
192 Checkpoint checkpoint; | |
193 | |
194 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
195 | |
196 InSequence s; | |
197 EXPECT_CALL(checkpoint, Call(1)); | |
198 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(Return(load
er.get())); | |
199 EXPECT_CALL(*loader, start(_)); | |
200 EXPECT_CALL(checkpoint, Call(2)); | |
201 EXPECT_CALL(checkpoint, Call(3)); | |
202 EXPECT_CALL(*loader, cancel()); | |
203 EXPECT_CALL(checkpoint, Call(4)); | |
204 | |
205 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
206 std::unique_ptr<WebDataConsumerHandle> handle | |
207 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
208 std::unique_ptr<WebDataConsumerHandle::Reader> reader = handle->obtainReader
(nullptr); | |
209 testing::runPendingTasks(); | |
210 | |
211 char buffer[1]; | |
212 size_t size = 0; | |
213 ASSERT_EQ(kShouldWait, reader->read(buffer, sizeof(buffer), kNone, &size)); | |
214 checkpoint.Call(1); | |
215 testing::runPendingTasks(); | |
216 checkpoint.Call(2); | |
217 handle = nullptr; | |
218 reader = nullptr; | |
219 checkpoint.Call(3); | |
220 ThreadState::current()-> collectAllGarbage(); | |
221 checkpoint.Call(4); | |
222 } | |
223 | |
224 TEST_F(FetchBlobDataConsumerHandleTest, ReadTest) | |
225 { | |
226 auto factory = new StrictMock<MockLoaderFactory>; | |
227 Checkpoint checkpoint; | |
228 | |
229 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
230 ThreadableLoaderClient* client = nullptr; | |
231 | |
232 InSequence s; | |
233 EXPECT_CALL(checkpoint, Call(1)); | |
234 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveA
rg<1>(&client), Return(loader.get()))); | |
235 EXPECT_CALL(*loader, start(_)); | |
236 EXPECT_CALL(checkpoint, Call(2)); | |
237 EXPECT_CALL(*loader, cancel()); | |
238 | |
239 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
240 std::unique_ptr<WebDataConsumerHandle> handle | |
241 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
242 | |
243 std::unique_ptr<ReplayingHandle> src = ReplayingHandle::create(); | |
244 src->add(Command(Command::Wait)); | |
245 src->add(Command(Command::Data, "hello, ")); | |
246 src->add(Command(Command::Data, "world")); | |
247 src->add(Command(Command::Wait)); | |
248 src->add(Command(Command::Done)); | |
249 | |
250 char buffer[1]; | |
251 size_t size = 0; | |
252 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
253 checkpoint.Call(1); | |
254 testing::runPendingTasks(); | |
255 checkpoint.Call(2); | |
256 client->didReceiveResponse(0, ResourceResponse(), std::move(src)); | |
257 HandleReaderRunner<HandleReader> runner(std::move(handle)); | |
258 std::unique_ptr<HandleReadResult> r = runner.wait(); | |
259 EXPECT_EQ(kDone, r->result()); | |
260 EXPECT_EQ("hello, world", toString(r->data())); | |
261 } | |
262 | |
263 TEST_F(FetchBlobDataConsumerHandleTest, TwoPhaseReadTest) | |
264 { | |
265 auto factory = new StrictMock<MockLoaderFactory>; | |
266 Checkpoint checkpoint; | |
267 | |
268 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
269 ThreadableLoaderClient* client = nullptr; | |
270 | |
271 InSequence s; | |
272 EXPECT_CALL(checkpoint, Call(1)); | |
273 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveA
rg<1>(&client), Return(loader.get()))); | |
274 EXPECT_CALL(*loader, start(_)); | |
275 EXPECT_CALL(checkpoint, Call(2)); | |
276 EXPECT_CALL(*loader, cancel()); | |
277 | |
278 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
279 std::unique_ptr<WebDataConsumerHandle> handle | |
280 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
281 | |
282 std::unique_ptr<ReplayingHandle> src = ReplayingHandle::create(); | |
283 src->add(Command(Command::Wait)); | |
284 src->add(Command(Command::Data, "hello, ")); | |
285 src->add(Command(Command::Data, "world")); | |
286 src->add(Command(Command::Wait)); | |
287 src->add(Command(Command::Done)); | |
288 | |
289 char buffer[1]; | |
290 size_t size = 0; | |
291 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
292 checkpoint.Call(1); | |
293 testing::runPendingTasks(); | |
294 checkpoint.Call(2); | |
295 client->didReceiveResponse(0, ResourceResponse(), std::move(src)); | |
296 HandleReaderRunner<HandleTwoPhaseReader> runner(std::move(handle)); | |
297 std::unique_ptr<HandleReadResult> r = runner.wait(); | |
298 EXPECT_EQ(kDone, r->result()); | |
299 EXPECT_EQ("hello, world", toString(r->data())); | |
300 } | |
301 | |
302 TEST_F(FetchBlobDataConsumerHandleTest, LoadErrorTest) | |
303 { | |
304 auto factory = new StrictMock<MockLoaderFactory>; | |
305 Checkpoint checkpoint; | |
306 | |
307 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
308 ThreadableLoaderClient* client = nullptr; | |
309 | |
310 InSequence s; | |
311 EXPECT_CALL(checkpoint, Call(1)); | |
312 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveA
rg<1>(&client), Return(loader.get()))); | |
313 EXPECT_CALL(*loader, start(_)); | |
314 EXPECT_CALL(checkpoint, Call(2)); | |
315 | |
316 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
317 std::unique_ptr<WebDataConsumerHandle> handle | |
318 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
319 | |
320 char buffer[1]; | |
321 size_t size = 0; | |
322 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
323 checkpoint.Call(1); | |
324 testing::runPendingTasks(); | |
325 checkpoint.Call(2); | |
326 client->didFail(ResourceError()); | |
327 HandleReaderRunner<HandleReader> runner(std::move(handle)); | |
328 std::unique_ptr<HandleReadResult> r = runner.wait(); | |
329 EXPECT_EQ(kUnexpectedError, r->result()); | |
330 } | |
331 | |
332 TEST_F(FetchBlobDataConsumerHandleTest, BodyLoadErrorTest) | |
333 { | |
334 auto factory = new StrictMock<MockLoaderFactory>; | |
335 Checkpoint checkpoint; | |
336 | |
337 Persistent<MockThreadableLoader> loader = MockThreadableLoader::create(); | |
338 ThreadableLoaderClient* client = nullptr; | |
339 | |
340 InSequence s; | |
341 EXPECT_CALL(checkpoint, Call(1)); | |
342 EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveA
rg<1>(&client), Return(loader.get()))); | |
343 EXPECT_CALL(*loader, start(_)); | |
344 EXPECT_CALL(checkpoint, Call(2)); | |
345 EXPECT_CALL(*loader, cancel()); | |
346 | |
347 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
348 std::unique_ptr<WebDataConsumerHandle> handle | |
349 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
350 | |
351 std::unique_ptr<ReplayingHandle> src = ReplayingHandle::create(); | |
352 src->add(Command(Command::Wait)); | |
353 src->add(Command(Command::Data, "hello, ")); | |
354 src->add(Command(Command::Error)); | |
355 | |
356 char buffer[1]; | |
357 size_t size = 0; | |
358 ASSERT_EQ(kShouldWait, handle->obtainReader(nullptr)->read(buffer, sizeof(bu
ffer), kNone, &size)); | |
359 checkpoint.Call(1); | |
360 testing::runPendingTasks(); | |
361 checkpoint.Call(2); | |
362 client->didReceiveResponse(0, ResourceResponse(), std::move(src)); | |
363 HandleReaderRunner<HandleReader> runner(std::move(handle)); | |
364 std::unique_ptr<HandleReadResult> r = runner.wait(); | |
365 EXPECT_EQ(kUnexpectedError, r->result()); | |
366 } | |
367 | |
368 TEST_F(FetchBlobDataConsumerHandleTest, DrainAsBlobDataHandle) | |
369 { | |
370 auto factory = new StrictMock<MockLoaderFactory>; | |
371 | |
372 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
373 std::unique_ptr<FetchDataConsumerHandle> handle | |
374 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
375 | |
376 size_t size = 0; | |
377 EXPECT_EQ(blobDataHandle, handle->obtainFetchDataReader(nullptr)->drainAsBlo
bDataHandle()); | |
378 EXPECT_FALSE(handle->obtainFetchDataReader(nullptr)->drainAsFormData()); | |
379 | |
380 EXPECT_EQ(kDone, handle->obtainReader(nullptr)->read(nullptr, 0, kNone, &siz
e)); | |
381 } | |
382 | |
383 TEST_F(FetchBlobDataConsumerHandleTest, DrainAsFormData) | |
384 { | |
385 auto factory = new StrictMock<MockLoaderFactory>; | |
386 | |
387 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
388 std::unique_ptr<FetchDataConsumerHandle> handle | |
389 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
390 | |
391 RefPtr<EncodedFormData> formData = handle->obtainFetchDataReader(nullptr)->d
rainAsFormData(); | |
392 ASSERT_TRUE(formData); | |
393 EXPECT_TRUE(formData->isSafeToSendToAnotherThread()); | |
394 ASSERT_EQ(1u, formData->elements().size()); | |
395 EXPECT_EQ(FormDataElement::encodedBlob, formData->elements()[0].m_type); | |
396 EXPECT_EQ(blobDataHandle->uuid(), formData->elements()[0].m_blobUUID); | |
397 EXPECT_EQ(blobDataHandle, formData->elements()[0].m_optionalBlobDataHandle); | |
398 | |
399 EXPECT_FALSE(handle->obtainFetchDataReader(nullptr)->drainAsBlobDataHandle()
); | |
400 size_t size; | |
401 EXPECT_EQ(kDone, handle->obtainFetchDataReader(nullptr)->read(nullptr, 0, kN
one, &size)); | |
402 } | |
403 | |
404 TEST_F(FetchBlobDataConsumerHandleTest, ZeroByteReadDoesNotAffectDraining) | |
405 { | |
406 auto factory = new StrictMock<MockLoaderFactory>; | |
407 | |
408 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
409 std::unique_ptr<FetchDataConsumerHandle> handle | |
410 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
411 std::unique_ptr<FetchDataConsumerHandle::Reader> reader = handle->obtainFetc
hDataReader(nullptr); | |
412 | |
413 size_t readSize; | |
414 EXPECT_EQ(kShouldWait, reader->read(nullptr, 0, kNone, &readSize)); | |
415 EXPECT_EQ(blobDataHandle, reader->drainAsBlobDataHandle()); | |
416 } | |
417 | |
418 TEST_F(FetchBlobDataConsumerHandleTest, OneByteReadAffectsDraining) | |
419 { | |
420 auto factory = new StrictMock<MockLoaderFactory>; | |
421 | |
422 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
423 std::unique_ptr<FetchDataConsumerHandle> handle | |
424 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
425 std::unique_ptr<FetchDataConsumerHandle::Reader> reader = handle->obtainFetc
hDataReader(nullptr); | |
426 | |
427 size_t readSize; | |
428 char c; | |
429 EXPECT_EQ(kShouldWait, reader->read(&c, 1, kNone, &readSize)); | |
430 EXPECT_FALSE(reader->drainAsFormData()); | |
431 } | |
432 | |
433 TEST_F(FetchBlobDataConsumerHandleTest, BeginReadAffectsDraining) | |
434 { | |
435 auto factory = new StrictMock<MockLoaderFactory>; | |
436 | |
437 RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a ti
me"); | |
438 std::unique_ptr<FetchDataConsumerHandle> handle | |
439 = FetchBlobDataConsumerHandle::create(&document(), blobDataHandle, facto
ry); | |
440 std::unique_ptr<FetchDataConsumerHandle::Reader> reader = handle->obtainFetc
hDataReader(nullptr); | |
441 | |
442 const void* buffer; | |
443 size_t available; | |
444 EXPECT_EQ(kShouldWait, reader->beginRead(&buffer, kNone, &available)); | |
445 EXPECT_FALSE(reader->drainAsBlobDataHandle()); | |
446 } | |
447 | |
448 } // namespace | |
449 } // namespace blink | |
OLD | NEW |