| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 // Tests exercising the Chrome Plugin API. | |
| 5 | |
| 6 #include "base/file_util.h" | |
| 7 #include "base/message_loop_proxy.h" | |
| 8 #include "base/path_service.h" | |
| 9 #include "base/string_util.h" | |
| 10 #include "chrome/browser/chrome_plugin_host.h" | |
| 11 #include "chrome/browser/profiles/profile.h" | |
| 12 #include "chrome/common/chrome_plugin_lib.h" | |
| 13 #include "chrome/common/net/url_request_context_getter.h" | |
| 14 #include "chrome/test/chrome_plugin/test_chrome_plugin.h" | |
| 15 #include "chrome/test/test_url_request_context_getter.h" | |
| 16 #include "content/browser/browser_thread.h" | |
| 17 #include "net/base/io_buffer.h" | |
| 18 #include "net/http/http_response_headers.h" | |
| 19 #include "net/url_request/url_request_test_job.h" | |
| 20 #include "net/url_request/url_request_test_util.h" | |
| 21 #include "net/test/test_server.h" | |
| 22 #include "testing/gtest/include/gtest/gtest.h" | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); | |
| 27 const char kPluginFilename[] = "test_chrome_plugin.dll"; | |
| 28 const int kResponseBufferSize = 4096; | |
| 29 | |
| 30 class ChromePluginTest : public testing::Test, | |
| 31 public net::URLRequest::Delegate { | |
| 32 public: | |
| 33 ChromePluginTest() | |
| 34 : io_thread_(BrowserThread::IO, &message_loop_), | |
| 35 request_(NULL), | |
| 36 response_buffer_(new net::IOBuffer(kResponseBufferSize)), | |
| 37 plugin_(NULL), | |
| 38 expected_payload_(NULL), | |
| 39 request_context_getter_(new TestURLRequestContextGetter()) { | |
| 40 test_funcs_.test_make_request = NULL; | |
| 41 } | |
| 42 | |
| 43 // Loads/unloads the chrome test plugin. | |
| 44 void LoadPlugin(); | |
| 45 void UnloadPlugin(); | |
| 46 | |
| 47 // Runs the test and expects the given payload as a response. If expectation | |
| 48 // is NULL, the request is expected to fail. | |
| 49 void RunTest(const GURL& url, const TestResponsePayload* expected_payload); | |
| 50 | |
| 51 // net::URLRequest::Delegate implementations | |
| 52 virtual void OnResponseStarted(net::URLRequest* request); | |
| 53 virtual void OnReadCompleted(net::URLRequest* request, int bytes_read); | |
| 54 | |
| 55 // Helper called when the net::URLRequest is done. | |
| 56 void OnURLRequestComplete(); | |
| 57 | |
| 58 // testing::Test | |
| 59 virtual void SetUp() { | |
| 60 LoadPlugin(); | |
| 61 net::URLRequest::RegisterProtocolFactory("test", | |
| 62 &net::URLRequestTestJob::Factory); | |
| 63 | |
| 64 // We need to setup a default request context in order to issue HTTP | |
| 65 // requests. | |
| 66 DCHECK(!Profile::GetDefaultRequestContext()); | |
| 67 Profile::set_default_request_context(request_context_getter_.get()); | |
| 68 } | |
| 69 virtual void TearDown() { | |
| 70 UnloadPlugin(); | |
| 71 net::URLRequest::RegisterProtocolFactory("test", NULL); | |
| 72 | |
| 73 Profile::set_default_request_context(NULL); | |
| 74 | |
| 75 // Clear the request before flushing the message loop since killing the | |
| 76 // request can result in the generation of more tasks. | |
| 77 request_.reset(); | |
| 78 | |
| 79 // Flush the message loop to make Purify happy. | |
| 80 message_loop_.RunAllPending(); | |
| 81 } | |
| 82 protected: | |
| 83 MessageLoopForIO message_loop_; | |
| 84 BrowserThread io_thread_; | |
| 85 | |
| 86 // Note: we use net::URLRequest (instead of URLFetcher) because this allows | |
| 87 // the request to be intercepted. | |
| 88 scoped_ptr<net::URLRequest> request_; | |
| 89 scoped_refptr<net::IOBuffer> response_buffer_; | |
| 90 std::string response_data_; | |
| 91 | |
| 92 ChromePluginLib* plugin_; | |
| 93 TestFuncParams::PluginFuncs test_funcs_; | |
| 94 const TestResponsePayload* expected_payload_; | |
| 95 scoped_refptr<URLRequestContextGetter> request_context_getter_; | |
| 96 }; | |
| 97 | |
| 98 static void STDCALL CPT_Complete(CPRequest* request, bool success, | |
| 99 const std::string& raw_headers, | |
| 100 const std::string& body) { | |
| 101 GURL url(request->url); | |
| 102 if (url == GURL(kChromeTestPluginPayloads[0].url)) { | |
| 103 // This URL should fail, because the plugin should not have intercepted it. | |
| 104 EXPECT_FALSE(success); | |
| 105 MessageLoop::current()->Quit(); | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 scoped_refptr<net::HttpResponseHeaders> headers( | |
| 110 new net::HttpResponseHeaders(raw_headers)); | |
| 111 EXPECT_TRUE(success); | |
| 112 EXPECT_EQ(200, headers->response_code()); | |
| 113 | |
| 114 if (url == net::URLRequestTestJob::test_url_1()) { | |
| 115 EXPECT_EQ(net::URLRequestTestJob::test_data_1(), body); | |
| 116 } else if (url == net::URLRequestTestJob::test_url_2()) { | |
| 117 EXPECT_EQ(net::URLRequestTestJob::test_data_2(), body); | |
| 118 } else if (url.spec().find("echo") != std::string::npos) { | |
| 119 EXPECT_EQ(kChromeTestPluginPostData, body); | |
| 120 } | |
| 121 | |
| 122 MessageLoop::current()->Quit(); | |
| 123 } | |
| 124 | |
| 125 static void STDCALL CPT_InvokeLater(TestFuncParams::CallbackFunc callback, | |
| 126 void* callback_data, int delay_ms) { | |
| 127 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 128 NewRunnableFunction(callback, callback_data), delay_ms); | |
| 129 } | |
| 130 | |
| 131 void ChromePluginTest::LoadPlugin() { | |
| 132 FilePath path; | |
| 133 PathService::Get(base::DIR_EXE, &path); | |
| 134 path = path.AppendASCII(kPluginFilename); | |
| 135 plugin_ = ChromePluginLib::Create(path, GetCPBrowserFuncsForBrowser()); | |
| 136 ASSERT_TRUE(plugin_); | |
| 137 | |
| 138 // Exchange test APIs with the plugin. | |
| 139 TestFuncParams params; | |
| 140 params.bfuncs.test_complete = CPT_Complete; | |
| 141 params.bfuncs.invoke_later = CPT_InvokeLater; | |
| 142 EXPECT_EQ(CPERR_SUCCESS, plugin_->CP_Test(¶ms)); | |
| 143 test_funcs_ = params.pfuncs; | |
| 144 } | |
| 145 | |
| 146 void ChromePluginTest::UnloadPlugin() { | |
| 147 ChromePluginLib::UnloadAllPlugins(); | |
| 148 plugin_ = NULL; | |
| 149 } | |
| 150 | |
| 151 void ChromePluginTest::RunTest(const GURL& url, | |
| 152 const TestResponsePayload* expected_payload) { | |
| 153 expected_payload_ = expected_payload; | |
| 154 | |
| 155 response_data_.clear(); | |
| 156 request_.reset(new net::URLRequest(url, this)); | |
| 157 request_->set_context(new TestURLRequestContext()); | |
| 158 request_->Start(); | |
| 159 | |
| 160 MessageLoop::current()->Run(); | |
| 161 } | |
| 162 | |
| 163 void ChromePluginTest::OnResponseStarted(net::URLRequest* request) { | |
| 164 DCHECK(request == request_); | |
| 165 | |
| 166 int bytes_read = 0; | |
| 167 if (request_->status().is_success()) | |
| 168 request_->Read(response_buffer_, kResponseBufferSize, &bytes_read); | |
| 169 OnReadCompleted(request_.get(), bytes_read); | |
| 170 } | |
| 171 | |
| 172 void ChromePluginTest::OnReadCompleted(net::URLRequest* request, | |
| 173 int bytes_read) { | |
| 174 DCHECK(request == request_); | |
| 175 | |
| 176 do { | |
| 177 if (!request_->status().is_success() || bytes_read <= 0) | |
| 178 break; | |
| 179 response_data_.append(response_buffer_->data(), bytes_read); | |
| 180 } while (request_->Read(response_buffer_, kResponseBufferSize, &bytes_read)); | |
| 181 | |
| 182 if (!request_->status().is_io_pending()) { | |
| 183 OnURLRequestComplete(); | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 void ChromePluginTest::OnURLRequestComplete() { | |
| 188 if (expected_payload_) { | |
| 189 EXPECT_TRUE(request_->status().is_success()); | |
| 190 | |
| 191 EXPECT_EQ(expected_payload_->status, request_->GetResponseCode()); | |
| 192 if (expected_payload_->mime_type) { | |
| 193 std::string mime_type; | |
| 194 EXPECT_TRUE(request_->response_headers()->GetMimeType(&mime_type)); | |
| 195 EXPECT_EQ(expected_payload_->mime_type, mime_type); | |
| 196 } | |
| 197 if (expected_payload_->body) { | |
| 198 EXPECT_EQ(expected_payload_->body, response_data_); | |
| 199 } | |
| 200 } else { | |
| 201 EXPECT_FALSE(request_->status().is_success()); | |
| 202 } | |
| 203 | |
| 204 MessageLoop::current()->Quit(); | |
| 205 // If MessageLoop::current() != main_loop_, it will be shut down when the | |
| 206 // main loop returns and this thread subsequently goes out of scope. | |
| 207 } | |
| 208 | |
| 209 // Tests that the plugin can intercept URLs. | |
| 210 TEST_F(ChromePluginTest, DoesIntercept) { | |
| 211 for (size_t i = 0; i < arraysize(kChromeTestPluginPayloads); ++i) { | |
| 212 RunTest(GURL(kChromeTestPluginPayloads[i].url), | |
| 213 &kChromeTestPluginPayloads[i]); | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 // Tests that non-intercepted URLs are handled normally. | |
| 218 TEST_F(ChromePluginTest, DoesNotIntercept) { | |
| 219 TestResponsePayload about_blank = { | |
| 220 "about:blank", | |
| 221 false, | |
| 222 -1, | |
| 223 NULL, | |
| 224 "" | |
| 225 }; | |
| 226 RunTest(GURL(about_blank.url), &about_blank); | |
| 227 } | |
| 228 | |
| 229 // Tests that unloading the plugin correctly unregisters URL interception. | |
| 230 TEST_F(ChromePluginTest, UnregisterIntercept) { | |
| 231 UnloadPlugin(); | |
| 232 | |
| 233 RunTest(GURL(kChromeTestPluginPayloads[0].url), NULL); | |
| 234 } | |
| 235 | |
| 236 static void ProcessAllPendingMessages() { | |
| 237 while (net::URLRequestTestJob::ProcessOnePendingMessage()); | |
| 238 } | |
| 239 | |
| 240 // Tests that the plugin can issue a GET request and receives the data when | |
| 241 // it comes back synchronously. | |
| 242 TEST_F(ChromePluginTest, CanMakeGETRequestSync) { | |
| 243 // test_url_1 has a synchronous response | |
| 244 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
| 245 "GET", net::URLRequestTestJob::test_url_1())); | |
| 246 | |
| 247 // Note: we must add this task after we make the request, so that | |
| 248 // net::URLRequestTestJob's StartAsync task is added and run first. | |
| 249 MessageLoop::current()->PostTask(FROM_HERE, | |
| 250 NewRunnableFunction(&ProcessAllPendingMessages)); | |
| 251 MessageLoop::current()->Run(); | |
| 252 } | |
| 253 | |
| 254 // Tests that the plugin can issue a GET request and receives the data when | |
| 255 // it comes back asynchronously. | |
| 256 TEST_F(ChromePluginTest, CanMakeGETRequestAsync) { | |
| 257 // test_url_2 has an asynchronous response | |
| 258 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
| 259 "GET", net::URLRequestTestJob::test_url_2())); | |
| 260 | |
| 261 // Note: we must add this task after we make the request, so that | |
| 262 // net::URLRequestTestJob's StartAsync task is added and run first. | |
| 263 MessageLoop::current()->PostTask(FROM_HERE, | |
| 264 NewRunnableFunction(&ProcessAllPendingMessages)); | |
| 265 MessageLoop::current()->Run(); | |
| 266 } | |
| 267 | |
| 268 // Tests that the plugin can issue a POST request. | |
| 269 TEST_F(ChromePluginTest, CanMakePOSTRequest) { | |
| 270 net::TestServer test_server(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)); | |
| 271 ASSERT_TRUE(test_server.Start()); | |
| 272 | |
| 273 GURL url = test_server.GetURL("echo"); | |
| 274 | |
| 275 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request("POST", url)); | |
| 276 | |
| 277 // Note: we must add this task after we make the request, so that | |
| 278 // net::URLRequestTestJob's StartAsync task is added and run first. | |
| 279 MessageLoop::current()->PostTask(FROM_HERE, | |
| 280 NewRunnableFunction(&ProcessAllPendingMessages)); | |
| 281 MessageLoop::current()->Run(); | |
| 282 } | |
| 283 | |
| 284 // Tests that the plugin does not intercept its own requests. | |
| 285 TEST_F(ChromePluginTest, DoesNotInterceptOwnRequest) { | |
| 286 const TestResponsePayload& payload = kChromeTestPluginPayloads[0]; | |
| 287 | |
| 288 EXPECT_EQ(CPERR_SUCCESS, test_funcs_.test_make_request( | |
| 289 "GET", GURL(payload.url))); | |
| 290 | |
| 291 MessageLoop::current()->Run(); | |
| 292 } | |
| 293 | |
| 294 } // namespace | |
| OLD | NEW |