Home | History | Annotate | Download | only in search
      1 // Copyright 2013 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 "chrome/browser/search/iframe_source.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/ref_counted_memory.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "chrome/browser/search/instant_io_context.h"
     12 #include "content/public/browser/browser_thread.h"
     13 #include "content/public/browser/resource_request_info.h"
     14 #include "content/public/test/mock_resource_context.h"
     15 #include "content/public/test/test_browser_thread_bundle.h"
     16 #include "grit/browser_resources.h"
     17 #include "ipc/ipc_message.h"
     18 #include "net/base/request_priority.h"
     19 #include "net/url_request/url_request.h"
     20 #include "net/url_request/url_request_context.h"
     21 #include "net/url_request/url_request_test_util.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 #include "url/gurl.h"
     24 
     25 using content::ResourceType;
     26 
     27 const int kNonInstantRendererPID = 0;
     28 const char kNonInstantOrigin[] = "http://evil";
     29 const int kInstantRendererPID = 1;
     30 const char kInstantOrigin[] = "chrome-search://instant";
     31 const int kInvalidRendererPID = 42;
     32 
     33 class TestIframeSource : public IframeSource {
     34  public:
     35   using IframeSource::GetMimeType;
     36   using IframeSource::ShouldServiceRequest;
     37   using IframeSource::SendResource;
     38   using IframeSource::SendJSWithOrigin;
     39 
     40  protected:
     41   virtual std::string GetSource() const OVERRIDE {
     42     return "test";
     43   }
     44 
     45   virtual bool ServesPath(const std::string& path) const OVERRIDE {
     46     return path == "/valid.html" || path == "/valid.js";
     47   }
     48 
     49   virtual void StartDataRequest(
     50       const std::string& path,
     51       int render_process_id,
     52       int render_frame_id,
     53       const content::URLDataSource::GotDataCallback& callback) OVERRIDE {
     54   }
     55 
     56   // RenderFrameHost is hard to mock in concert with everything else, so stub
     57   // this method out for testing.
     58   virtual bool GetOrigin(
     59       int process_id,
     60       int render_frame_id,
     61       std::string* origin) const OVERRIDE {
     62     if (process_id == kInstantRendererPID) {
     63       *origin = kInstantOrigin;
     64       return true;
     65     }
     66     if (process_id == kNonInstantRendererPID) {
     67       *origin = kNonInstantOrigin;
     68       return true;
     69     }
     70     return false;
     71   }
     72 };
     73 
     74 class IframeSourceTest : public testing::Test {
     75  public:
     76   // net::URLRequest wants to be executed with a message loop that has TYPE_IO.
     77   // InstantIOContext needs to be created on the UI thread and have everything
     78   // else happen on the IO thread. This setup is a hacky way to satisfy all
     79   // those constraints.
     80   IframeSourceTest()
     81       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
     82         resource_context_(&test_url_request_context_),
     83         instant_io_context_(NULL),
     84         response_(NULL) {
     85   }
     86 
     87   TestIframeSource* source() { return source_.get(); }
     88 
     89   std::string response_string() {
     90     if (response_.get()) {
     91       return std::string(response_->front_as<char>(), response_->size());
     92     }
     93     return "";
     94   }
     95 
     96   scoped_ptr<net::URLRequest> MockRequest(
     97       const std::string& url,
     98       bool allocate_info,
     99       int render_process_id,
    100       int render_frame_id) {
    101     scoped_ptr<net::URLRequest> request(
    102         resource_context_.GetRequestContext()->CreateRequest(
    103             GURL(url),
    104             net::DEFAULT_PRIORITY,
    105             NULL,
    106             NULL));
    107     if (allocate_info) {
    108       content::ResourceRequestInfo::AllocateForTesting(
    109           request.get(),
    110           content::RESOURCE_TYPE_SUB_FRAME,
    111           &resource_context_,
    112           render_process_id,
    113           render_frame_id,
    114           MSG_ROUTING_NONE,
    115           false);
    116     }
    117     return request.Pass();
    118   }
    119 
    120   void SendResource(int resource_id) {
    121     source()->SendResource(resource_id, callback_);
    122   }
    123 
    124   void SendJSWithOrigin(
    125       int resource_id,
    126       int render_process_id,
    127       int render_frame_id) {
    128     source()->SendJSWithOrigin(resource_id, render_process_id, render_frame_id,
    129                                callback_);
    130   }
    131 
    132  private:
    133   virtual void SetUp() OVERRIDE {
    134     source_.reset(new TestIframeSource());
    135     callback_ = base::Bind(&IframeSourceTest::SaveResponse,
    136                            base::Unretained(this));
    137     instant_io_context_ = new InstantIOContext;
    138     InstantIOContext::SetUserDataOnIO(&resource_context_, instant_io_context_);
    139     InstantIOContext::AddInstantProcessOnIO(instant_io_context_,
    140                                             kInstantRendererPID);
    141     response_ = NULL;
    142   }
    143 
    144   virtual void TearDown() {
    145     source_.reset();
    146   }
    147 
    148   void SaveResponse(base::RefCountedMemory* data) {
    149     response_ = data;
    150   }
    151 
    152   content::TestBrowserThreadBundle thread_bundle_;
    153 
    154   net::TestURLRequestContext test_url_request_context_;
    155   content::MockResourceContext resource_context_;
    156   scoped_ptr<TestIframeSource> source_;
    157   content::URLDataSource::GotDataCallback callback_;
    158   scoped_refptr<InstantIOContext> instant_io_context_;
    159   scoped_refptr<base::RefCountedMemory> response_;
    160 };
    161 
    162 TEST_F(IframeSourceTest, ShouldServiceRequest) {
    163   scoped_ptr<net::URLRequest> request;
    164   request = MockRequest("http://test/loader.js", true,
    165                         kNonInstantRendererPID, 0);
    166   EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
    167   request = MockRequest("chrome-search://bogus/valid.js", true,
    168                         kInstantRendererPID, 0);
    169   EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
    170   request = MockRequest("chrome-search://test/bogus.js", true,
    171                         kInstantRendererPID, 0);
    172   EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
    173   request = MockRequest("chrome-search://test/valid.js", true,
    174                         kInstantRendererPID, 0);
    175   EXPECT_TRUE(source()->ShouldServiceRequest(request.get()));
    176   request = MockRequest("chrome-search://test/valid.js", true,
    177                         kNonInstantRendererPID, 0);
    178   EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
    179   request = MockRequest("chrome-search://test/valid.js", true,
    180                         kInvalidRendererPID, 0);
    181   EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
    182 }
    183 
    184 TEST_F(IframeSourceTest, GetMimeType) {
    185   // URLDataManagerBackend does not include / in path_and_query.
    186   EXPECT_EQ("text/html", source()->GetMimeType("foo.html"));
    187   EXPECT_EQ("application/javascript", source()->GetMimeType("foo.js"));
    188   EXPECT_EQ("text/css", source()->GetMimeType("foo.css"));
    189   EXPECT_EQ("image/png", source()->GetMimeType("foo.png"));
    190   EXPECT_EQ("", source()->GetMimeType("bogus"));
    191 }
    192 
    193 TEST_F(IframeSourceTest, SendResource) {
    194   SendResource(IDR_MOST_VISITED_TITLE_HTML);
    195   EXPECT_FALSE(response_string().empty());
    196 }
    197 
    198 TEST_F(IframeSourceTest, SendJSWithOrigin) {
    199   SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInstantRendererPID, 0);
    200   EXPECT_FALSE(response_string().empty());
    201   SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kNonInstantRendererPID, 0);
    202   EXPECT_FALSE(response_string().empty());
    203   SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInvalidRendererPID, 0);
    204   EXPECT_TRUE(response_string().empty());
    205 }
    206