OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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 "content/child/url_response_body_consumer.h" | 5 #include "content/child/url_response_body_consumer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_forward.h" | 8 #include "base/callback_forward.h" |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "url/gurl.h" | 22 #include "url/gurl.h" |
23 #include "url/origin.h" | 23 #include "url/origin.h" |
24 | 24 |
25 namespace content { | 25 namespace content { |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 class TestRequestPeer : public RequestPeer { | 29 class TestRequestPeer : public RequestPeer { |
30 public: | 30 public: |
31 struct Context; | 31 struct Context; |
32 explicit TestRequestPeer(Context* context) : context_(context) {} | 32 TestRequestPeer(Context* context, |
| 33 scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
| 34 : context_(context), task_runner_(std::move(task_runner)) {} |
33 | 35 |
34 void OnUploadProgress(uint64_t position, uint64_t size) override { | 36 void OnUploadProgress(uint64_t position, uint64_t size) override { |
35 ADD_FAILURE() << "OnUploadProgress should not be called."; | 37 ADD_FAILURE() << "OnUploadProgress should not be called."; |
36 } | 38 } |
37 | 39 |
38 bool OnReceivedRedirect(const net::RedirectInfo& redirect_info, | 40 bool OnReceivedRedirect(const net::RedirectInfo& redirect_info, |
39 const ResourceResponseInfo& info) override { | 41 const ResourceResponseInfo& info) override { |
40 ADD_FAILURE() << "OnReceivedRedirect should not be called."; | 42 ADD_FAILURE() << "OnReceivedRedirect should not be called."; |
41 return false; | 43 return false; |
42 } | 44 } |
43 | 45 |
44 void OnReceivedResponse(const ResourceResponseInfo& info) override { | 46 void OnReceivedResponse(const ResourceResponseInfo& info) override { |
45 ADD_FAILURE() << "OnReceivedResponse should not be called."; | 47 ADD_FAILURE() << "OnReceivedResponse should not be called."; |
46 } | 48 } |
47 | 49 |
48 void OnDownloadedData(int len, int encoded_data_length) override { | 50 void OnDownloadedData(int len, int encoded_data_length) override { |
49 ADD_FAILURE() << "OnDownloadedData should not be called."; | 51 ADD_FAILURE() << "OnDownloadedData should not be called."; |
50 } | 52 } |
51 | 53 |
52 void OnReceivedData(std::unique_ptr<ReceivedData> data) override { | 54 void OnReceivedData(std::unique_ptr<ReceivedData> data) override { |
53 EXPECT_FALSE(context_->complete); | 55 EXPECT_FALSE(context_->complete); |
54 context_->data.append(data->payload(), data->length()); | 56 context_->data.append(data->payload(), data->length()); |
| 57 if (context_->release_data_asynchronously) |
| 58 task_runner_->DeleteSoon(FROM_HERE, data.release()); |
55 context_->run_loop_quit_closure.Run(); | 59 context_->run_loop_quit_closure.Run(); |
56 } | 60 } |
57 | 61 |
58 void OnTransferSizeUpdated(int transfer_size_diff) override {} | 62 void OnTransferSizeUpdated(int transfer_size_diff) override {} |
59 | 63 |
60 void OnCompletedRequest(int error_code, | 64 void OnCompletedRequest(int error_code, |
61 bool was_ignored_by_handler, | 65 bool was_ignored_by_handler, |
62 bool stale_copy_in_cache, | 66 bool stale_copy_in_cache, |
63 const base::TimeTicks& completion_time, | 67 const base::TimeTicks& completion_time, |
64 int64_t total_transfer_size, | 68 int64_t total_transfer_size, |
65 int64_t encoded_body_size) override { | 69 int64_t encoded_body_size) override { |
66 EXPECT_FALSE(context_->complete); | 70 EXPECT_FALSE(context_->complete); |
67 context_->complete = true; | 71 context_->complete = true; |
68 context_->error_code = error_code; | 72 context_->error_code = error_code; |
69 context_->run_loop_quit_closure.Run(); | 73 context_->run_loop_quit_closure.Run(); |
70 } | 74 } |
71 | 75 |
72 struct Context { | 76 struct Context { |
73 // Data received. If downloading to file, remains empty. | 77 // Data received. If downloading to file, remains empty. |
74 std::string data; | 78 std::string data; |
75 bool complete = false; | 79 bool complete = false; |
76 base::Closure run_loop_quit_closure; | 80 base::Closure run_loop_quit_closure; |
77 int error_code = net::OK; | 81 int error_code = net::OK; |
| 82 bool release_data_asynchronously = false; |
78 }; | 83 }; |
79 | 84 |
80 private: | 85 private: |
81 Context* context_; | 86 Context* context_; |
| 87 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
82 | 88 |
83 DISALLOW_COPY_AND_ASSIGN(TestRequestPeer); | 89 DISALLOW_COPY_AND_ASSIGN(TestRequestPeer); |
84 }; | 90 }; |
85 | 91 |
86 class URLResponseBodyConsumerTest : public ::testing::Test, | 92 class URLResponseBodyConsumerTest : public ::testing::Test, |
87 public ::IPC::Sender { | 93 public ::IPC::Sender { |
88 protected: | 94 protected: |
89 URLResponseBodyConsumerTest() | 95 URLResponseBodyConsumerTest() |
90 : dispatcher_(new ResourceDispatcher(this, message_loop_.task_runner())) { | 96 : dispatcher_(new ResourceDispatcher(this, message_loop_.task_runner())) { |
91 } | 97 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 options.element_num_bytes = 1; | 129 options.element_num_bytes = 1; |
124 options.capacity_num_bytes = 1024; | 130 options.capacity_num_bytes = 1024; |
125 return options; | 131 return options; |
126 } | 132 } |
127 | 133 |
128 // Returns the request id. | 134 // Returns the request id. |
129 int SetUpRequestPeer(std::unique_ptr<ResourceRequest> request, | 135 int SetUpRequestPeer(std::unique_ptr<ResourceRequest> request, |
130 TestRequestPeer::Context* context) { | 136 TestRequestPeer::Context* context) { |
131 return dispatcher_->StartAsync( | 137 return dispatcher_->StartAsync( |
132 std::move(request), 0, nullptr, url::Origin(), | 138 std::move(request), 0, nullptr, url::Origin(), |
133 base::MakeUnique<TestRequestPeer>(context), | 139 base::MakeUnique<TestRequestPeer>(context, message_loop_.task_runner()), |
134 blink::WebURLRequest::LoadingIPCType::ChromeIPC, nullptr, nullptr); | 140 blink::WebURLRequest::LoadingIPCType::ChromeIPC, nullptr, nullptr); |
135 } | 141 } |
136 | 142 |
137 void Run(TestRequestPeer::Context* context) { | 143 void Run(TestRequestPeer::Context* context) { |
138 base::RunLoop run_loop; | 144 base::RunLoop run_loop; |
139 context->run_loop_quit_closure = run_loop.QuitClosure(); | 145 context->run_loop_quit_closure = run_loop.QuitClosure(); |
140 run_loop.Run(); | 146 run_loop.Run(); |
141 } | 147 } |
142 | 148 |
143 base::MessageLoop message_loop_; | 149 base::MessageLoop message_loop_; |
144 std::unique_ptr<ResourceDispatcher> dispatcher_; | 150 std::unique_ptr<ResourceDispatcher> dispatcher_; |
145 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE; | 151 static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE; |
146 }; | 152 }; |
147 | 153 |
148 TEST_F(URLResponseBodyConsumerTest, ReceiveData) { | 154 TEST_F(URLResponseBodyConsumerTest, ReceiveData) { |
149 TestRequestPeer::Context context; | 155 TestRequestPeer::Context context; |
150 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); | 156 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); |
151 int request_id = SetUpRequestPeer(std::move(request), &context); | 157 int request_id = SetUpRequestPeer(std::move(request), &context); |
152 mojo::DataPipe data_pipe(CreateDataPipeOptions()); | 158 mojo::DataPipe data_pipe(CreateDataPipeOptions()); |
153 | 159 |
154 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( | 160 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( |
155 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), | 161 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), |
156 message_loop_.task_runner())); | 162 message_loop_.task_runner())); |
157 consumer->Start(message_loop_.task_runner().get()); | 163 consumer->Start(); |
158 | 164 |
159 mojo::ScopedDataPipeProducerHandle writer = | 165 mojo::ScopedDataPipeProducerHandle writer = |
160 std::move(data_pipe.producer_handle); | 166 std::move(data_pipe.producer_handle); |
161 std::string buffer = "hello"; | 167 std::string buffer = "hello"; |
162 uint32_t size = buffer.size(); | 168 uint32_t size = buffer.size(); |
163 MojoResult result = | 169 MojoResult result = |
164 mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); | 170 mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); |
165 ASSERT_EQ(MOJO_RESULT_OK, result); | 171 ASSERT_EQ(MOJO_RESULT_OK, result); |
166 ASSERT_EQ(buffer.size(), size); | 172 ASSERT_EQ(buffer.size(), size); |
167 | 173 |
168 Run(&context); | 174 Run(&context); |
169 | 175 |
170 EXPECT_FALSE(context.complete); | 176 EXPECT_FALSE(context.complete); |
171 EXPECT_EQ("hello", context.data); | 177 EXPECT_EQ("hello", context.data); |
172 } | 178 } |
173 | 179 |
174 TEST_F(URLResponseBodyConsumerTest, OnCompleteThenClose) { | 180 TEST_F(URLResponseBodyConsumerTest, OnCompleteThenClose) { |
175 TestRequestPeer::Context context; | 181 TestRequestPeer::Context context; |
176 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); | 182 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); |
177 int request_id = SetUpRequestPeer(std::move(request), &context); | 183 int request_id = SetUpRequestPeer(std::move(request), &context); |
178 mojo::DataPipe data_pipe(CreateDataPipeOptions()); | 184 mojo::DataPipe data_pipe(CreateDataPipeOptions()); |
179 | 185 |
180 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( | 186 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( |
181 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), | 187 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), |
182 message_loop_.task_runner())); | 188 message_loop_.task_runner())); |
183 consumer->Start(message_loop_.task_runner().get()); | 189 consumer->Start(); |
184 | 190 |
185 consumer->OnComplete(ResourceRequestCompletionStatus()); | 191 consumer->OnComplete(ResourceRequestCompletionStatus()); |
186 mojo::ScopedDataPipeProducerHandle writer = | 192 mojo::ScopedDataPipeProducerHandle writer = |
| 193 std::move(data_pipe.producer_handle); |
| 194 std::string buffer = "hello"; |
| 195 uint32_t size = buffer.size(); |
| 196 MojoResult result = |
| 197 mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); |
| 198 ASSERT_EQ(MOJO_RESULT_OK, result); |
| 199 ASSERT_EQ(buffer.size(), size); |
| 200 |
| 201 Run(&context); |
| 202 |
| 203 writer.reset(); |
| 204 EXPECT_FALSE(context.complete); |
| 205 EXPECT_EQ("hello", context.data); |
| 206 |
| 207 Run(&context); |
| 208 |
| 209 EXPECT_TRUE(context.complete); |
| 210 EXPECT_EQ("hello", context.data); |
| 211 } |
| 212 |
| 213 // Release the received data asynchronously. This leads to MOJO_RESULT_BUSY |
| 214 // from the BeginReadDataRaw call in OnReadable. |
| 215 TEST_F(URLResponseBodyConsumerTest, OnCompleteThenCloseWithAsyncRelease) { |
| 216 TestRequestPeer::Context context; |
| 217 context.release_data_asynchronously = true; |
| 218 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); |
| 219 int request_id = SetUpRequestPeer(std::move(request), &context); |
| 220 mojo::DataPipe data_pipe(CreateDataPipeOptions()); |
| 221 |
| 222 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( |
| 223 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), |
| 224 message_loop_.task_runner())); |
| 225 consumer->Start(); |
| 226 |
| 227 consumer->OnComplete(ResourceRequestCompletionStatus()); |
| 228 mojo::ScopedDataPipeProducerHandle writer = |
187 std::move(data_pipe.producer_handle); | 229 std::move(data_pipe.producer_handle); |
188 std::string buffer = "hello"; | 230 std::string buffer = "hello"; |
189 uint32_t size = buffer.size(); | 231 uint32_t size = buffer.size(); |
190 MojoResult result = | 232 MojoResult result = |
191 mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); | 233 mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); |
192 ASSERT_EQ(MOJO_RESULT_OK, result); | 234 ASSERT_EQ(MOJO_RESULT_OK, result); |
193 ASSERT_EQ(buffer.size(), size); | 235 ASSERT_EQ(buffer.size(), size); |
194 | 236 |
195 Run(&context); | 237 Run(&context); |
196 | 238 |
197 writer.reset(); | 239 writer.reset(); |
198 EXPECT_FALSE(context.complete); | 240 EXPECT_FALSE(context.complete); |
199 EXPECT_EQ("hello", context.data); | 241 EXPECT_EQ("hello", context.data); |
200 | 242 |
201 Run(&context); | 243 Run(&context); |
202 | 244 |
203 EXPECT_TRUE(context.complete); | 245 EXPECT_TRUE(context.complete); |
204 EXPECT_EQ("hello", context.data); | 246 EXPECT_EQ("hello", context.data); |
205 } | 247 } |
206 | 248 |
207 TEST_F(URLResponseBodyConsumerTest, CloseThenOnComplete) { | 249 TEST_F(URLResponseBodyConsumerTest, CloseThenOnComplete) { |
208 TestRequestPeer::Context context; | 250 TestRequestPeer::Context context; |
209 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); | 251 std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); |
210 int request_id = SetUpRequestPeer(std::move(request), &context); | 252 int request_id = SetUpRequestPeer(std::move(request), &context); |
211 mojo::DataPipe data_pipe(CreateDataPipeOptions()); | 253 mojo::DataPipe data_pipe(CreateDataPipeOptions()); |
212 | 254 |
213 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( | 255 scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( |
214 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), | 256 request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), |
215 message_loop_.task_runner())); | 257 message_loop_.task_runner())); |
216 consumer->Start(message_loop_.task_runner().get()); | 258 consumer->Start(); |
217 | 259 |
218 ResourceRequestCompletionStatus status; | 260 ResourceRequestCompletionStatus status; |
219 status.error_code = net::ERR_FAILED; | 261 status.error_code = net::ERR_FAILED; |
220 data_pipe.producer_handle.reset(); | 262 data_pipe.producer_handle.reset(); |
221 consumer->OnComplete(status); | 263 consumer->OnComplete(status); |
222 | 264 |
223 Run(&context); | 265 Run(&context); |
224 | 266 |
225 EXPECT_TRUE(context.complete); | 267 EXPECT_TRUE(context.complete); |
226 EXPECT_EQ(net::ERR_FAILED, context.error_code); | 268 EXPECT_EQ(net::ERR_FAILED, context.error_code); |
227 EXPECT_EQ("", context.data); | 269 EXPECT_EQ("", context.data); |
228 } | 270 } |
229 | 271 |
230 } // namespace | 272 } // namespace |
231 | 273 |
232 } // namespace content | 274 } // namespace content |
OLD | NEW |