• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
6 #include <vector>
7 
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/process/process.h"
11 #include "base/process/process_handle.h"
12 #include "content/child/request_extra_data.h"
13 #include "content/child/resource_dispatcher.h"
14 #include "content/common/resource_messages.h"
15 #include "content/public/common/resource_response.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/upload_data.h"
18 #include "net/http/http_response_headers.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "webkit/common/appcache/appcache_interfaces.h"
21 
22 using webkit_glue::ResourceLoaderBridge;
23 using webkit_glue::ResourceResponseInfo;
24 
25 namespace content {
26 
27 static const char test_page_url[] = "http://www.google.com/";
28 static const char test_page_headers[] =
29   "HTTP/1.1 200 OK\nContent-Type:text/html\n\n";
30 static const char test_page_mime_type[] = "text/html";
31 static const char test_page_charset[] = "";
32 static const char test_page_contents[] =
33   "<html><head><title>Google</title></head><body><h1>Google</h1></body></html>";
34 static const uint32 test_page_contents_len = arraysize(test_page_contents) - 1;
35 
36 static const char kShmemSegmentName[] = "DeferredResourceLoaderTest";
37 
38 // Listens for request response data and stores it so that it can be compared
39 // to the reference data.
40 class TestRequestCallback : public ResourceLoaderBridge::Peer {
41  public:
TestRequestCallback()42   TestRequestCallback() : complete_(false) {
43   }
44 
OnUploadProgress(uint64 position,uint64 size)45   virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
46   }
47 
OnReceivedRedirect(const GURL & new_url,const ResourceResponseInfo & info,bool * has_new_first_party_for_cookies,GURL * new_first_party_for_cookies)48   virtual bool OnReceivedRedirect(
49       const GURL& new_url,
50       const ResourceResponseInfo& info,
51       bool* has_new_first_party_for_cookies,
52       GURL* new_first_party_for_cookies) OVERRIDE {
53     *has_new_first_party_for_cookies = false;
54     return true;
55   }
56 
OnReceivedResponse(const ResourceResponseInfo & info)57   virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
58   }
59 
OnDownloadedData(int len,int encoded_data_length)60   virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
61   }
62 
OnReceivedData(const char * data,int data_length,int encoded_data_length)63   virtual void OnReceivedData(const char* data,
64                               int data_length,
65                               int encoded_data_length) OVERRIDE {
66     EXPECT_FALSE(complete_);
67     data_.append(data, data_length);
68     total_encoded_data_length_ += encoded_data_length;
69   }
70 
OnCompletedRequest(int error_code,bool was_ignored_by_handler,const std::string & security_info,const base::TimeTicks & completion_time)71   virtual void OnCompletedRequest(
72       int error_code,
73       bool was_ignored_by_handler,
74       const std::string& security_info,
75       const base::TimeTicks& completion_time) OVERRIDE {
76     EXPECT_FALSE(complete_);
77     complete_ = true;
78   }
79 
complete() const80   bool complete() const {
81     return complete_;
82   }
data() const83   const std::string& data() const {
84     return data_;
85   }
total_encoded_data_length() const86   int total_encoded_data_length() const {
87     return total_encoded_data_length_;
88   }
89 
90  private:
91   bool complete_;
92   std::string data_;
93   int total_encoded_data_length_;
94 };
95 
96 
97 // Sets up the message sender override for the unit test
98 class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
99  public:
100   // Emulates IPC send operations (IPC::Sender) by adding
101   // pending messages to the queue.
Send(IPC::Message * msg)102   virtual bool Send(IPC::Message* msg) OVERRIDE {
103     message_queue_.push_back(IPC::Message(*msg));
104     delete msg;
105     return true;
106   }
107 
108   // Emulates the browser process and processes the pending IPC messages,
109   // returning the hardcoded file contents.
ProcessMessages()110   void ProcessMessages() {
111     while (!message_queue_.empty()) {
112       int request_id;
113       ResourceHostMsg_Request request;
114       ASSERT_TRUE(ResourceHostMsg_RequestResource::Read(
115           &message_queue_[0], &request_id, &request));
116 
117       // check values
118       EXPECT_EQ(test_page_url, request.url.spec());
119 
120       // received response message
121       ResourceResponseHead response;
122       std::string raw_headers(test_page_headers);
123       std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
124       response.headers = new net::HttpResponseHeaders(raw_headers);
125       response.mime_type = test_page_mime_type;
126       response.charset = test_page_charset;
127       dispatcher_->OnReceivedResponse(request_id, response);
128 
129       // received data message with the test contents
130       base::SharedMemory shared_mem;
131       EXPECT_TRUE(shared_mem.CreateAndMapAnonymous(test_page_contents_len));
132       char* put_data_here = static_cast<char*>(shared_mem.memory());
133       memcpy(put_data_here, test_page_contents, test_page_contents_len);
134       base::SharedMemoryHandle dup_handle;
135       EXPECT_TRUE(shared_mem.GiveToProcess(
136           base::Process::Current().handle(), &dup_handle));
137       dispatcher_->OnSetDataBuffer(request_id, dup_handle,
138                                    test_page_contents_len, 0);
139       dispatcher_->OnReceivedData(request_id, 0, test_page_contents_len,
140                                   test_page_contents_len);
141 
142       message_queue_.erase(message_queue_.begin());
143 
144       // read the ack message.
145       Tuple1<int> request_ack;
146       ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read(
147           &message_queue_[0], &request_ack));
148 
149       ASSERT_EQ(request_ack.a, request_id);
150 
151       message_queue_.erase(message_queue_.begin());
152     }
153   }
154 
155  protected:
156   // testing::Test
SetUp()157   virtual void SetUp() OVERRIDE {
158     dispatcher_.reset(new ResourceDispatcher(this));
159   }
TearDown()160   virtual void TearDown() OVERRIDE {
161     dispatcher_.reset();
162   }
163 
CreateBridge()164   ResourceLoaderBridge* CreateBridge() {
165     webkit_glue::ResourceLoaderBridge::RequestInfo request_info;
166     request_info.method = "GET";
167     request_info.url = GURL(test_page_url);
168     request_info.first_party_for_cookies = GURL(test_page_url);
169     request_info.referrer = GURL();
170     request_info.headers = std::string();
171     request_info.load_flags = 0;
172     request_info.requestor_pid = 0;
173     request_info.request_type = ResourceType::SUB_RESOURCE;
174     request_info.appcache_host_id = appcache::kNoHostId;
175     request_info.routing_id = 0;
176     RequestExtraData extra_data(blink::WebReferrerPolicyDefault,
177                                 blink::WebString(),
178                                 false, MSG_ROUTING_NONE, true, 0, GURL(),
179                                 false, -1, true,
180                                 PAGE_TRANSITION_LINK, false, -1, -1);
181     request_info.extra_data = &extra_data;
182 
183     return dispatcher_->CreateBridge(request_info);
184   }
185 
186   std::vector<IPC::Message> message_queue_;
187   static scoped_ptr<ResourceDispatcher> dispatcher_;
188 };
189 
190 /*static*/
191 scoped_ptr<ResourceDispatcher> ResourceDispatcherTest::dispatcher_;
192 
193 // Does a simple request and tests that the correct data is received.
TEST_F(ResourceDispatcherTest,RoundTrip)194 TEST_F(ResourceDispatcherTest, RoundTrip) {
195   TestRequestCallback callback;
196   ResourceLoaderBridge* bridge = CreateBridge();
197 
198   bridge->Start(&callback);
199 
200   ProcessMessages();
201 
202   // FIXME(brettw) when the request complete messages are actually handledo
203   // and dispatched, uncomment this.
204   //EXPECT_TRUE(callback.complete());
205   //EXPECT_STREQ(test_page_contents, callback.data().c_str());
206   //EXPECT_EQ(test_page_contents_len, callback.total_encoded_data_length());
207 
208   delete bridge;
209 }
210 
211 // Tests that the request IDs are straight when there are multiple requests.
TEST_F(ResourceDispatcherTest,MultipleRequests)212 TEST_F(ResourceDispatcherTest, MultipleRequests) {
213   // FIXME
214 }
215 
216 // Tests that the cancel method prevents other messages from being received
TEST_F(ResourceDispatcherTest,Cancel)217 TEST_F(ResourceDispatcherTest, Cancel) {
218   // FIXME
219 }
220 
TEST_F(ResourceDispatcherTest,Cookies)221 TEST_F(ResourceDispatcherTest, Cookies) {
222   // FIXME
223 }
224 
TEST_F(ResourceDispatcherTest,SerializedPostData)225 TEST_F(ResourceDispatcherTest, SerializedPostData) {
226   // FIXME
227 }
228 
229 // This class provides functionality to validate whether the ResourceDispatcher
230 // object honors the deferred loading contract correctly, i.e. if deferred
231 // loading is enabled it should queue up any responses received. If deferred
232 // loading is enabled/disabled in the context of a dispatched message, other
233 // queued messages should not be dispatched until deferred load is turned off.
234 class DeferredResourceLoadingTest : public ResourceDispatcherTest,
235                                     public ResourceLoaderBridge::Peer {
236  public:
DeferredResourceLoadingTest()237   DeferredResourceLoadingTest()
238       : defer_loading_(false) {
239   }
240 
Send(IPC::Message * msg)241   virtual bool Send(IPC::Message* msg) OVERRIDE {
242     delete msg;
243     return true;
244   }
245 
InitMessages()246   void InitMessages() {
247     set_defer_loading(true);
248 
249     ResourceResponseHead response_head;
250     response_head.error_code = net::OK;
251 
252     dispatcher_->OnMessageReceived(
253         ResourceMsg_ReceivedResponse(0, response_head));
254 
255     // Duplicate the shared memory handle so both the test and the callee can
256     // close their copy.
257     base::SharedMemoryHandle duplicated_handle;
258     EXPECT_TRUE(shared_handle_.ShareToProcess(base::GetCurrentProcessHandle(),
259                                               &duplicated_handle));
260 
261     dispatcher_->OnMessageReceived(
262         ResourceMsg_SetDataBuffer(0, duplicated_handle, 100, 0));
263     dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(0, 0, 100, 100));
264 
265     set_defer_loading(false);
266   }
267 
268   // ResourceLoaderBridge::Peer methods.
OnUploadProgress(uint64 position,uint64 size)269   virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
270   }
271 
OnReceivedRedirect(const GURL & new_url,const ResourceResponseInfo & info,bool * has_new_first_party_for_cookies,GURL * new_first_party_for_cookies)272   virtual bool OnReceivedRedirect(
273       const GURL& new_url,
274       const ResourceResponseInfo& info,
275       bool* has_new_first_party_for_cookies,
276       GURL* new_first_party_for_cookies) OVERRIDE {
277     *has_new_first_party_for_cookies = false;
278     return true;
279   }
280 
OnReceivedResponse(const ResourceResponseInfo & info)281   virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
282     EXPECT_EQ(defer_loading_, false);
283     set_defer_loading(true);
284   }
285 
OnDownloadedData(int len,int encoded_data_length)286   virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
287   }
288 
OnReceivedData(const char * data,int data_length,int encoded_data_length)289   virtual void OnReceivedData(const char* data,
290                               int data_length,
291                               int encoded_data_length) OVERRIDE {
292     EXPECT_EQ(defer_loading_, false);
293     set_defer_loading(false);
294   }
295 
OnCompletedRequest(int error_code,bool was_ignored_by_handler,const std::string & security_info,const base::TimeTicks & completion_time)296   virtual void OnCompletedRequest(
297       int error_code,
298       bool was_ignored_by_handler,
299       const std::string& security_info,
300       const base::TimeTicks& completion_time) OVERRIDE {
301   }
302 
303  protected:
SetUp()304   virtual void SetUp() OVERRIDE {
305     ResourceDispatcherTest::SetUp();
306     shared_handle_.Delete(kShmemSegmentName);
307     EXPECT_TRUE(shared_handle_.CreateNamed(kShmemSegmentName, false, 100));
308   }
309 
TearDown()310   virtual void TearDown() OVERRIDE {
311     shared_handle_.Close();
312     EXPECT_TRUE(shared_handle_.Delete(kShmemSegmentName));
313     ResourceDispatcherTest::TearDown();
314   }
315 
316  private:
set_defer_loading(bool defer)317   void set_defer_loading(bool defer) {
318     defer_loading_ = defer;
319     dispatcher_->SetDefersLoading(0, defer);
320   }
321 
defer_loading() const322   bool defer_loading() const {
323     return defer_loading_;
324   }
325 
326   bool defer_loading_;
327   base::SharedMemory shared_handle_;
328 };
329 
TEST_F(DeferredResourceLoadingTest,DeferredLoadTest)330 TEST_F(DeferredResourceLoadingTest, DeferredLoadTest) {
331   base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
332 
333   ResourceLoaderBridge* bridge = CreateBridge();
334 
335   bridge->Start(this);
336   InitMessages();
337 
338   // Dispatch deferred messages.
339   message_loop.RunUntilIdle();
340   delete bridge;
341 }
342 
343 class TimeConversionTest : public ResourceDispatcherTest,
344                            public ResourceLoaderBridge::Peer {
345  public:
Send(IPC::Message * msg)346   virtual bool Send(IPC::Message* msg) OVERRIDE {
347     delete msg;
348     return true;
349   }
350 
PerformTest(const ResourceResponseHead & response_head)351   void PerformTest(const ResourceResponseHead& response_head) {
352     scoped_ptr<ResourceLoaderBridge> bridge(CreateBridge());
353     bridge->Start(this);
354 
355     dispatcher_->OnMessageReceived(
356         ResourceMsg_ReceivedResponse(0, response_head));
357   }
358 
359   // ResourceLoaderBridge::Peer methods.
OnUploadProgress(uint64 position,uint64 size)360   virtual void OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
361   }
362 
OnReceivedRedirect(const GURL & new_url,const ResourceResponseInfo & info,bool * has_new_first_party_for_cookies,GURL * new_first_party_for_cookies)363   virtual bool OnReceivedRedirect(
364       const GURL& new_url,
365       const ResourceResponseInfo& info,
366       bool* has_new_first_party_for_cookies,
367       GURL* new_first_party_for_cookies) OVERRIDE {
368     return true;
369   }
370 
OnReceivedResponse(const ResourceResponseInfo & info)371   virtual void OnReceivedResponse(const ResourceResponseInfo& info) OVERRIDE {
372     response_info_ = info;
373   }
374 
OnDownloadedData(int len,int encoded_data_length)375   virtual void OnDownloadedData(int len, int encoded_data_length) OVERRIDE {
376   }
377 
OnReceivedData(const char * data,int data_length,int encoded_data_length)378   virtual void OnReceivedData(const char* data,
379                               int data_length,
380                               int encoded_data_length) OVERRIDE {
381   }
382 
OnCompletedRequest(int error_code,bool was_ignored_by_handler,const std::string & security_info,const base::TimeTicks & completion_time)383   virtual void OnCompletedRequest(
384       int error_code,
385       bool was_ignored_by_handler,
386       const std::string& security_info,
387       const base::TimeTicks& completion_time) OVERRIDE {
388   }
389 
response_info() const390   const ResourceResponseInfo& response_info() const { return response_info_; }
391 
392  private:
393   ResourceResponseInfo response_info_;
394 };
395 
396 // TODO(simonjam): Enable this when 10829031 lands.
TEST_F(TimeConversionTest,DISABLED_ProperlyInitialized)397 TEST_F(TimeConversionTest, DISABLED_ProperlyInitialized) {
398   ResourceResponseHead response_head;
399   response_head.error_code = net::OK;
400   response_head.request_start = base::TimeTicks::FromInternalValue(5);
401   response_head.response_start = base::TimeTicks::FromInternalValue(15);
402   response_head.load_timing.request_start_time = base::Time::Now();
403   response_head.load_timing.request_start =
404       base::TimeTicks::FromInternalValue(10);
405   response_head.load_timing.connect_timing.connect_start =
406       base::TimeTicks::FromInternalValue(13);
407 
408   PerformTest(response_head);
409 
410   EXPECT_LT(base::TimeTicks(), response_info().load_timing.request_start);
411   EXPECT_EQ(base::TimeTicks(),
412             response_info().load_timing.connect_timing.dns_start);
413   EXPECT_LE(response_head.load_timing.request_start,
414             response_info().load_timing.connect_timing.connect_start);
415 }
416 
TEST_F(TimeConversionTest,PartiallyInitialized)417 TEST_F(TimeConversionTest, PartiallyInitialized) {
418   ResourceResponseHead response_head;
419   response_head.error_code = net::OK;
420   response_head.request_start = base::TimeTicks::FromInternalValue(5);
421   response_head.response_start = base::TimeTicks::FromInternalValue(15);
422 
423   PerformTest(response_head);
424 
425   EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
426   EXPECT_EQ(base::TimeTicks(),
427             response_info().load_timing.connect_timing.dns_start);
428 }
429 
TEST_F(TimeConversionTest,NotInitialized)430 TEST_F(TimeConversionTest, NotInitialized) {
431   ResourceResponseHead response_head;
432   response_head.error_code = net::OK;
433 
434   PerformTest(response_head);
435 
436   EXPECT_EQ(base::TimeTicks(), response_info().load_timing.request_start);
437   EXPECT_EQ(base::TimeTicks(),
438             response_info().load_timing.connect_timing.dns_start);
439 }
440 
441 }  // namespace content
442