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