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.
5 #include "chrome/browser/search/iframe_source.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 "net/base/request_priority.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
24 const int kNonInstantRendererPID = 0;
25 const char kNonInstantOrigin[] = "http://evil";
26 const int kInstantRendererPID = 1;
27 const char kInstantOrigin[] = "chrome-search://instant";
28 const int kInvalidRendererPID = 42;
30 class TestIframeSource : public IframeSource {
32 using IframeSource::GetMimeType;
33 using IframeSource::ShouldServiceRequest;
34 using IframeSource::SendResource;
35 using IframeSource::SendJSWithOrigin;
38 virtual std::string GetSource() const OVERRIDE {
42 virtual bool ServesPath(const std::string& path) const OVERRIDE {
43 return path == "/valid.html" || path == "/valid.js";
46 virtual void StartDataRequest(
47 const std::string& path,
48 int render_process_id,
50 const content::URLDataSource::GotDataCallback& callback) OVERRIDE {
53 // RenderViewHost is hard to mock in concert with everything else, so stub
54 // this method out for testing.
55 virtual bool GetOrigin(
58 std::string* origin) const OVERRIDE {
59 if (process_id == kInstantRendererPID) {
60 *origin = kInstantOrigin;
63 if (process_id == kNonInstantRendererPID) {
64 *origin = kNonInstantOrigin;
71 class IframeSourceTest : public testing::Test {
73 // net::URLRequest wants to be executed with a message loop that has TYPE_IO.
74 // InstantIOContext needs to be created on the UI thread and have everything
75 // else happen on the IO thread. This setup is a hacky way to satisfy all
78 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
79 resource_context_(&test_url_request_context_),
80 instant_io_context_(NULL),
84 TestIframeSource* source() { return source_.get(); }
86 std::string response_string() {
87 if (response_.get()) {
88 return std::string(reinterpret_cast<const char*>(response_->front()),
94 net::URLRequest* MockRequest(
95 const std::string& url,
97 int render_process_id,
99 net::URLRequest* request =
100 new net::URLRequest(GURL(url),
101 net::DEFAULT_PRIORITY,
103 resource_context_.GetRequestContext());
105 content::ResourceRequestInfo::AllocateForTesting(request,
106 ResourceType::SUB_FRAME,
115 void SendResource(int resource_id) {
116 source()->SendResource(resource_id, callback_);
119 void SendJSWithOrigin(
121 int render_process_id,
122 int render_view_id) {
123 source()->SendJSWithOrigin(resource_id, render_process_id, render_view_id,
128 virtual void SetUp() OVERRIDE {
129 source_.reset(new TestIframeSource());
130 callback_ = base::Bind(&IframeSourceTest::SaveResponse,
131 base::Unretained(this));
132 instant_io_context_ = new InstantIOContext;
133 InstantIOContext::SetUserDataOnIO(&resource_context_, instant_io_context_);
134 InstantIOContext::AddInstantProcessOnIO(instant_io_context_,
135 kInstantRendererPID);
139 virtual void TearDown() {
143 void SaveResponse(base::RefCountedMemory* data) {
147 content::TestBrowserThreadBundle thread_bundle_;
149 net::TestURLRequestContext test_url_request_context_;
150 content::MockResourceContext resource_context_;
151 scoped_ptr<TestIframeSource> source_;
152 content::URLDataSource::GotDataCallback callback_;
153 scoped_refptr<InstantIOContext> instant_io_context_;
154 scoped_refptr<base::RefCountedMemory> response_;
157 TEST_F(IframeSourceTest, ShouldServiceRequest) {
158 scoped_ptr<net::URLRequest> request;
159 request.reset(MockRequest("http://test/loader.js", true,
160 kNonInstantRendererPID, 0));
161 EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
162 request.reset(MockRequest("chrome-search://bogus/valid.js", true,
163 kInstantRendererPID, 0));
164 EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
165 request.reset(MockRequest("chrome-search://test/bogus.js", true,
166 kInstantRendererPID, 0));
167 EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
168 request.reset(MockRequest("chrome-search://test/valid.js", true,
169 kInstantRendererPID, 0));
170 EXPECT_TRUE(source()->ShouldServiceRequest(request.get()));
171 request.reset(MockRequest("chrome-search://test/valid.js", true,
172 kNonInstantRendererPID, 0));
173 EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
174 request.reset(MockRequest("chrome-search://test/valid.js", true,
175 kInvalidRendererPID, 0));
176 EXPECT_FALSE(source()->ShouldServiceRequest(request.get()));
179 TEST_F(IframeSourceTest, GetMimeType) {
180 // URLDataManagerBackend does not include / in path_and_query.
181 EXPECT_EQ("text/html", source()->GetMimeType("foo.html"));
182 EXPECT_EQ("application/javascript", source()->GetMimeType("foo.js"));
183 EXPECT_EQ("text/css", source()->GetMimeType("foo.css"));
184 EXPECT_EQ("image/png", source()->GetMimeType("foo.png"));
185 EXPECT_EQ("", source()->GetMimeType("bogus"));
188 TEST_F(IframeSourceTest, SendResource) {
189 SendResource(IDR_MOST_VISITED_TITLE_HTML);
190 EXPECT_FALSE(response_string().empty());
193 TEST_F(IframeSourceTest, SendJSWithOrigin) {
194 SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInstantRendererPID, 0);
195 EXPECT_FALSE(response_string().empty());
196 SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kNonInstantRendererPID, 0);
197 EXPECT_FALSE(response_string().empty());
198 SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS, kInvalidRendererPID, 0);
199 EXPECT_TRUE(response_string().empty());