OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "content/browser/renderer_host/resource_dispatcher_host_impl.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/file_path.h" | |
11 #include "base/memory/scoped_vector.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/process_util.h" | |
14 #include "base/string_number_conversions.h" | |
15 #include "base/string_split.h" | |
16 #include "content/browser/browser_thread_impl.h" | |
17 #include "content/browser/child_process_security_policy_impl.h" | |
18 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" | |
19 #include "content/browser/renderer_host/resource_message_filter.h" | |
20 #include "content/common/child_process_host_impl.h" | |
21 #include "content/common/resource_messages.h" | |
22 #include "content/common/view_messages.h" | |
23 #include "content/public/browser/global_request_id.h" | |
24 #include "content/public/browser/resource_context.h" | |
25 #include "content/public/browser/resource_dispatcher_host_delegate.h" | |
26 #include "content/public/browser/resource_throttle.h" | |
27 #include "content/public/common/resource_response.h" | |
28 #include "content/public/test/test_browser_context.h" | |
29 #include "content/test/test_content_browser_client.h" | |
30 #include "net/base/net_errors.h" | |
31 #include "net/base/upload_data.h" | |
32 #include "net/http/http_util.h" | |
33 #include "net/url_request/url_request.h" | |
34 #include "net/url_request/url_request_context.h" | |
35 #include "net/url_request/url_request_job.h" | |
36 #include "net/url_request/url_request_simple_job.h" | |
37 #include "net/url_request/url_request_test_job.h" | |
38 #include "testing/gtest/include/gtest/gtest.h" | |
39 #include "webkit/appcache/appcache_interfaces.h" | |
40 | |
41 // TODO(eroman): Write unit tests for SafeBrowsing that exercise | |
42 // SafeBrowsingResourceHandler. | |
43 | |
44 namespace content { | |
45 | |
46 namespace { | |
47 | |
48 // Returns the resource response header structure for this request. | |
49 void GetResponseHead(const std::vector<IPC::Message>& messages, | |
50 ResourceResponseHead* response_head) { | |
51 ASSERT_GE(messages.size(), 2U); | |
52 | |
53 // The first messages should be received response. | |
54 ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type()); | |
55 | |
56 PickleIterator iter(messages[0]); | |
57 int request_id; | |
58 ASSERT_TRUE(IPC::ReadParam(&messages[0], &iter, &request_id)); | |
59 ASSERT_TRUE(IPC::ReadParam(&messages[0], &iter, response_head)); | |
60 } | |
61 | |
62 void GenerateIPCMessage( | |
63 scoped_refptr<ResourceMessageFilter> filter, | |
64 scoped_ptr<IPC::Message> message) { | |
65 bool msg_is_ok; | |
66 ResourceDispatcherHostImpl::Get()->OnMessageReceived( | |
67 *message, filter.get(), &msg_is_ok); | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 static int RequestIDForMessage(const IPC::Message& msg) { | |
73 int request_id = -1; | |
74 switch (msg.type()) { | |
75 case ResourceMsg_UploadProgress::ID: | |
76 case ResourceMsg_ReceivedResponse::ID: | |
77 case ResourceMsg_ReceivedRedirect::ID: | |
78 case ResourceMsg_SetDataBuffer::ID: | |
79 case ResourceMsg_DataReceived::ID: | |
80 case ResourceMsg_RequestComplete::ID: | |
81 request_id = IPC::MessageIterator(msg).NextInt(); | |
82 break; | |
83 } | |
84 return request_id; | |
85 } | |
86 | |
87 static ResourceHostMsg_Request CreateResourceRequest( | |
88 const char* method, | |
89 ResourceType::Type type, | |
90 const GURL& url) { | |
91 ResourceHostMsg_Request request; | |
92 request.method = std::string(method); | |
93 request.url = url; | |
94 request.first_party_for_cookies = url; // bypass third-party cookie blocking | |
95 request.referrer_policy = WebKit::WebReferrerPolicyDefault; | |
96 request.load_flags = 0; | |
97 request.origin_pid = 0; | |
98 request.resource_type = type; | |
99 request.request_context = 0; | |
100 request.appcache_host_id = appcache::kNoHostId; | |
101 request.download_to_file = false; | |
102 request.is_main_frame = true; | |
103 request.frame_id = 0; | |
104 request.parent_is_main_frame = false; | |
105 request.parent_frame_id = -1; | |
106 request.transition_type = PAGE_TRANSITION_LINK; | |
107 request.allow_download = true; | |
108 return request; | |
109 } | |
110 | |
111 // Spin up the message loop to kick off the request. | |
112 static void KickOffRequest() { | |
113 MessageLoop::current()->RunUntilIdle(); | |
114 } | |
115 | |
116 // We may want to move this to a shared space if it is useful for something else | |
117 class ResourceIPCAccumulator { | |
118 public: | |
119 void AddMessage(const IPC::Message& msg) { | |
120 messages_.push_back(msg); | |
121 } | |
122 | |
123 // This groups the messages by their request ID. The groups will be in order | |
124 // that the first message for each request ID was received, and the messages | |
125 // within the groups will be in the order that they appeared. | |
126 // Note that this clears messages_. | |
127 typedef std::vector< std::vector<IPC::Message> > ClassifiedMessages; | |
128 void GetClassifiedMessages(ClassifiedMessages* msgs); | |
129 | |
130 private: | |
131 std::vector<IPC::Message> messages_; | |
132 }; | |
133 | |
134 // This is very inefficient as a result of repeatedly extracting the ID, use | |
135 // only for tests! | |
136 void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) { | |
137 while (!messages_.empty()) { | |
138 // Ignore unknown message types as it is valid for code to generated other | |
139 // IPCs as side-effects that we are not testing here. | |
140 int cur_id = RequestIDForMessage(messages_[0]); | |
141 if (cur_id != -1) { | |
142 std::vector<IPC::Message> cur_requests; | |
143 cur_requests.push_back(messages_[0]); | |
144 // find all other messages with this ID | |
145 for (int i = 1; i < static_cast<int>(messages_.size()); i++) { | |
146 int id = RequestIDForMessage(messages_[i]); | |
147 if (id == cur_id) { | |
148 cur_requests.push_back(messages_[i]); | |
149 messages_.erase(messages_.begin() + i); | |
150 i--; | |
151 } | |
152 } | |
153 msgs->push_back(cur_requests); | |
154 } | |
155 messages_.erase(messages_.begin()); | |
156 } | |
157 } | |
158 | |
159 class MockURLRequestContextSelector | |
160 : public ResourceMessageFilter::URLRequestContextSelector { | |
161 public: | |
162 explicit MockURLRequestContextSelector( | |
163 net::URLRequestContext* request_context) | |
164 : request_context_(request_context) {} | |
165 | |
166 virtual net::URLRequestContext* GetRequestContext( | |
167 ResourceType::Type request_type) { | |
168 return request_context_; | |
169 } | |
170 | |
171 private: | |
172 net::URLRequestContext* const request_context_; | |
173 }; | |
174 | |
175 // This class forwards the incoming messages to the ResourceDispatcherHostTest. | |
176 // This is used to emulate different sub-processes, since this filter will | |
177 // have a different ID than the original. For the test, we want all the incoming | |
178 // messages to go to the same place, which is why this forwards. | |
179 class ForwardingFilter : public ResourceMessageFilter { | |
180 public: | |
181 explicit ForwardingFilter(IPC::Sender* dest, | |
182 ResourceContext* resource_context) | |
183 : ResourceMessageFilter( | |
184 ChildProcessHostImpl::GenerateChildProcessUniqueId(), | |
185 PROCESS_TYPE_RENDERER, | |
186 resource_context, NULL, NULL, | |
187 new MockURLRequestContextSelector( | |
188 resource_context->GetRequestContext())), | |
189 dest_(dest) { | |
190 OnChannelConnected(base::GetCurrentProcId()); | |
191 } | |
192 | |
193 // ResourceMessageFilter override | |
194 virtual bool Send(IPC::Message* msg) { | |
195 if (!dest_) | |
196 return false; | |
197 return dest_->Send(msg); | |
198 } | |
199 | |
200 protected: | |
201 virtual ~ForwardingFilter() {} | |
202 | |
203 private: | |
204 IPC::Sender* dest_; | |
205 | |
206 DISALLOW_COPY_AND_ASSIGN(ForwardingFilter); | |
207 }; | |
208 | |
209 // This class is a variation on URLRequestTestJob in that it does | |
210 // not complete start upon entry, only when specifically told to. | |
211 class URLRequestTestDelayedStartJob : public net::URLRequestTestJob { | |
212 public: | |
213 URLRequestTestDelayedStartJob(net::URLRequest* request, | |
214 net::NetworkDelegate* network_delegate) | |
215 : net::URLRequestTestJob(request, network_delegate) { | |
216 Init(); | |
217 } | |
218 URLRequestTestDelayedStartJob(net::URLRequest* request, | |
219 net::NetworkDelegate* network_delegate, | |
220 bool auto_advance) | |
221 : net::URLRequestTestJob(request, network_delegate, auto_advance) { | |
222 Init(); | |
223 } | |
224 URLRequestTestDelayedStartJob(net::URLRequest* request, | |
225 net::NetworkDelegate* network_delegate, | |
226 const std::string& response_headers, | |
227 const std::string& response_data, | |
228 bool auto_advance) | |
229 : net::URLRequestTestJob(request, | |
230 network_delegate, | |
231 response_headers, | |
232 response_data, | |
233 auto_advance) { | |
234 Init(); | |
235 } | |
236 | |
237 // Do nothing until you're told to. | |
238 virtual void Start() {} | |
239 | |
240 // Finish starting a URL request whose job is an instance of | |
241 // URLRequestTestDelayedStartJob. It is illegal to call this routine | |
242 // with a URLRequest that does not use URLRequestTestDelayedStartJob. | |
243 static void CompleteStart(net::URLRequest* request) { | |
244 for (URLRequestTestDelayedStartJob* job = list_head_; | |
245 job; | |
246 job = job->next_) { | |
247 if (job->request() == request) { | |
248 job->net::URLRequestTestJob::Start(); | |
249 return; | |
250 } | |
251 } | |
252 NOTREACHED(); | |
253 } | |
254 | |
255 static bool DelayedStartQueueEmpty() { | |
256 return !list_head_; | |
257 } | |
258 | |
259 static void ClearQueue() { | |
260 if (list_head_) { | |
261 LOG(ERROR) | |
262 << "Unreleased entries on URLRequestTestDelayedStartJob delay queue" | |
263 << "; may result in leaks."; | |
264 list_head_ = NULL; | |
265 } | |
266 } | |
267 | |
268 protected: | |
269 virtual ~URLRequestTestDelayedStartJob() { | |
270 for (URLRequestTestDelayedStartJob** job = &list_head_; *job; | |
271 job = &(*job)->next_) { | |
272 if (*job == this) { | |
273 *job = (*job)->next_; | |
274 return; | |
275 } | |
276 } | |
277 NOTREACHED(); | |
278 } | |
279 | |
280 private: | |
281 void Init() { | |
282 next_ = list_head_; | |
283 list_head_ = this; | |
284 } | |
285 | |
286 static URLRequestTestDelayedStartJob* list_head_; | |
287 URLRequestTestDelayedStartJob* next_; | |
288 }; | |
289 | |
290 URLRequestTestDelayedStartJob* | |
291 URLRequestTestDelayedStartJob::list_head_ = NULL; | |
292 | |
293 // This class is a variation on URLRequestTestJob in that it | |
294 // returns IO_pending errors before every read, not just the first one. | |
295 class URLRequestTestDelayedCompletionJob : public net::URLRequestTestJob { | |
296 public: | |
297 URLRequestTestDelayedCompletionJob(net::URLRequest* request, | |
298 net::NetworkDelegate* network_delegate) | |
299 : net::URLRequestTestJob(request, network_delegate) {} | |
300 URLRequestTestDelayedCompletionJob(net::URLRequest* request, | |
301 net::NetworkDelegate* network_delegate, | |
302 bool auto_advance) | |
303 : net::URLRequestTestJob(request, network_delegate, auto_advance) {} | |
304 URLRequestTestDelayedCompletionJob(net::URLRequest* request, | |
305 net::NetworkDelegate* network_delegate, | |
306 const std::string& response_headers, | |
307 const std::string& response_data, | |
308 bool auto_advance) | |
309 : net::URLRequestTestJob(request, | |
310 network_delegate, | |
311 response_headers, | |
312 response_data, | |
313 auto_advance) {} | |
314 | |
315 protected: | |
316 ~URLRequestTestDelayedCompletionJob() {} | |
317 | |
318 private: | |
319 virtual bool NextReadAsync() OVERRIDE { return true; } | |
320 }; | |
321 | |
322 class URLRequestBigJob : public net::URLRequestSimpleJob { | |
323 public: | |
324 URLRequestBigJob(net::URLRequest* request, | |
325 net::NetworkDelegate* network_delegate) | |
326 : net::URLRequestSimpleJob(request, network_delegate) { | |
327 } | |
328 | |
329 virtual int GetData(std::string* mime_type, | |
330 std::string* charset, | |
331 std::string* data, | |
332 const net::CompletionCallback& callback) const OVERRIDE { | |
333 *mime_type = "text/plain"; | |
334 *charset = "UTF-8"; | |
335 | |
336 std::string text; | |
337 int count; | |
338 if (!ParseURL(request_->url(), &text, &count)) | |
339 return net::ERR_INVALID_URL; | |
340 | |
341 data->reserve(text.size() * count); | |
342 for (int i = 0; i < count; ++i) | |
343 data->append(text); | |
344 | |
345 return net::OK; | |
346 } | |
347 | |
348 private: | |
349 virtual ~URLRequestBigJob() {} | |
350 | |
351 // big-job:substring,N | |
352 static bool ParseURL(const GURL& url, std::string* text, int* count) { | |
353 std::vector<std::string> parts; | |
354 base::SplitString(url.path(), ',', &parts); | |
355 | |
356 if (parts.size() != 2) | |
357 return false; | |
358 | |
359 *text = parts[0]; | |
360 return base::StringToInt(parts[1], count); | |
361 } | |
362 }; | |
363 | |
364 // Associated with an URLRequest to determine if the URLRequest gets deleted. | |
365 class TestUserData : public base::SupportsUserData::Data { | |
366 public: | |
367 explicit TestUserData(bool* was_deleted) | |
368 : was_deleted_(was_deleted) { | |
369 } | |
370 | |
371 ~TestUserData() { | |
372 *was_deleted_ = true; | |
373 } | |
374 | |
375 private: | |
376 bool* was_deleted_; | |
377 }; | |
378 | |
379 class TransfersAllNavigationsContentBrowserClient | |
380 : public TestContentBrowserClient { | |
381 public: | |
382 virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context, | |
383 const GURL& current_url, | |
384 const GURL& new_url) { | |
385 return true; | |
386 } | |
387 }; | |
388 | |
389 enum GenericResourceThrottleFlags { | |
390 NONE = 0, | |
391 DEFER_STARTING_REQUEST = 1 << 0, | |
392 DEFER_PROCESSING_RESPONSE = 1 << 1, | |
393 CANCEL_BEFORE_START = 1 << 2 | |
394 }; | |
395 | |
396 // Throttle that tracks the current throttle blocking a request. Only one | |
397 // can throttle any request at a time. | |
398 class GenericResourceThrottle : public ResourceThrottle { | |
399 public: | |
400 // The value is used to indicate that the throttle should not provide | |
401 // a error code when cancelling a request. net::OK is used, because this | |
402 // is not an error code. | |
403 static const int USE_DEFAULT_CANCEL_ERROR_CODE = net::OK; | |
404 | |
405 GenericResourceThrottle(int flags, int code) | |
406 : flags_(flags), | |
407 error_code_for_cancellation_(code) { | |
408 } | |
409 | |
410 virtual ~GenericResourceThrottle() { | |
411 if (active_throttle_ == this) | |
412 active_throttle_ = NULL; | |
413 } | |
414 | |
415 // ResourceThrottle implementation: | |
416 virtual void WillStartRequest(bool* defer) OVERRIDE { | |
417 ASSERT_EQ(NULL, active_throttle_); | |
418 if (flags_ & DEFER_STARTING_REQUEST) { | |
419 active_throttle_ = this; | |
420 *defer = true; | |
421 } | |
422 | |
423 if (flags_ & CANCEL_BEFORE_START) { | |
424 if (error_code_for_cancellation_ == USE_DEFAULT_CANCEL_ERROR_CODE) { | |
425 controller()->Cancel(); | |
426 } else { | |
427 controller()->CancelWithError(error_code_for_cancellation_); | |
428 } | |
429 } | |
430 } | |
431 | |
432 virtual void WillProcessResponse(bool* defer) OVERRIDE { | |
433 ASSERT_EQ(NULL, active_throttle_); | |
434 if (flags_ & DEFER_PROCESSING_RESPONSE) { | |
435 active_throttle_ = this; | |
436 *defer = true; | |
437 } | |
438 } | |
439 | |
440 void Resume() { | |
441 ASSERT_TRUE(this == active_throttle_); | |
442 active_throttle_ = NULL; | |
443 controller()->Resume(); | |
444 } | |
445 | |
446 static GenericResourceThrottle* active_throttle() { | |
447 return active_throttle_; | |
448 } | |
449 | |
450 private: | |
451 int flags_; // bit-wise union of GenericResourceThrottleFlags. | |
452 int error_code_for_cancellation_; | |
453 | |
454 // The currently active throttle, if any. | |
455 static GenericResourceThrottle* active_throttle_; | |
456 }; | |
457 // static | |
458 GenericResourceThrottle* GenericResourceThrottle::active_throttle_ = NULL; | |
459 | |
460 class TestResourceDispatcherHostDelegate | |
461 : public ResourceDispatcherHostDelegate { | |
462 public: | |
463 TestResourceDispatcherHostDelegate() | |
464 : create_two_throttles_(false), | |
465 flags_(NONE), | |
466 error_code_for_cancellation_( | |
467 GenericResourceThrottle::USE_DEFAULT_CANCEL_ERROR_CODE) { | |
468 } | |
469 | |
470 void set_url_request_user_data(base::SupportsUserData::Data* user_data) { | |
471 user_data_.reset(user_data); | |
472 } | |
473 | |
474 void set_flags(int value) { | |
475 flags_ = value; | |
476 } | |
477 | |
478 void set_error_code_for_cancellation(int code) { | |
479 error_code_for_cancellation_ = code; | |
480 } | |
481 | |
482 void set_create_two_throttles(bool create_two_throttles) { | |
483 create_two_throttles_ = create_two_throttles; | |
484 } | |
485 | |
486 // ResourceDispatcherHostDelegate implementation: | |
487 | |
488 virtual void RequestBeginning( | |
489 net::URLRequest* request, | |
490 ResourceContext* resource_context, | |
491 appcache::AppCacheService* appcache_service, | |
492 ResourceType::Type resource_type, | |
493 int child_id, | |
494 int route_id, | |
495 bool is_continuation_of_transferred_request, | |
496 ScopedVector<ResourceThrottle>* throttles) OVERRIDE { | |
497 if (user_data_.get()) { | |
498 const void* key = user_data_.get(); | |
499 request->SetUserData(key, user_data_.release()); | |
500 } | |
501 | |
502 if (flags_ != NONE) { | |
503 throttles->push_back(new GenericResourceThrottle( | |
504 flags_, error_code_for_cancellation_)); | |
505 if (create_two_throttles_) | |
506 throttles->push_back(new GenericResourceThrottle( | |
507 flags_, error_code_for_cancellation_)); | |
508 } | |
509 } | |
510 | |
511 private: | |
512 bool create_two_throttles_; | |
513 int flags_; | |
514 int error_code_for_cancellation_; | |
515 scoped_ptr<base::SupportsUserData::Data> user_data_; | |
516 }; | |
517 | |
518 class ResourceDispatcherHostTest : public testing::Test, | |
519 public IPC::Sender { | |
520 public: | |
521 ResourceDispatcherHostTest() | |
522 : ui_thread_(BrowserThread::UI, &message_loop_), | |
523 file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_), | |
524 cache_thread_(BrowserThread::CACHE, &message_loop_), | |
525 io_thread_(BrowserThread::IO, &message_loop_), | |
526 old_factory_(NULL), | |
527 resource_type_(ResourceType::SUB_RESOURCE), | |
528 send_data_received_acks_(false) { | |
529 browser_context_.reset(new TestBrowserContext()); | |
530 BrowserContext::EnsureResourceContextInitialized(browser_context_.get()); | |
531 message_loop_.RunUntilIdle(); | |
532 filter_ = new ForwardingFilter( | |
533 this, browser_context_->GetResourceContext()); | |
534 } | |
535 // IPC::Sender implementation | |
536 virtual bool Send(IPC::Message* msg) { | |
537 accum_.AddMessage(*msg); | |
538 | |
539 if (send_data_received_acks_ && | |
540 msg->type() == ResourceMsg_DataReceived::ID) { | |
541 GenerateDataReceivedACK(*msg); | |
542 } | |
543 | |
544 delete msg; | |
545 return true; | |
546 } | |
547 | |
548 protected: | |
549 // testing::Test | |
550 virtual void SetUp() { | |
551 DCHECK(!test_fixture_); | |
552 test_fixture_ = this; | |
553 ChildProcessSecurityPolicyImpl::GetInstance()->Add(0); | |
554 net::URLRequest::Deprecated::RegisterProtocolFactory( | |
555 "test", | |
556 &ResourceDispatcherHostTest::Factory); | |
557 EnsureTestSchemeIsAllowed(); | |
558 delay_start_ = false; | |
559 delay_complete_ = false; | |
560 url_request_jobs_created_count_ = 0; | |
561 } | |
562 | |
563 virtual void TearDown() { | |
564 net::URLRequest::Deprecated::RegisterProtocolFactory("test", NULL); | |
565 if (!scheme_.empty()) | |
566 net::URLRequest::Deprecated::RegisterProtocolFactory( | |
567 scheme_, old_factory_); | |
568 | |
569 EXPECT_TRUE(URLRequestTestDelayedStartJob::DelayedStartQueueEmpty()); | |
570 URLRequestTestDelayedStartJob::ClearQueue(); | |
571 | |
572 DCHECK(test_fixture_ == this); | |
573 test_fixture_ = NULL; | |
574 | |
575 host_.Shutdown(); | |
576 | |
577 ChildProcessSecurityPolicyImpl::GetInstance()->Remove(0); | |
578 | |
579 // Flush the message loop to make application verifiers happy. | |
580 if (ResourceDispatcherHostImpl::Get()) | |
581 ResourceDispatcherHostImpl::Get()->CancelRequestsForContext( | |
582 browser_context_->GetResourceContext()); | |
583 browser_context_.reset(); | |
584 message_loop_.RunUntilIdle(); | |
585 } | |
586 | |
587 // Creates a request using the current test object as the filter. | |
588 void MakeTestRequest(int render_view_id, | |
589 int request_id, | |
590 const GURL& url); | |
591 | |
592 // Generates a request using the given filter. This will probably be a | |
593 // ForwardingFilter. | |
594 void MakeTestRequest(ResourceMessageFilter* filter, | |
595 int render_view_id, | |
596 int request_id, | |
597 const GURL& url); | |
598 | |
599 void CancelRequest(int request_id); | |
600 | |
601 void CompleteStartRequest(int request_id); | |
602 void CompleteStartRequest(ResourceMessageFilter* filter, int request_id); | |
603 | |
604 void EnsureSchemeIsAllowed(const std::string& scheme) { | |
605 ChildProcessSecurityPolicyImpl* policy = | |
606 ChildProcessSecurityPolicyImpl::GetInstance(); | |
607 if (!policy->IsWebSafeScheme(scheme)) | |
608 policy->RegisterWebSafeScheme(scheme); | |
609 } | |
610 | |
611 void EnsureTestSchemeIsAllowed() { | |
612 EnsureSchemeIsAllowed("test"); | |
613 } | |
614 | |
615 // Sets a particular response for any request from now on. To switch back to | |
616 // the default bahavior, pass an empty |headers|. |headers| should be raw- | |
617 // formatted (NULLs instead of EOLs). | |
618 void SetResponse(const std::string& headers, const std::string& data) { | |
619 response_headers_ = net::HttpUtil::AssembleRawHeaders(headers.data(), | |
620 headers.size()); | |
621 response_data_ = data; | |
622 } | |
623 void SetResponse(const std::string& headers) { | |
624 SetResponse(headers, std::string()); | |
625 } | |
626 | |
627 // Sets a particular resource type for any request from now on. | |
628 void SetResourceType(ResourceType::Type type) { | |
629 resource_type_ = type; | |
630 } | |
631 | |
632 void SendDataReceivedACKs(bool send_acks) { | |
633 send_data_received_acks_ = send_acks; | |
634 } | |
635 | |
636 // Intercepts requests for the given protocol. | |
637 void HandleScheme(const std::string& scheme) { | |
638 DCHECK(scheme_.empty()); | |
639 DCHECK(!old_factory_); | |
640 scheme_ = scheme; | |
641 old_factory_ = net::URLRequest::Deprecated::RegisterProtocolFactory( | |
642 scheme_, &ResourceDispatcherHostTest::Factory); | |
643 EnsureSchemeIsAllowed(scheme); | |
644 } | |
645 | |
646 // Our own net::URLRequestJob factory. | |
647 static net::URLRequestJob* Factory(net::URLRequest* request, | |
648 net::NetworkDelegate* network_delegate, | |
649 const std::string& scheme) { | |
650 url_request_jobs_created_count_++; | |
651 if (test_fixture_->response_headers_.empty()) { | |
652 if (delay_start_) { | |
653 return new URLRequestTestDelayedStartJob(request, network_delegate); | |
654 } else if (delay_complete_) { | |
655 return new URLRequestTestDelayedCompletionJob(request, | |
656 network_delegate); | |
657 } else if (scheme == "big-job") { | |
658 return new URLRequestBigJob(request, network_delegate); | |
659 } else { | |
660 return new net::URLRequestTestJob(request, network_delegate); | |
661 } | |
662 } else { | |
663 if (delay_start_) { | |
664 return new URLRequestTestDelayedStartJob( | |
665 request, network_delegate, | |
666 test_fixture_->response_headers_, test_fixture_->response_data_, | |
667 false); | |
668 } else if (delay_complete_) { | |
669 return new URLRequestTestDelayedCompletionJob( | |
670 request, network_delegate, | |
671 test_fixture_->response_headers_, test_fixture_->response_data_, | |
672 false); | |
673 } else { | |
674 return new net::URLRequestTestJob( | |
675 request, network_delegate, | |
676 test_fixture_->response_headers_, test_fixture_->response_data_, | |
677 false); | |
678 } | |
679 } | |
680 } | |
681 | |
682 void SetDelayedStartJobGeneration(bool delay_job_start) { | |
683 delay_start_ = delay_job_start; | |
684 } | |
685 | |
686 void SetDelayedCompleteJobGeneration(bool delay_job_complete) { | |
687 delay_complete_ = delay_job_complete; | |
688 } | |
689 | |
690 void GenerateDataReceivedACK(const IPC::Message& msg) { | |
691 EXPECT_EQ(ResourceMsg_DataReceived::ID, msg.type()); | |
692 | |
693 int request_id = IPC::MessageIterator(msg).NextInt(); | |
694 scoped_ptr<IPC::Message> ack( | |
695 new ResourceHostMsg_DataReceived_ACK(msg.routing_id(), request_id)); | |
696 | |
697 MessageLoop::current()->PostTask( | |
698 FROM_HERE, | |
699 base::Bind(&GenerateIPCMessage, filter_, base::Passed(&ack))); | |
700 } | |
701 | |
702 MessageLoopForIO message_loop_; | |
703 BrowserThreadImpl ui_thread_; | |
704 BrowserThreadImpl file_thread_; | |
705 BrowserThreadImpl cache_thread_; | |
706 BrowserThreadImpl io_thread_; | |
707 scoped_ptr<TestBrowserContext> browser_context_; | |
708 scoped_refptr<ForwardingFilter> filter_; | |
709 ResourceDispatcherHostImpl host_; | |
710 ResourceIPCAccumulator accum_; | |
711 std::string response_headers_; | |
712 std::string response_data_; | |
713 std::string scheme_; | |
714 net::URLRequest::ProtocolFactory* old_factory_; | |
715 ResourceType::Type resource_type_; | |
716 bool send_data_received_acks_; | |
717 static ResourceDispatcherHostTest* test_fixture_; | |
718 static bool delay_start_; | |
719 static bool delay_complete_; | |
720 static int url_request_jobs_created_count_; | |
721 }; | |
722 // Static. | |
723 ResourceDispatcherHostTest* ResourceDispatcherHostTest::test_fixture_ = NULL; | |
724 bool ResourceDispatcherHostTest::delay_start_ = false; | |
725 bool ResourceDispatcherHostTest::delay_complete_ = false; | |
726 int ResourceDispatcherHostTest::url_request_jobs_created_count_ = 0; | |
727 | |
728 void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id, | |
729 int request_id, | |
730 const GURL& url) { | |
731 MakeTestRequest(filter_.get(), render_view_id, request_id, url); | |
732 } | |
733 | |
734 void ResourceDispatcherHostTest::MakeTestRequest( | |
735 ResourceMessageFilter* filter, | |
736 int render_view_id, | |
737 int request_id, | |
738 const GURL& url) { | |
739 ResourceHostMsg_Request request = | |
740 CreateResourceRequest("GET", resource_type_, url); | |
741 ResourceHostMsg_RequestResource msg(render_view_id, request_id, request); | |
742 bool msg_was_ok; | |
743 host_.OnMessageReceived(msg, filter, &msg_was_ok); | |
744 KickOffRequest(); | |
745 } | |
746 | |
747 void ResourceDispatcherHostTest::CancelRequest(int request_id) { | |
748 host_.CancelRequest(filter_->child_id(), request_id, false); | |
749 } | |
750 | |
751 void ResourceDispatcherHostTest::CompleteStartRequest(int request_id) { | |
752 CompleteStartRequest(filter_, request_id); | |
753 } | |
754 | |
755 void ResourceDispatcherHostTest::CompleteStartRequest( | |
756 ResourceMessageFilter* filter, | |
757 int request_id) { | |
758 GlobalRequestID gid(filter->child_id(), request_id); | |
759 net::URLRequest* req = host_.GetURLRequest(gid); | |
760 EXPECT_TRUE(req); | |
761 if (req) | |
762 URLRequestTestDelayedStartJob::CompleteStart(req); | |
763 } | |
764 | |
765 void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages, | |
766 const std::string& reference_data) { | |
767 // A successful request will have received 4 messages: | |
768 // ReceivedResponse (indicates headers received) | |
769 // SetDataBuffer (contains shared memory handle) | |
770 // DataReceived (data offset and length into shared memory) | |
771 // RequestComplete (request is done) | |
772 // | |
773 // This function verifies that we received 4 messages and that they | |
774 // are appropriate. | |
775 ASSERT_EQ(4U, messages.size()); | |
776 | |
777 // The first messages should be received response | |
778 ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, messages[0].type()); | |
779 | |
780 ASSERT_EQ(ResourceMsg_SetDataBuffer::ID, messages[1].type()); | |
781 | |
782 PickleIterator iter(messages[1]); | |
783 int request_id; | |
784 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &request_id)); | |
785 base::SharedMemoryHandle shm_handle; | |
786 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &shm_handle)); | |
787 int shm_size; | |
788 ASSERT_TRUE(IPC::ReadParam(&messages[1], &iter, &shm_size)); | |
789 | |
790 // Followed by the data, currently we only do the data in one chunk, but | |
791 // should probably test multiple chunks later | |
792 ASSERT_EQ(ResourceMsg_DataReceived::ID, messages[2].type()); | |
793 | |
794 PickleIterator iter2(messages[2]); | |
795 ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &request_id)); | |
796 int data_offset; | |
797 ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_offset)); | |
798 int data_length; | |
799 ASSERT_TRUE(IPC::ReadParam(&messages[2], &iter2, &data_length)); | |
800 | |
801 ASSERT_EQ(reference_data.size(), static_cast<size_t>(data_length)); | |
802 ASSERT_GE(shm_size, data_length); | |
803 | |
804 base::SharedMemory shared_mem(shm_handle, true); // read only | |
805 shared_mem.Map(data_length); | |
806 const char* data = static_cast<char*>(shared_mem.memory()) + data_offset; | |
807 ASSERT_EQ(0, memcmp(reference_data.c_str(), data, data_length)); | |
808 | |
809 // The last message should be all data received. | |
810 ASSERT_EQ(ResourceMsg_RequestComplete::ID, messages[3].type()); | |
811 } | |
812 | |
813 // Tests whether many messages get dispatched properly. | |
814 TEST_F(ResourceDispatcherHostTest, TestMany) { | |
815 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
816 | |
817 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
818 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
819 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
820 | |
821 // flush all the pending requests | |
822 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
823 | |
824 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
825 | |
826 // sorts out all the messages we saw by request | |
827 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
828 accum_.GetClassifiedMessages(&msgs); | |
829 | |
830 // there are three requests, so we should have gotten them classified as such | |
831 ASSERT_EQ(3U, msgs.size()); | |
832 | |
833 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
834 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_2()); | |
835 CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); | |
836 } | |
837 | |
838 void CheckCancelledRequestCompleteMessage(const IPC::Message& message) { | |
839 ASSERT_EQ(ResourceMsg_RequestComplete::ID, message.type()); | |
840 | |
841 int request_id; | |
842 int error_code; | |
843 | |
844 PickleIterator iter(message); | |
845 ASSERT_TRUE(IPC::ReadParam(&message, &iter, &request_id)); | |
846 ASSERT_TRUE(IPC::ReadParam(&message, &iter, &error_code)); | |
847 | |
848 EXPECT_EQ(net::ERR_ABORTED, error_code); | |
849 } | |
850 | |
851 // Tests whether messages get canceled properly. We issue three requests, | |
852 // cancel one of them, and make sure that each sent the proper notifications. | |
853 TEST_F(ResourceDispatcherHostTest, Cancel) { | |
854 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
855 | |
856 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
857 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
858 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
859 CancelRequest(2); | |
860 | |
861 // flush all the pending requests | |
862 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
863 MessageLoop::current()->RunUntilIdle(); | |
864 | |
865 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
866 | |
867 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
868 accum_.GetClassifiedMessages(&msgs); | |
869 | |
870 // there are three requests, so we should have gotten them classified as such | |
871 ASSERT_EQ(3U, msgs.size()); | |
872 | |
873 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
874 CheckSuccessfulRequest(msgs[2], net::URLRequestTestJob::test_data_3()); | |
875 | |
876 // Check that request 2 got canceled. | |
877 ASSERT_EQ(2U, msgs[1].size()); | |
878 ASSERT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[1][0].type()); | |
879 CheckCancelledRequestCompleteMessage(msgs[1][1]); | |
880 } | |
881 | |
882 TEST_F(ResourceDispatcherHostTest, CancelWhileStartIsDeferred) { | |
883 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
884 | |
885 bool was_deleted = false; | |
886 | |
887 // Arrange to have requests deferred before starting. | |
888 TestResourceDispatcherHostDelegate delegate; | |
889 delegate.set_flags(DEFER_STARTING_REQUEST); | |
890 delegate.set_url_request_user_data(new TestUserData(&was_deleted)); | |
891 host_.SetDelegate(&delegate); | |
892 | |
893 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
894 CancelRequest(1); | |
895 | |
896 // Our TestResourceThrottle should not have been deleted yet. This is to | |
897 // ensure that destruction of the URLRequest happens asynchronously to | |
898 // calling CancelRequest. | |
899 EXPECT_FALSE(was_deleted); | |
900 | |
901 // flush all the pending requests | |
902 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
903 MessageLoop::current()->RunUntilIdle(); | |
904 | |
905 EXPECT_TRUE(was_deleted); | |
906 | |
907 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
908 } | |
909 | |
910 // Tests if cancel is called in ResourceThrottle::WillStartRequest, then the | |
911 // URLRequest will not be started. | |
912 TEST_F(ResourceDispatcherHostTest, CancelInResourceThrottleWillStartRequest) { | |
913 TestResourceDispatcherHostDelegate delegate; | |
914 delegate.set_flags(CANCEL_BEFORE_START); | |
915 host_.SetDelegate(&delegate); | |
916 | |
917 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
918 | |
919 // flush all the pending requests | |
920 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
921 MessageLoop::current()->RunUntilIdle(); | |
922 | |
923 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
924 accum_.GetClassifiedMessages(&msgs); | |
925 | |
926 // Check that request got canceled. | |
927 ASSERT_EQ(1U, msgs[0].size()); | |
928 CheckCancelledRequestCompleteMessage(msgs[0][0]); | |
929 | |
930 // Make sure URLRequest is never started. | |
931 EXPECT_EQ(0, url_request_jobs_created_count_); | |
932 } | |
933 | |
934 TEST_F(ResourceDispatcherHostTest, PausedStartError) { | |
935 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
936 | |
937 // Arrange to have requests deferred before processing response headers. | |
938 TestResourceDispatcherHostDelegate delegate; | |
939 delegate.set_flags(DEFER_PROCESSING_RESPONSE); | |
940 host_.SetDelegate(&delegate); | |
941 | |
942 SetDelayedStartJobGeneration(true); | |
943 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_error()); | |
944 CompleteStartRequest(1); | |
945 | |
946 // flush all the pending requests | |
947 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
948 MessageLoop::current()->RunUntilIdle(); | |
949 | |
950 EXPECT_EQ(0, host_.pending_requests()); | |
951 } | |
952 | |
953 TEST_F(ResourceDispatcherHostTest, ThrottleAndResumeTwice) { | |
954 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
955 | |
956 // Arrange to have requests deferred before starting. | |
957 TestResourceDispatcherHostDelegate delegate; | |
958 delegate.set_flags(DEFER_STARTING_REQUEST); | |
959 delegate.set_create_two_throttles(true); | |
960 host_.SetDelegate(&delegate); | |
961 | |
962 // Make sure the first throttle blocked the request, and then resume. | |
963 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
964 GenericResourceThrottle* first_throttle = | |
965 GenericResourceThrottle::active_throttle(); | |
966 ASSERT_TRUE(first_throttle); | |
967 first_throttle->Resume(); | |
968 | |
969 // Make sure the second throttle blocked the request, and then resume. | |
970 ASSERT_TRUE(GenericResourceThrottle::active_throttle()); | |
971 ASSERT_NE(first_throttle, GenericResourceThrottle::active_throttle()); | |
972 GenericResourceThrottle::active_throttle()->Resume(); | |
973 | |
974 ASSERT_FALSE(GenericResourceThrottle::active_throttle()); | |
975 | |
976 // The request is started asynchronously. | |
977 MessageLoop::current()->RunUntilIdle(); | |
978 | |
979 // Flush all the pending requests. | |
980 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
981 | |
982 EXPECT_EQ(0, host_.pending_requests()); | |
983 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
984 | |
985 // Make sure the request completed successfully. | |
986 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
987 accum_.GetClassifiedMessages(&msgs); | |
988 ASSERT_EQ(1U, msgs.size()); | |
989 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
990 } | |
991 | |
992 | |
993 // Tests that the delegate can cancel a request and provide a error code. | |
994 TEST_F(ResourceDispatcherHostTest, CancelInDelegate) { | |
995 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
996 | |
997 TestResourceDispatcherHostDelegate delegate; | |
998 delegate.set_flags(CANCEL_BEFORE_START); | |
999 delegate.set_error_code_for_cancellation(net::ERR_ACCESS_DENIED); | |
1000 host_.SetDelegate(&delegate); | |
1001 | |
1002 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
1003 // The request will get cancelled by the throttle. | |
1004 | |
1005 // flush all the pending requests | |
1006 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1007 MessageLoop::current()->RunUntilIdle(); | |
1008 | |
1009 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1010 | |
1011 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1012 accum_.GetClassifiedMessages(&msgs); | |
1013 | |
1014 // Check the cancellation | |
1015 ASSERT_EQ(1U, msgs.size()); | |
1016 ASSERT_EQ(1U, msgs[0].size()); | |
1017 ASSERT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][0].type()); | |
1018 | |
1019 int request_id; | |
1020 int error_code; | |
1021 | |
1022 PickleIterator iter(msgs[0][0]); | |
1023 ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); | |
1024 ASSERT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); | |
1025 | |
1026 EXPECT_EQ(net::ERR_ACCESS_DENIED, error_code); | |
1027 } | |
1028 | |
1029 // The host delegate acts as a second one so we can have some requests | |
1030 // pending and some canceled. | |
1031 class TestFilter : public ForwardingFilter { | |
1032 public: | |
1033 explicit TestFilter(ResourceContext* resource_context) | |
1034 : ForwardingFilter(NULL, resource_context), | |
1035 has_canceled_(false), | |
1036 received_after_canceled_(0) { | |
1037 } | |
1038 | |
1039 // ForwardingFilter override | |
1040 virtual bool Send(IPC::Message* msg) OVERRIDE { | |
1041 // no messages should be received when the process has been canceled | |
1042 if (has_canceled_) | |
1043 received_after_canceled_++; | |
1044 delete msg; | |
1045 return true; | |
1046 } | |
1047 | |
1048 bool has_canceled_; | |
1049 int received_after_canceled_; | |
1050 | |
1051 private: | |
1052 virtual ~TestFilter() {} | |
1053 }; | |
1054 | |
1055 // Tests CancelRequestsForProcess | |
1056 TEST_F(ResourceDispatcherHostTest, TestProcessCancel) { | |
1057 scoped_refptr<TestFilter> test_filter = new TestFilter( | |
1058 browser_context_->GetResourceContext()); | |
1059 | |
1060 // request 1 goes to the test delegate | |
1061 ResourceHostMsg_Request request = CreateResourceRequest( | |
1062 "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1()); | |
1063 | |
1064 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1065 | |
1066 MakeTestRequest(test_filter.get(), 0, 1, | |
1067 net::URLRequestTestJob::test_url_1()); | |
1068 | |
1069 // request 2 goes to us | |
1070 MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2()); | |
1071 | |
1072 // request 3 goes to the test delegate | |
1073 MakeTestRequest(test_filter.get(), 0, 3, | |
1074 net::URLRequestTestJob::test_url_3()); | |
1075 | |
1076 // Make sure all requests have finished stage one. test_url_1 will have | |
1077 // finished. | |
1078 MessageLoop::current()->RunUntilIdle(); | |
1079 | |
1080 // TODO(mbelshe): | |
1081 // Now that the async IO path is in place, the IO always completes on the | |
1082 // initial call; so the requests have already completed. This basically | |
1083 // breaks the whole test. | |
1084 //EXPECT_EQ(3, host_.pending_requests()); | |
1085 | |
1086 // Process each request for one level so one callback is called. | |
1087 for (int i = 0; i < 2; i++) | |
1088 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); | |
1089 | |
1090 // Cancel the requests to the test process. | |
1091 host_.CancelRequestsForProcess(filter_->child_id()); | |
1092 test_filter->has_canceled_ = true; | |
1093 | |
1094 // Flush all the pending requests. | |
1095 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1096 | |
1097 EXPECT_EQ(0, host_.pending_requests()); | |
1098 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1099 | |
1100 // The test delegate should not have gotten any messages after being canceled. | |
1101 ASSERT_EQ(0, test_filter->received_after_canceled_); | |
1102 | |
1103 // We should have gotten exactly one result. | |
1104 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1105 accum_.GetClassifiedMessages(&msgs); | |
1106 ASSERT_EQ(1U, msgs.size()); | |
1107 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
1108 } | |
1109 | |
1110 // Tests blocking and resuming requests. | |
1111 TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) { | |
1112 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1113 | |
1114 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
1115 host_.BlockRequestsForRoute(filter_->child_id(), 2); | |
1116 host_.BlockRequestsForRoute(filter_->child_id(), 3); | |
1117 | |
1118 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
1119 MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2()); | |
1120 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
1121 MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1()); | |
1122 MakeTestRequest(2, 5, net::URLRequestTestJob::test_url_2()); | |
1123 MakeTestRequest(3, 6, net::URLRequestTestJob::test_url_3()); | |
1124 | |
1125 // Flush all the pending requests | |
1126 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1127 | |
1128 // Sort out all the messages we saw by request | |
1129 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1130 accum_.GetClassifiedMessages(&msgs); | |
1131 | |
1132 // All requests but the 2 for the RVH 0 should have been blocked. | |
1133 ASSERT_EQ(2U, msgs.size()); | |
1134 | |
1135 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
1136 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
1137 | |
1138 // Resume requests for RVH 1 and flush pending requests. | |
1139 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 1); | |
1140 KickOffRequest(); | |
1141 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1142 | |
1143 msgs.clear(); | |
1144 accum_.GetClassifiedMessages(&msgs); | |
1145 ASSERT_EQ(2U, msgs.size()); | |
1146 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
1147 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_1()); | |
1148 | |
1149 // Test that new requests are not blocked for RVH 1. | |
1150 MakeTestRequest(1, 7, net::URLRequestTestJob::test_url_1()); | |
1151 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1152 msgs.clear(); | |
1153 accum_.GetClassifiedMessages(&msgs); | |
1154 ASSERT_EQ(1U, msgs.size()); | |
1155 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
1156 | |
1157 // Now resumes requests for all RVH (2 and 3). | |
1158 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 2); | |
1159 host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 3); | |
1160 KickOffRequest(); | |
1161 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1162 | |
1163 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1164 | |
1165 msgs.clear(); | |
1166 accum_.GetClassifiedMessages(&msgs); | |
1167 ASSERT_EQ(2U, msgs.size()); | |
1168 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_2()); | |
1169 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
1170 } | |
1171 | |
1172 // Tests blocking and canceling requests. | |
1173 TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) { | |
1174 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1175 | |
1176 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
1177 | |
1178 MakeTestRequest(0, 1, net::URLRequestTestJob::test_url_1()); | |
1179 MakeTestRequest(1, 2, net::URLRequestTestJob::test_url_2()); | |
1180 MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3()); | |
1181 MakeTestRequest(1, 4, net::URLRequestTestJob::test_url_1()); | |
1182 | |
1183 // Flush all the pending requests. | |
1184 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1185 | |
1186 // Sort out all the messages we saw by request. | |
1187 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1188 accum_.GetClassifiedMessages(&msgs); | |
1189 | |
1190 // The 2 requests for the RVH 0 should have been processed. | |
1191 ASSERT_EQ(2U, msgs.size()); | |
1192 | |
1193 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
1194 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
1195 | |
1196 // Cancel requests for RVH 1. | |
1197 host_.CancelBlockedRequestsForRoute(filter_->child_id(), 1); | |
1198 KickOffRequest(); | |
1199 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1200 | |
1201 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1202 | |
1203 msgs.clear(); | |
1204 accum_.GetClassifiedMessages(&msgs); | |
1205 ASSERT_EQ(0U, msgs.size()); | |
1206 } | |
1207 | |
1208 // Tests that blocked requests are canceled if their associated process dies. | |
1209 TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) { | |
1210 // This second filter is used to emulate a second process. | |
1211 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( | |
1212 this, browser_context_->GetResourceContext()); | |
1213 | |
1214 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1215 EXPECT_EQ(0, | |
1216 host_.GetOutstandingRequestsMemoryCost(second_filter->child_id())); | |
1217 | |
1218 host_.BlockRequestsForRoute(second_filter->child_id(), 0); | |
1219 | |
1220 MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); | |
1221 MakeTestRequest(second_filter.get(), 0, 2, | |
1222 net::URLRequestTestJob::test_url_2()); | |
1223 MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); | |
1224 MakeTestRequest(second_filter.get(), 0, 4, | |
1225 net::URLRequestTestJob::test_url_1()); | |
1226 | |
1227 // Simulate process death. | |
1228 host_.CancelRequestsForProcess(second_filter->child_id()); | |
1229 | |
1230 // Flush all the pending requests. | |
1231 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1232 | |
1233 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1234 EXPECT_EQ(0, | |
1235 host_.GetOutstandingRequestsMemoryCost(second_filter->child_id())); | |
1236 | |
1237 // Sort out all the messages we saw by request. | |
1238 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1239 accum_.GetClassifiedMessages(&msgs); | |
1240 | |
1241 // The 2 requests for the RVH 0 should have been processed. | |
1242 ASSERT_EQ(2U, msgs.size()); | |
1243 | |
1244 CheckSuccessfulRequest(msgs[0], net::URLRequestTestJob::test_data_1()); | |
1245 CheckSuccessfulRequest(msgs[1], net::URLRequestTestJob::test_data_3()); | |
1246 | |
1247 EXPECT_TRUE(host_.blocked_loaders_map_.empty()); | |
1248 } | |
1249 | |
1250 // Tests that blocked requests don't leak when the ResourceDispatcherHost goes | |
1251 // away. Note that we rely on Purify for finding the leaks if any. | |
1252 // If this test turns the Purify bot red, check the ResourceDispatcherHost | |
1253 // destructor to make sure the blocked requests are deleted. | |
1254 TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) { | |
1255 // This second filter is used to emulate a second process. | |
1256 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( | |
1257 this, browser_context_->GetResourceContext()); | |
1258 | |
1259 host_.BlockRequestsForRoute(filter_->child_id(), 1); | |
1260 host_.BlockRequestsForRoute(filter_->child_id(), 2); | |
1261 host_.BlockRequestsForRoute(second_filter->child_id(), 1); | |
1262 | |
1263 MakeTestRequest(filter_.get(), 0, 1, net::URLRequestTestJob::test_url_1()); | |
1264 MakeTestRequest(filter_.get(), 1, 2, net::URLRequestTestJob::test_url_2()); | |
1265 MakeTestRequest(filter_.get(), 0, 3, net::URLRequestTestJob::test_url_3()); | |
1266 MakeTestRequest(second_filter.get(), 1, 4, | |
1267 net::URLRequestTestJob::test_url_1()); | |
1268 MakeTestRequest(filter_.get(), 2, 5, net::URLRequestTestJob::test_url_2()); | |
1269 MakeTestRequest(filter_.get(), 2, 6, net::URLRequestTestJob::test_url_3()); | |
1270 | |
1271 host_.CancelRequestsForProcess(filter_->child_id()); | |
1272 host_.CancelRequestsForProcess(second_filter->child_id()); | |
1273 | |
1274 // Flush all the pending requests. | |
1275 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1276 } | |
1277 | |
1278 // Test the private helper method "CalculateApproximateMemoryCost()". | |
1279 TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) { | |
1280 net::URLRequestContext context; | |
1281 net::URLRequest req(GURL("http://www.google.com"), NULL, &context); | |
1282 EXPECT_EQ(4427, | |
1283 ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req)); | |
1284 | |
1285 // Add 9 bytes of referrer. | |
1286 req.set_referrer("123456789"); | |
1287 EXPECT_EQ(4436, | |
1288 ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req)); | |
1289 | |
1290 // Add 33 bytes of upload content. | |
1291 std::string upload_content; | |
1292 upload_content.resize(33); | |
1293 std::fill(upload_content.begin(), upload_content.end(), 'x'); | |
1294 scoped_refptr<net::UploadData> upload_data(new net::UploadData()); | |
1295 upload_data->AppendBytes(upload_content.data(), upload_content.size()); | |
1296 req.set_upload(upload_data); | |
1297 | |
1298 // Since the upload throttling is disabled, this has no effect on the cost. | |
1299 EXPECT_EQ(4436, | |
1300 ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req)); | |
1301 } | |
1302 | |
1303 // Test the private helper method "IncrementOutstandingRequestsMemoryCost()". | |
1304 TEST_F(ResourceDispatcherHostTest, IncrementOutstandingRequestsMemoryCost) { | |
1305 // Add some counts for render_process_host=7 | |
1306 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(7)); | |
1307 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
1308 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
1309 EXPECT_EQ(3, host_.IncrementOutstandingRequestsMemoryCost(1, 7)); | |
1310 | |
1311 // Add some counts for render_process_host=3 | |
1312 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(3)); | |
1313 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(1, 3)); | |
1314 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(1, 3)); | |
1315 | |
1316 // Remove all the counts for render_process_host=7 | |
1317 EXPECT_EQ(3, host_.GetOutstandingRequestsMemoryCost(7)); | |
1318 EXPECT_EQ(2, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
1319 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
1320 EXPECT_EQ(0, host_.IncrementOutstandingRequestsMemoryCost(-1, 7)); | |
1321 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(7)); | |
1322 | |
1323 // Remove all the counts for render_process_host=3 | |
1324 EXPECT_EQ(2, host_.GetOutstandingRequestsMemoryCost(3)); | |
1325 EXPECT_EQ(1, host_.IncrementOutstandingRequestsMemoryCost(-1, 3)); | |
1326 EXPECT_EQ(0, host_.IncrementOutstandingRequestsMemoryCost(-1, 3)); | |
1327 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(3)); | |
1328 | |
1329 // When an entry reaches 0, it should be deleted. | |
1330 EXPECT_TRUE(host_.outstanding_requests_memory_cost_map_.end() == | |
1331 host_.outstanding_requests_memory_cost_map_.find(7)); | |
1332 EXPECT_TRUE(host_.outstanding_requests_memory_cost_map_.end() == | |
1333 host_.outstanding_requests_memory_cost_map_.find(3)); | |
1334 } | |
1335 | |
1336 // Test that when too many requests are outstanding for a particular | |
1337 // render_process_host_id, any subsequent request from it fails. | |
1338 TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) { | |
1339 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1340 | |
1341 // Expected cost of each request as measured by | |
1342 // ResourceDispatcherHost::CalculateApproximateMemoryCost(). | |
1343 int kMemoryCostOfTest2Req = | |
1344 ResourceDispatcherHostImpl::kAvgBytesPerOutstandingRequest + | |
1345 std::string("GET").size() + | |
1346 net::URLRequestTestJob::test_url_2().spec().size(); | |
1347 | |
1348 // Tighten the bound on the ResourceDispatcherHost, to speed things up. | |
1349 int kMaxCostPerProcess = 440000; | |
1350 host_.set_max_outstanding_requests_cost_per_process(kMaxCostPerProcess); | |
1351 | |
1352 // Determine how many instance of test_url_2() we can request before | |
1353 // throttling kicks in. | |
1354 size_t kMaxRequests = kMaxCostPerProcess / kMemoryCostOfTest2Req; | |
1355 | |
1356 // This second filter is used to emulate a second process. | |
1357 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( | |
1358 this, browser_context_->GetResourceContext()); | |
1359 | |
1360 // Saturate the number of outstanding requests for our process. | |
1361 for (size_t i = 0; i < kMaxRequests; ++i) { | |
1362 MakeTestRequest(filter_.get(), 0, i + 1, | |
1363 net::URLRequestTestJob::test_url_2()); | |
1364 } | |
1365 | |
1366 // Issue two more requests for our process -- these should fail immediately. | |
1367 MakeTestRequest(filter_.get(), 0, kMaxRequests + 1, | |
1368 net::URLRequestTestJob::test_url_2()); | |
1369 MakeTestRequest(filter_.get(), 0, kMaxRequests + 2, | |
1370 net::URLRequestTestJob::test_url_2()); | |
1371 | |
1372 // Issue two requests for the second process -- these should succeed since | |
1373 // it is just process 0 that is saturated. | |
1374 MakeTestRequest(second_filter.get(), 0, kMaxRequests + 3, | |
1375 net::URLRequestTestJob::test_url_2()); | |
1376 MakeTestRequest(second_filter.get(), 0, kMaxRequests + 4, | |
1377 net::URLRequestTestJob::test_url_2()); | |
1378 | |
1379 // Flush all the pending requests. | |
1380 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1381 MessageLoop::current()->RunUntilIdle(); | |
1382 | |
1383 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id())); | |
1384 | |
1385 // Sorts out all the messages we saw by request. | |
1386 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1387 accum_.GetClassifiedMessages(&msgs); | |
1388 | |
1389 // We issued (kMaxRequests + 4) total requests. | |
1390 ASSERT_EQ(kMaxRequests + 4, msgs.size()); | |
1391 | |
1392 // Check that the first kMaxRequests succeeded. | |
1393 for (size_t i = 0; i < kMaxRequests; ++i) | |
1394 CheckSuccessfulRequest(msgs[i], net::URLRequestTestJob::test_data_2()); | |
1395 | |
1396 // Check that the subsequent two requests (kMaxRequests + 1) and | |
1397 // (kMaxRequests + 2) were failed, since the per-process bound was reached. | |
1398 for (int i = 0; i < 2; ++i) { | |
1399 // Should have sent a single RequestComplete message. | |
1400 int index = kMaxRequests + i; | |
1401 EXPECT_EQ(1U, msgs[index].size()); | |
1402 EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[index][0].type()); | |
1403 | |
1404 // The RequestComplete message should have the error code of | |
1405 // ERR_INSUFFICIENT_RESOURCES. | |
1406 int request_id; | |
1407 int error_code; | |
1408 | |
1409 PickleIterator iter(msgs[index][0]); | |
1410 EXPECT_TRUE(IPC::ReadParam(&msgs[index][0], &iter, &request_id)); | |
1411 EXPECT_TRUE(IPC::ReadParam(&msgs[index][0], &iter, &error_code)); | |
1412 | |
1413 EXPECT_EQ(index + 1, request_id); | |
1414 EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES, error_code); | |
1415 } | |
1416 | |
1417 // The final 2 requests should have succeeded. | |
1418 CheckSuccessfulRequest(msgs[kMaxRequests + 2], | |
1419 net::URLRequestTestJob::test_data_2()); | |
1420 CheckSuccessfulRequest(msgs[kMaxRequests + 3], | |
1421 net::URLRequestTestJob::test_data_2()); | |
1422 } | |
1423 | |
1424 // Tests that we sniff the mime type for a simple request. | |
1425 TEST_F(ResourceDispatcherHostTest, MimeSniffed) { | |
1426 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1427 | |
1428 std::string raw_headers("HTTP/1.1 200 OK\n\n"); | |
1429 std::string response_data("<html><title>Test One</title></html>"); | |
1430 SetResponse(raw_headers, response_data); | |
1431 | |
1432 HandleScheme("http"); | |
1433 MakeTestRequest(0, 1, GURL("http:bla")); | |
1434 | |
1435 // Flush all pending requests. | |
1436 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1437 | |
1438 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1439 | |
1440 // Sorts out all the messages we saw by request. | |
1441 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1442 accum_.GetClassifiedMessages(&msgs); | |
1443 ASSERT_EQ(1U, msgs.size()); | |
1444 | |
1445 ResourceResponseHead response_head; | |
1446 GetResponseHead(msgs[0], &response_head); | |
1447 ASSERT_EQ("text/html", response_head.mime_type); | |
1448 } | |
1449 | |
1450 // Tests that we don't sniff the mime type when the server provides one. | |
1451 TEST_F(ResourceDispatcherHostTest, MimeNotSniffed) { | |
1452 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1453 | |
1454 std::string raw_headers("HTTP/1.1 200 OK\n" | |
1455 "Content-type: image/jpeg\n\n"); | |
1456 std::string response_data("<html><title>Test One</title></html>"); | |
1457 SetResponse(raw_headers, response_data); | |
1458 | |
1459 HandleScheme("http"); | |
1460 MakeTestRequest(0, 1, GURL("http:bla")); | |
1461 | |
1462 // Flush all pending requests. | |
1463 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1464 | |
1465 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1466 | |
1467 // Sorts out all the messages we saw by request. | |
1468 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1469 accum_.GetClassifiedMessages(&msgs); | |
1470 ASSERT_EQ(1U, msgs.size()); | |
1471 | |
1472 ResourceResponseHead response_head; | |
1473 GetResponseHead(msgs[0], &response_head); | |
1474 ASSERT_EQ("image/jpeg", response_head.mime_type); | |
1475 } | |
1476 | |
1477 // Tests that we don't sniff the mime type when there is no message body. | |
1478 TEST_F(ResourceDispatcherHostTest, MimeNotSniffed2) { | |
1479 | |
1480 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1481 | |
1482 SetResponse("HTTP/1.1 304 Not Modified\n\n"); | |
1483 | |
1484 HandleScheme("http"); | |
1485 MakeTestRequest(0, 1, GURL("http:bla")); | |
1486 | |
1487 // Flush all pending requests. | |
1488 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1489 | |
1490 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1491 | |
1492 // Sorts out all the messages we saw by request. | |
1493 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1494 accum_.GetClassifiedMessages(&msgs); | |
1495 ASSERT_EQ(1U, msgs.size()); | |
1496 | |
1497 ResourceResponseHead response_head; | |
1498 GetResponseHead(msgs[0], &response_head); | |
1499 ASSERT_EQ("", response_head.mime_type); | |
1500 } | |
1501 | |
1502 TEST_F(ResourceDispatcherHostTest, MimeSniff204) { | |
1503 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1504 | |
1505 SetResponse("HTTP/1.1 204 No Content\n\n"); | |
1506 | |
1507 HandleScheme("http"); | |
1508 MakeTestRequest(0, 1, GURL("http:bla")); | |
1509 | |
1510 // Flush all pending requests. | |
1511 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1512 | |
1513 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1514 | |
1515 // Sorts out all the messages we saw by request. | |
1516 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1517 accum_.GetClassifiedMessages(&msgs); | |
1518 ASSERT_EQ(1U, msgs.size()); | |
1519 | |
1520 ResourceResponseHead response_head; | |
1521 GetResponseHead(msgs[0], &response_head); | |
1522 ASSERT_EQ("text/plain", response_head.mime_type); | |
1523 } | |
1524 | |
1525 TEST_F(ResourceDispatcherHostTest, MimeSniffEmpty) { | |
1526 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1527 | |
1528 SetResponse("HTTP/1.1 200 OK\n\n"); | |
1529 | |
1530 HandleScheme("http"); | |
1531 MakeTestRequest(0, 1, GURL("http:bla")); | |
1532 | |
1533 // Flush all pending requests. | |
1534 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1535 | |
1536 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1537 | |
1538 // Sorts out all the messages we saw by request. | |
1539 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1540 accum_.GetClassifiedMessages(&msgs); | |
1541 ASSERT_EQ(1U, msgs.size()); | |
1542 | |
1543 ResourceResponseHead response_head; | |
1544 GetResponseHead(msgs[0], &response_head); | |
1545 ASSERT_EQ("text/plain", response_head.mime_type); | |
1546 } | |
1547 | |
1548 // Tests for crbug.com/31266 (Non-2xx + application/octet-stream). | |
1549 TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) { | |
1550 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1551 | |
1552 std::string raw_headers("HTTP/1.1 403 Forbidden\n" | |
1553 "Content-disposition: attachment; filename=blah\n" | |
1554 "Content-type: application/octet-stream\n\n"); | |
1555 std::string response_data("<html><title>Test One</title></html>"); | |
1556 SetResponse(raw_headers, response_data); | |
1557 | |
1558 // Only MAIN_FRAMEs can trigger a download. | |
1559 SetResourceType(ResourceType::MAIN_FRAME); | |
1560 | |
1561 HandleScheme("http"); | |
1562 MakeTestRequest(0, 1, GURL("http:bla")); | |
1563 | |
1564 // Flush all pending requests. | |
1565 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1566 | |
1567 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1568 | |
1569 // Sorts out all the messages we saw by request. | |
1570 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1571 accum_.GetClassifiedMessages(&msgs); | |
1572 | |
1573 // We should have gotten one RequestComplete message. | |
1574 ASSERT_EQ(1U, msgs[0].size()); | |
1575 EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][0].type()); | |
1576 | |
1577 // The RequestComplete message should have had the error code of | |
1578 // ERR_FILE_NOT_FOUND. | |
1579 int request_id; | |
1580 int error_code; | |
1581 | |
1582 PickleIterator iter(msgs[0][0]); | |
1583 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); | |
1584 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); | |
1585 | |
1586 EXPECT_EQ(1, request_id); | |
1587 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, error_code); | |
1588 } | |
1589 | |
1590 // Test for http://crbug.com/76202 . We don't want to destroy a | |
1591 // download request prematurely when processing a cancellation from | |
1592 // the renderer. | |
1593 TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) { | |
1594 EXPECT_EQ(0, host_.pending_requests()); | |
1595 | |
1596 int render_view_id = 0; | |
1597 int request_id = 1; | |
1598 | |
1599 std::string raw_headers("HTTP\n" | |
1600 "Content-disposition: attachment; filename=foo\n\n"); | |
1601 std::string response_data("01234567890123456789\x01foobar"); | |
1602 | |
1603 // Get past sniffing metrics in the BufferedResourceHandler. Note that | |
1604 // if we don't get past the sniffing metrics, the result will be that | |
1605 // the BufferedResourceHandler won't have figured out that it's a download, | |
1606 // won't have constructed a DownloadResourceHandler, and and the request | |
1607 // will be successfully canceled below, failing the test. | |
1608 response_data.resize(1025, ' '); | |
1609 | |
1610 SetResponse(raw_headers, response_data); | |
1611 SetResourceType(ResourceType::MAIN_FRAME); | |
1612 SetDelayedCompleteJobGeneration(true); | |
1613 HandleScheme("http"); | |
1614 | |
1615 MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); | |
1616 // Return some data so that the request is identified as a download | |
1617 // and the proper resource handlers are created. | |
1618 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); | |
1619 | |
1620 // And now simulate a cancellation coming from the renderer. | |
1621 ResourceHostMsg_CancelRequest msg(filter_->child_id(), request_id); | |
1622 bool msg_was_ok; | |
1623 host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok); | |
1624 | |
1625 // Since the request had already started processing as a download, | |
1626 // the cancellation above should have been ignored and the request | |
1627 // should still be alive. | |
1628 EXPECT_EQ(1, host_.pending_requests()); | |
1629 | |
1630 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1631 EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0)); | |
1632 } | |
1633 | |
1634 TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) { | |
1635 EXPECT_EQ(0, host_.pending_requests()); | |
1636 | |
1637 int render_view_id = 0; | |
1638 int request_id = 1; | |
1639 | |
1640 std::string raw_headers("HTTP\n" | |
1641 "Content-disposition: attachment; filename=foo\n\n"); | |
1642 std::string response_data("01234567890123456789\x01foobar"); | |
1643 // Get past sniffing metrics. | |
1644 response_data.resize(1025, ' '); | |
1645 | |
1646 SetResponse(raw_headers, response_data); | |
1647 SetResourceType(ResourceType::MAIN_FRAME); | |
1648 SetDelayedCompleteJobGeneration(true); | |
1649 HandleScheme("http"); | |
1650 | |
1651 MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); | |
1652 // Return some data so that the request is identified as a download | |
1653 // and the proper resource handlers are created. | |
1654 EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage()); | |
1655 | |
1656 // And now simulate a cancellation coming from the renderer. | |
1657 ResourceHostMsg_CancelRequest msg(filter_->child_id(), request_id); | |
1658 bool msg_was_ok; | |
1659 host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok); | |
1660 | |
1661 // Since the request had already started processing as a download, | |
1662 // the cancellation above should have been ignored and the request | |
1663 // should still be alive. | |
1664 EXPECT_EQ(1, host_.pending_requests()); | |
1665 | |
1666 // Cancelling by other methods shouldn't work either. | |
1667 host_.CancelRequestsForProcess(render_view_id); | |
1668 EXPECT_EQ(1, host_.pending_requests()); | |
1669 | |
1670 // Cancelling by context should work. | |
1671 host_.CancelRequestsForContext(filter_->resource_context()); | |
1672 EXPECT_EQ(0, host_.pending_requests()); | |
1673 } | |
1674 | |
1675 // Test the cancelling of requests that are being transferred to a new renderer | |
1676 // due to a redirection. | |
1677 TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) { | |
1678 EXPECT_EQ(0, host_.pending_requests()); | |
1679 | |
1680 int render_view_id = 0; | |
1681 int request_id = 1; | |
1682 | |
1683 std::string raw_headers("HTTP/1.1 200 OK\n" | |
1684 "Content-Type: text/html; charset=utf-8\n\n"); | |
1685 std::string response_data("<html>foobar</html>"); | |
1686 | |
1687 SetResponse(raw_headers, response_data); | |
1688 SetResourceType(ResourceType::MAIN_FRAME); | |
1689 HandleScheme("http"); | |
1690 | |
1691 MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); | |
1692 | |
1693 GlobalRequestID global_request_id(filter_->child_id(), request_id); | |
1694 host_.MarkAsTransferredNavigation(global_request_id); | |
1695 | |
1696 // And now simulate a cancellation coming from the renderer. | |
1697 ResourceHostMsg_CancelRequest msg(filter_->child_id(), request_id); | |
1698 bool msg_was_ok; | |
1699 host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok); | |
1700 | |
1701 // Since the request is marked as being transferred, | |
1702 // the cancellation above should have been ignored and the request | |
1703 // should still be alive. | |
1704 EXPECT_EQ(1, host_.pending_requests()); | |
1705 | |
1706 // Cancelling by other methods shouldn't work either. | |
1707 host_.CancelRequestsForProcess(render_view_id); | |
1708 EXPECT_EQ(1, host_.pending_requests()); | |
1709 | |
1710 // Cancelling by context should work. | |
1711 host_.CancelRequestsForContext(filter_->resource_context()); | |
1712 EXPECT_EQ(0, host_.pending_requests()); | |
1713 } | |
1714 | |
1715 TEST_F(ResourceDispatcherHostTest, TransferNavigation) { | |
1716 EXPECT_EQ(0, host_.pending_requests()); | |
1717 | |
1718 int render_view_id = 0; | |
1719 int request_id = 1; | |
1720 | |
1721 // Configure initial request. | |
1722 SetResponse("HTTP/1.1 302 Found\n" | |
1723 "Location: http://other.com/blech\n\n"); | |
1724 | |
1725 SetResourceType(ResourceType::MAIN_FRAME); | |
1726 HandleScheme("http"); | |
1727 | |
1728 // Temporarily replace ContentBrowserClient with one that will trigger the | |
1729 // transfer navigation code paths. | |
1730 ContentBrowserClient* old_client = GetContentClient()->browser(); | |
1731 TransfersAllNavigationsContentBrowserClient new_client; | |
1732 GetContentClient()->set_browser_for_testing(&new_client); | |
1733 | |
1734 MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); | |
1735 | |
1736 // Restore. | |
1737 GetContentClient()->set_browser_for_testing(old_client); | |
1738 | |
1739 // This second filter is used to emulate a second process. | |
1740 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( | |
1741 this, browser_context_->GetResourceContext()); | |
1742 | |
1743 int new_render_view_id = 1; | |
1744 int new_request_id = 2; | |
1745 | |
1746 const std::string kResponseBody = "hello world"; | |
1747 SetResponse("HTTP/1.1 200 OK\n" | |
1748 "Content-Type: text/plain\n\n", | |
1749 kResponseBody); | |
1750 | |
1751 ResourceHostMsg_Request request = | |
1752 CreateResourceRequest("GET", ResourceType::MAIN_FRAME, | |
1753 GURL("http://other.com/blech")); | |
1754 request.transferred_request_child_id = filter_->child_id(); | |
1755 request.transferred_request_request_id = request_id; | |
1756 | |
1757 ResourceHostMsg_RequestResource transfer_request_msg( | |
1758 new_render_view_id, new_request_id, request); | |
1759 bool msg_was_ok; | |
1760 host_.OnMessageReceived(transfer_request_msg, second_filter, &msg_was_ok); | |
1761 MessageLoop::current()->RunUntilIdle(); | |
1762 | |
1763 // Flush all the pending requests. | |
1764 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1765 | |
1766 // Check generated messages. | |
1767 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1768 accum_.GetClassifiedMessages(&msgs); | |
1769 | |
1770 ASSERT_EQ(1U, msgs.size()); | |
1771 CheckSuccessfulRequest(msgs[0], kResponseBody); | |
1772 } | |
1773 | |
1774 TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { | |
1775 EXPECT_EQ(0, host_.pending_requests()); | |
1776 | |
1777 int render_view_id = 0; | |
1778 int request_id = 1; | |
1779 | |
1780 // Configure initial request. | |
1781 SetResponse("HTTP/1.1 302 Found\n" | |
1782 "Location: http://other.com/blech\n\n"); | |
1783 | |
1784 SetResourceType(ResourceType::MAIN_FRAME); | |
1785 HandleScheme("http"); | |
1786 | |
1787 // Temporarily replace ContentBrowserClient with one that will trigger the | |
1788 // transfer navigation code paths. | |
1789 ContentBrowserClient* old_client = GetContentClient()->browser(); | |
1790 TransfersAllNavigationsContentBrowserClient new_client; | |
1791 GetContentClient()->set_browser_for_testing(&new_client); | |
1792 | |
1793 MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); | |
1794 | |
1795 // Restore. | |
1796 GetContentClient()->set_browser_for_testing(old_client); | |
1797 | |
1798 // This second filter is used to emulate a second process. | |
1799 scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( | |
1800 this, browser_context_->GetResourceContext()); | |
1801 | |
1802 int new_render_view_id = 1; | |
1803 int new_request_id = 2; | |
1804 | |
1805 // Delay the start of the next request so that we can setup the response for | |
1806 // the next URL. | |
1807 SetDelayedStartJobGeneration(true); | |
1808 | |
1809 SetResponse("HTTP/1.1 302 Found\n" | |
1810 "Location: http://other.com/blerg\n\n"); | |
1811 | |
1812 ResourceHostMsg_Request request = | |
1813 CreateResourceRequest("GET", ResourceType::MAIN_FRAME, | |
1814 GURL("http://other.com/blech")); | |
1815 request.transferred_request_child_id = filter_->child_id(); | |
1816 request.transferred_request_request_id = request_id; | |
1817 | |
1818 ResourceHostMsg_RequestResource transfer_request_msg( | |
1819 new_render_view_id, new_request_id, request); | |
1820 bool msg_was_ok; | |
1821 host_.OnMessageReceived(transfer_request_msg, second_filter, &msg_was_ok); | |
1822 MessageLoop::current()->RunUntilIdle(); | |
1823 | |
1824 // Response data for "http://other.com/blerg": | |
1825 const std::string kResponseBody = "hello world"; | |
1826 SetResponse("HTTP/1.1 200 OK\n" | |
1827 "Content-Type: text/plain\n\n", | |
1828 kResponseBody); | |
1829 | |
1830 // OK, let the redirect happen. | |
1831 SetDelayedStartJobGeneration(false); | |
1832 CompleteStartRequest(second_filter, new_request_id); | |
1833 MessageLoop::current()->RunUntilIdle(); | |
1834 | |
1835 // Flush all the pending requests. | |
1836 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1837 | |
1838 // Now, simulate the renderer choosing to follow the redirect. | |
1839 ResourceHostMsg_FollowRedirect redirect_msg( | |
1840 new_render_view_id, new_request_id, false, GURL()); | |
1841 host_.OnMessageReceived(redirect_msg, second_filter, &msg_was_ok); | |
1842 MessageLoop::current()->RunUntilIdle(); | |
1843 | |
1844 // Flush all the pending requests. | |
1845 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1846 | |
1847 // Check generated messages. | |
1848 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1849 accum_.GetClassifiedMessages(&msgs); | |
1850 | |
1851 ASSERT_EQ(1U, msgs.size()); | |
1852 | |
1853 // We should have received a redirect followed by a "normal" payload. | |
1854 EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type()); | |
1855 msgs[0].erase(msgs[0].begin()); | |
1856 CheckSuccessfulRequest(msgs[0], kResponseBody); | |
1857 } | |
1858 | |
1859 TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) { | |
1860 EXPECT_EQ(0, host_.pending_requests()); | |
1861 | |
1862 SetResourceType(ResourceType::MAIN_FRAME); | |
1863 HandleScheme("http"); | |
1864 | |
1865 MakeTestRequest(0, 1, GURL("foo://bar")); | |
1866 | |
1867 // Flush all pending requests. | |
1868 while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} | |
1869 | |
1870 // Sort all the messages we saw by request. | |
1871 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1872 accum_.GetClassifiedMessages(&msgs); | |
1873 | |
1874 // We should have gotten one RequestComplete message. | |
1875 ASSERT_EQ(1U, msgs[0].size()); | |
1876 EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][0].type()); | |
1877 | |
1878 // The RequestComplete message should have the error code of | |
1879 // ERR_UNKNOWN_URL_SCHEME. | |
1880 int request_id; | |
1881 int error_code; | |
1882 | |
1883 PickleIterator iter(msgs[0][0]); | |
1884 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &request_id)); | |
1885 EXPECT_TRUE(IPC::ReadParam(&msgs[0][0], &iter, &error_code)); | |
1886 | |
1887 EXPECT_EQ(1, request_id); | |
1888 EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, error_code); | |
1889 } | |
1890 | |
1891 TEST_F(ResourceDispatcherHostTest, DataReceivedACKs) { | |
1892 EXPECT_EQ(0, host_.pending_requests()); | |
1893 | |
1894 SendDataReceivedACKs(true); | |
1895 | |
1896 HandleScheme("big-job"); | |
1897 MakeTestRequest(0, 1, GURL("big-job:0123456789,1000000")); | |
1898 | |
1899 // Sort all the messages we saw by request. | |
1900 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1901 accum_.GetClassifiedMessages(&msgs); | |
1902 | |
1903 size_t size = msgs[0].size(); | |
1904 | |
1905 EXPECT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type()); | |
1906 EXPECT_EQ(ResourceMsg_SetDataBuffer::ID, msgs[0][1].type()); | |
1907 for (size_t i = 2; i < size - 1; ++i) | |
1908 EXPECT_EQ(ResourceMsg_DataReceived::ID, msgs[0][i].type()); | |
1909 EXPECT_EQ(ResourceMsg_RequestComplete::ID, msgs[0][size - 1].type()); | |
1910 } | |
1911 | |
1912 TEST_F(ResourceDispatcherHostTest, DelayedDataReceivedACKs) { | |
1913 EXPECT_EQ(0, host_.pending_requests()); | |
1914 | |
1915 HandleScheme("big-job"); | |
1916 MakeTestRequest(0, 1, GURL("big-job:0123456789,1000000")); | |
1917 | |
1918 // Sort all the messages we saw by request. | |
1919 ResourceIPCAccumulator::ClassifiedMessages msgs; | |
1920 accum_.GetClassifiedMessages(&msgs); | |
1921 | |
1922 // We expect 1x ReceivedResponse, 1x SetDataBuffer, Nx ReceivedData messages. | |
1923 EXPECT_EQ(ResourceMsg_ReceivedResponse::ID, msgs[0][0].type()); | |
1924 EXPECT_EQ(ResourceMsg_SetDataBuffer::ID, msgs[0][1].type()); | |
1925 for (size_t i = 2; i < msgs[0].size(); ++i) | |
1926 EXPECT_EQ(ResourceMsg_DataReceived::ID, msgs[0][i].type()); | |
1927 | |
1928 // NOTE: If we fail the above checks then it means that we probably didn't | |
1929 // load a big enough response to trigger the delay mechanism we are trying to | |
1930 // test! | |
1931 | |
1932 msgs[0].erase(msgs[0].begin()); | |
1933 msgs[0].erase(msgs[0].begin()); | |
1934 | |
1935 // ACK all DataReceived messages until we find a RequestComplete message. | |
1936 bool complete = false; | |
1937 while (!complete) { | |
1938 for (size_t i = 0; i < msgs[0].size(); ++i) { | |
1939 if (msgs[0][i].type() == ResourceMsg_RequestComplete::ID) { | |
1940 complete = true; | |
1941 break; | |
1942 } | |
1943 | |
1944 EXPECT_EQ(ResourceMsg_DataReceived::ID, msgs[0][i].type()); | |
1945 | |
1946 ResourceHostMsg_DataReceived_ACK msg(0, 1); | |
1947 bool msg_was_ok; | |
1948 host_.OnMessageReceived(msg, filter_.get(), &msg_was_ok); | |
1949 } | |
1950 | |
1951 MessageLoop::current()->RunUntilIdle(); | |
1952 | |
1953 msgs.clear(); | |
1954 accum_.GetClassifiedMessages(&msgs); | |
1955 } | |
1956 } | |
1957 | |
1958 } // namespace content | |
OLD | NEW |