| OLD | NEW |
| (Empty) |
| 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 <queue> | |
| 6 #include <map> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/callback.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/json/json_string_value_serializer.h" | |
| 12 #include "base/memory/weak_ptr.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/stl_util.h" | |
| 16 #include "base/utf_string_conversions.h" | |
| 17 #include "chrome/browser/content_settings/cookie_settings.h" | |
| 18 #include "chrome/browser/extensions/api/webrequest/webrequest_api.h" | |
| 19 #include "chrome/browser/extensions/api/webrequest/webrequest_api_constants.h" | |
| 20 #include "chrome/browser/extensions/api/webrequest/webrequest_api_helpers.h" | |
| 21 #include "chrome/browser/extensions/extension_event_router_forwarder.h" | |
| 22 #include "chrome/browser/net/chrome_network_delegate.h" | |
| 23 #include "chrome/browser/prefs/pref_member.h" | |
| 24 #include "chrome/common/extensions/extension_messages.h" | |
| 25 #include "chrome/common/pref_names.h" | |
| 26 #include "chrome/test/base/testing_browser_process.h" | |
| 27 #include "chrome/test/base/testing_pref_service.h" | |
| 28 #include "chrome/test/base/testing_profile.h" | |
| 29 #include "content/test/test_browser_thread.h" | |
| 30 #include "net/base/auth.h" | |
| 31 #include "net/base/net_util.h" | |
| 32 #include "net/url_request/url_request_test_util.h" | |
| 33 #include "testing/gtest/include/gtest/gtest.h" | |
| 34 | |
| 35 namespace helpers = extension_webrequest_api_helpers; | |
| 36 namespace keys = extension_webrequest_api_constants; | |
| 37 | |
| 38 using helpers::CalculateOnAuthRequiredDelta; | |
| 39 using helpers::CalculateOnBeforeRequestDelta; | |
| 40 using helpers::CalculateOnBeforeSendHeadersDelta; | |
| 41 using helpers::CalculateOnHeadersReceivedDelta; | |
| 42 using helpers::CharListToString; | |
| 43 using helpers::EventLogEntries; | |
| 44 using helpers::EventResponseDelta; | |
| 45 using helpers::EventResponseDeltas; | |
| 46 using helpers::EventResponseDeltas; | |
| 47 using helpers::InDecreasingExtensionInstallationTimeOrder; | |
| 48 using helpers::MergeCancelOfResponses; | |
| 49 using helpers::MergeOnBeforeRequestResponses; | |
| 50 using helpers::ResponseHeader; | |
| 51 using helpers::ResponseHeaders; | |
| 52 using helpers::StringToCharList; | |
| 53 | |
| 54 namespace { | |
| 55 static void EventHandledOnIOThread( | |
| 56 void* profile, | |
| 57 const std::string& extension_id, | |
| 58 const std::string& event_name, | |
| 59 const std::string& sub_event_name, | |
| 60 uint64 request_id, | |
| 61 ExtensionWebRequestEventRouter::EventResponse* response) { | |
| 62 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled( | |
| 63 profile, extension_id, event_name, sub_event_name, request_id, | |
| 64 response); | |
| 65 } | |
| 66 | |
| 67 // Searches |key| in |collection| by iterating over its elements and returns | |
| 68 // true if found. | |
| 69 template <typename Collection, typename Key> | |
| 70 bool Contains(const Collection& collection, const Key& key) { | |
| 71 return std::find(collection.begin(), collection.end(), key) != | |
| 72 collection.end(); | |
| 73 } | |
| 74 | |
| 75 } // namespace | |
| 76 | |
| 77 // A mock event router that responds to events with a pre-arranged queue of | |
| 78 // Tasks. | |
| 79 class TestIPCSender : public IPC::Message::Sender { | |
| 80 public: | |
| 81 typedef std::list<linked_ptr<IPC::Message> > SentMessages; | |
| 82 | |
| 83 // Adds a Task to the queue. We will fire these in order as events are | |
| 84 // dispatched. | |
| 85 void PushTask(const base::Closure& task) { | |
| 86 task_queue_.push(task); | |
| 87 } | |
| 88 | |
| 89 size_t GetNumTasks() { return task_queue_.size(); } | |
| 90 | |
| 91 SentMessages::const_iterator sent_begin() const { | |
| 92 return sent_messages_.begin(); | |
| 93 } | |
| 94 | |
| 95 SentMessages::const_iterator sent_end() const { | |
| 96 return sent_messages_.end(); | |
| 97 } | |
| 98 | |
| 99 private: | |
| 100 // IPC::Message::Sender | |
| 101 virtual bool Send(IPC::Message* message) { | |
| 102 EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type()); | |
| 103 | |
| 104 EXPECT_FALSE(task_queue_.empty()); | |
| 105 MessageLoop::current()->PostTask(FROM_HERE, task_queue_.front()); | |
| 106 task_queue_.pop(); | |
| 107 | |
| 108 sent_messages_.push_back(linked_ptr<IPC::Message>(message)); | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 std::queue<base::Closure> task_queue_; | |
| 113 SentMessages sent_messages_; | |
| 114 }; | |
| 115 | |
| 116 class ExtensionWebRequestTest : public testing::Test { | |
| 117 public: | |
| 118 ExtensionWebRequestTest() | |
| 119 : ui_thread_(content::BrowserThread::UI, &message_loop_), | |
| 120 io_thread_(content::BrowserThread::IO, &message_loop_) {} | |
| 121 | |
| 122 protected: | |
| 123 virtual void SetUp() OVERRIDE { | |
| 124 event_router_ = new ExtensionEventRouterForwarder(); | |
| 125 enable_referrers_.Init( | |
| 126 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL); | |
| 127 network_delegate_.reset(new ChromeNetworkDelegate( | |
| 128 event_router_.get(), NULL, NULL, &profile_, | |
| 129 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_)); | |
| 130 context_ = new TestURLRequestContext(); | |
| 131 context_->set_network_delegate(network_delegate_.get()); | |
| 132 } | |
| 133 | |
| 134 MessageLoopForIO message_loop_; | |
| 135 content::TestBrowserThread ui_thread_; | |
| 136 content::TestBrowserThread io_thread_; | |
| 137 TestingProfile profile_; | |
| 138 TestDelegate delegate_; | |
| 139 BooleanPrefMember enable_referrers_; | |
| 140 TestIPCSender ipc_sender_; | |
| 141 scoped_refptr<ExtensionEventRouterForwarder> event_router_; | |
| 142 scoped_refptr<ExtensionInfoMap> extension_info_map_; | |
| 143 scoped_ptr<ChromeNetworkDelegate> network_delegate_; | |
| 144 scoped_refptr<TestURLRequestContext> context_; | |
| 145 }; | |
| 146 | |
| 147 // Tests that we handle disagreements among extensions about responses to | |
| 148 // blocking events (redirection) by choosing the response from the | |
| 149 // most-recently-installed extension. | |
| 150 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) { | |
| 151 std::string extension1_id("1"); | |
| 152 std::string extension2_id("2"); | |
| 153 ExtensionWebRequestEventRouter::RequestFilter filter; | |
| 154 const std::string kEventName(keys::kOnBeforeRequest); | |
| 155 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); | |
| 156 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 157 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", | |
| 158 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 159 ipc_sender_factory.GetWeakPtr()); | |
| 160 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 161 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", | |
| 162 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 163 ipc_sender_factory.GetWeakPtr()); | |
| 164 | |
| 165 GURL redirect_url("about:redirected"); | |
| 166 GURL not_chosen_redirect_url("about:not_chosen"); | |
| 167 | |
| 168 net::URLRequest request(GURL("about:blank"), &delegate_); | |
| 169 request.set_context(context_); | |
| 170 { | |
| 171 // onBeforeRequest will be dispatched twice initially. The second response - | |
| 172 // the redirect - should win, since it has a later |install_time|. The | |
| 173 // redirect will dispatch another pair of onBeforeRequest. There, the first | |
| 174 // response should win (later |install_time|). | |
| 175 ExtensionWebRequestEventRouter::EventResponse* response = NULL; | |
| 176 | |
| 177 // Extension1 response. Arrives first, but ignored due to install_time. | |
| 178 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 179 extension1_id, base::Time::FromDoubleT(1)); | |
| 180 response->new_url = not_chosen_redirect_url; | |
| 181 ipc_sender_.PushTask( | |
| 182 base::Bind(&EventHandledOnIOThread, | |
| 183 &profile_, extension1_id, kEventName, kEventName + "/1", | |
| 184 request.identifier(), response)); | |
| 185 | |
| 186 // Extension2 response. Arrives second, and chosen because of install_time. | |
| 187 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 188 extension2_id, base::Time::FromDoubleT(2)); | |
| 189 response->new_url = redirect_url; | |
| 190 ipc_sender_.PushTask( | |
| 191 base::Bind(&EventHandledOnIOThread, | |
| 192 &profile_, extension2_id, kEventName, kEventName + "/2", | |
| 193 request.identifier(), response)); | |
| 194 | |
| 195 // Extension2 response to the redirected URL. Arrives first, and chosen. | |
| 196 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 197 extension2_id, base::Time::FromDoubleT(2)); | |
| 198 ipc_sender_.PushTask( | |
| 199 base::Bind(&EventHandledOnIOThread, | |
| 200 &profile_, extension2_id, kEventName, kEventName + "/2", | |
| 201 request.identifier(), response)); | |
| 202 | |
| 203 // Extension1 response to the redirected URL. Arrives second, and ignored. | |
| 204 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 205 extension1_id, base::Time::FromDoubleT(1)); | |
| 206 ipc_sender_.PushTask( | |
| 207 base::Bind(&EventHandledOnIOThread, | |
| 208 &profile_, extension1_id, kEventName, kEventName + "/1", | |
| 209 request.identifier(), response)); | |
| 210 | |
| 211 request.Start(); | |
| 212 MessageLoop::current()->Run(); | |
| 213 | |
| 214 EXPECT_TRUE(!request.is_pending()); | |
| 215 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); | |
| 216 EXPECT_EQ(0, request.status().error()); | |
| 217 EXPECT_EQ(redirect_url, request.url()); | |
| 218 EXPECT_EQ(2U, request.url_chain().size()); | |
| 219 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); | |
| 220 } | |
| 221 | |
| 222 // Now test the same thing but the extensions answer in reverse order. | |
| 223 net::URLRequest request2(GURL("about:blank"), &delegate_); | |
| 224 request2.set_context(context_); | |
| 225 { | |
| 226 ExtensionWebRequestEventRouter::EventResponse* response = NULL; | |
| 227 | |
| 228 // Extension2 response. Arrives first, and chosen because of install_time. | |
| 229 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 230 extension2_id, base::Time::FromDoubleT(2)); | |
| 231 response->new_url = redirect_url; | |
| 232 ipc_sender_.PushTask( | |
| 233 base::Bind(&EventHandledOnIOThread, | |
| 234 &profile_, extension2_id, kEventName, kEventName + "/2", | |
| 235 request2.identifier(), response)); | |
| 236 | |
| 237 // Extension1 response. Arrives second, but ignored due to install_time. | |
| 238 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 239 extension1_id, base::Time::FromDoubleT(1)); | |
| 240 response->new_url = not_chosen_redirect_url; | |
| 241 ipc_sender_.PushTask( | |
| 242 base::Bind(&EventHandledOnIOThread, | |
| 243 &profile_, extension1_id, kEventName, kEventName + "/1", | |
| 244 request2.identifier(), response)); | |
| 245 | |
| 246 // Extension2 response to the redirected URL. Arrives first, and chosen. | |
| 247 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 248 extension2_id, base::Time::FromDoubleT(2)); | |
| 249 ipc_sender_.PushTask( | |
| 250 base::Bind(&EventHandledOnIOThread, | |
| 251 &profile_, extension2_id, kEventName, kEventName + "/2", | |
| 252 request2.identifier(), response)); | |
| 253 | |
| 254 // Extension1 response to the redirected URL. Arrives second, and ignored. | |
| 255 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 256 extension1_id, base::Time::FromDoubleT(1)); | |
| 257 ipc_sender_.PushTask( | |
| 258 base::Bind(&EventHandledOnIOThread, | |
| 259 &profile_, extension1_id, kEventName, kEventName + "/1", | |
| 260 request2.identifier(), response)); | |
| 261 | |
| 262 request2.Start(); | |
| 263 MessageLoop::current()->Run(); | |
| 264 | |
| 265 EXPECT_TRUE(!request2.is_pending()); | |
| 266 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request2.status().status()); | |
| 267 EXPECT_EQ(0, request2.status().error()); | |
| 268 EXPECT_EQ(redirect_url, request2.url()); | |
| 269 EXPECT_EQ(2U, request2.url_chain().size()); | |
| 270 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); | |
| 271 } | |
| 272 | |
| 273 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 274 &profile_, extension1_id, kEventName + "/1"); | |
| 275 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 276 &profile_, extension2_id, kEventName + "/2"); | |
| 277 } | |
| 278 | |
| 279 // Test that a request is canceled if this is requested by any extension | |
| 280 // regardless whether it is the extension with the highest precedence. | |
| 281 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceCancel) { | |
| 282 std::string extension1_id("1"); | |
| 283 std::string extension2_id("2"); | |
| 284 ExtensionWebRequestEventRouter::RequestFilter filter; | |
| 285 const std::string kEventName(keys::kOnBeforeRequest); | |
| 286 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); | |
| 287 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 288 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", | |
| 289 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 290 ipc_sender_factory.GetWeakPtr()); | |
| 291 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 292 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", | |
| 293 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 294 ipc_sender_factory.GetWeakPtr()); | |
| 295 | |
| 296 GURL request_url("about:blank"); | |
| 297 net::URLRequest request(request_url, &delegate_); | |
| 298 request.set_context(context_); | |
| 299 | |
| 300 // onBeforeRequest will be dispatched twice. The second response - | |
| 301 // the redirect - would win, since it has a later |install_time|, but | |
| 302 // the first response takes precedence because cancel >> redirect. | |
| 303 GURL redirect_url("about:redirected"); | |
| 304 ExtensionWebRequestEventRouter::EventResponse* response = NULL; | |
| 305 | |
| 306 // Extension1 response. Arrives first, would be ignored in principle due to | |
| 307 // install_time but "cancel" always wins. | |
| 308 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 309 extension1_id, base::Time::FromDoubleT(1)); | |
| 310 response->cancel = true; | |
| 311 ipc_sender_.PushTask( | |
| 312 base::Bind(&EventHandledOnIOThread, | |
| 313 &profile_, extension1_id, kEventName, kEventName + "/1", | |
| 314 request.identifier(), response)); | |
| 315 | |
| 316 // Extension2 response. Arrives second, but has higher precedence | |
| 317 // due to its later install_time. | |
| 318 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 319 extension2_id, base::Time::FromDoubleT(2)); | |
| 320 response->new_url = redirect_url; | |
| 321 ipc_sender_.PushTask( | |
| 322 base::Bind(&EventHandledOnIOThread, | |
| 323 &profile_, extension2_id, kEventName, kEventName + "/2", | |
| 324 request.identifier(), response)); | |
| 325 | |
| 326 request.Start(); | |
| 327 | |
| 328 MessageLoop::current()->Run(); | |
| 329 | |
| 330 EXPECT_TRUE(!request.is_pending()); | |
| 331 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); | |
| 332 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, request.status().error()); | |
| 333 EXPECT_EQ(request_url, request.url()); | |
| 334 EXPECT_EQ(1U, request.url_chain().size()); | |
| 335 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); | |
| 336 | |
| 337 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 338 &profile_, extension1_id, kEventName + "/1"); | |
| 339 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 340 &profile_, extension2_id, kEventName + "/2"); | |
| 341 } | |
| 342 | |
| 343 TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) { | |
| 344 // We subscribe to OnBeforeRequest and OnErrorOccurred. | |
| 345 // While the OnBeforeRequest handler is blocked, we cancel the request. | |
| 346 // We verify that the response of the blocked OnBeforeRequest handler | |
| 347 // is ignored. | |
| 348 | |
| 349 std::string extension_id("1"); | |
| 350 ExtensionWebRequestEventRouter::RequestFilter filter; | |
| 351 | |
| 352 // Subscribe to OnBeforeRequest and OnErrorOccurred. | |
| 353 const std::string kEventName(keys::kOnBeforeRequest); | |
| 354 const std::string kEventName2(keys::kOnErrorOccurred); | |
| 355 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); | |
| 356 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 357 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", | |
| 358 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 359 ipc_sender_factory.GetWeakPtr()); | |
| 360 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 361 &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1", | |
| 362 filter, 0, ipc_sender_factory.GetWeakPtr()); | |
| 363 | |
| 364 GURL request_url("about:blank"); | |
| 365 net::URLRequest request(request_url, &delegate_); | |
| 366 request.set_context(context_); | |
| 367 | |
| 368 ExtensionWebRequestEventRouter::EventResponse* response = NULL; | |
| 369 | |
| 370 // Extension response for the OnBeforeRequest handler. This should not be | |
| 371 // processed because request is canceled before the handler responds. | |
| 372 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 373 extension_id, base::Time::FromDoubleT(1)); | |
| 374 GURL redirect_url("about:redirected"); | |
| 375 response->new_url = redirect_url; | |
| 376 ipc_sender_.PushTask( | |
| 377 base::Bind(&EventHandledOnIOThread, | |
| 378 &profile_, extension_id, kEventName, kEventName + "/1", | |
| 379 request.identifier(), response)); | |
| 380 | |
| 381 // Extension response for OnErrorOccurred: Terminate the message loop. | |
| 382 ipc_sender_.PushTask( | |
| 383 base::Bind(&MessageLoop::PostTask, | |
| 384 base::Unretained(MessageLoop::current()), | |
| 385 FROM_HERE, MessageLoop::QuitClosure() | |
| 386 )); | |
| 387 | |
| 388 request.Start(); | |
| 389 // request.Start() will have submitted OnBeforeRequest by the time we cancel. | |
| 390 request.Cancel(); | |
| 391 MessageLoop::current()->Run(); | |
| 392 | |
| 393 EXPECT_TRUE(!request.is_pending()); | |
| 394 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status()); | |
| 395 EXPECT_EQ(net::ERR_ABORTED, request.status().error()); | |
| 396 EXPECT_EQ(request_url, request.url()); | |
| 397 EXPECT_EQ(1U, request.url_chain().size()); | |
| 398 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); | |
| 399 | |
| 400 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 401 &profile_, extension_id, kEventName + "/1"); | |
| 402 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 403 &profile_, extension_id, kEventName2 + "/1"); | |
| 404 } | |
| 405 | |
| 406 struct HeaderModificationTest_Header { | |
| 407 const char* name; | |
| 408 const char* value; | |
| 409 }; | |
| 410 | |
| 411 struct HeaderModificationTest_Modification { | |
| 412 enum Type { | |
| 413 SET, | |
| 414 REMOVE | |
| 415 }; | |
| 416 | |
| 417 int extension_id; | |
| 418 Type type; | |
| 419 const char* key; | |
| 420 const char* value; | |
| 421 }; | |
| 422 | |
| 423 struct HeaderModificationTest { | |
| 424 int before_size; | |
| 425 HeaderModificationTest_Header before[10]; | |
| 426 int modification_size; | |
| 427 HeaderModificationTest_Modification modification[10]; | |
| 428 int after_size; | |
| 429 HeaderModificationTest_Header after[10]; | |
| 430 }; | |
| 431 | |
| 432 class ExtensionWebRequestHeaderModificationTest : | |
| 433 public testing::TestWithParam<HeaderModificationTest> { | |
| 434 public: | |
| 435 ExtensionWebRequestHeaderModificationTest() | |
| 436 : ui_thread_(content::BrowserThread::UI, &message_loop_), | |
| 437 io_thread_(content::BrowserThread::IO, &message_loop_) {} | |
| 438 | |
| 439 protected: | |
| 440 virtual void SetUp() { | |
| 441 event_router_ = new ExtensionEventRouterForwarder(); | |
| 442 enable_referrers_.Init( | |
| 443 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL); | |
| 444 network_delegate_.reset(new ChromeNetworkDelegate( | |
| 445 event_router_.get(), NULL, NULL, &profile_, | |
| 446 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_)); | |
| 447 context_ = new TestURLRequestContext(); | |
| 448 context_->set_network_delegate(network_delegate_.get()); | |
| 449 } | |
| 450 | |
| 451 MessageLoopForIO message_loop_; | |
| 452 content::TestBrowserThread ui_thread_; | |
| 453 content::TestBrowserThread io_thread_; | |
| 454 TestingProfile profile_; | |
| 455 TestDelegate delegate_; | |
| 456 BooleanPrefMember enable_referrers_; | |
| 457 TestIPCSender ipc_sender_; | |
| 458 scoped_refptr<ExtensionEventRouterForwarder> event_router_; | |
| 459 scoped_refptr<ExtensionInfoMap> extension_info_map_; | |
| 460 scoped_ptr<ChromeNetworkDelegate> network_delegate_; | |
| 461 scoped_refptr<TestURLRequestContext> context_; | |
| 462 }; | |
| 463 | |
| 464 TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) { | |
| 465 std::string extension1_id("1"); | |
| 466 std::string extension2_id("2"); | |
| 467 std::string extension3_id("3"); | |
| 468 ExtensionWebRequestEventRouter::RequestFilter filter; | |
| 469 const std::string kEventName(keys::kOnBeforeSendHeaders); | |
| 470 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); | |
| 471 | |
| 472 // Install two extensions that can modify headers. Extension 2 has | |
| 473 // higher precedence than extension 1. | |
| 474 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 475 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", | |
| 476 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 477 ipc_sender_factory.GetWeakPtr()); | |
| 478 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 479 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", | |
| 480 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, | |
| 481 ipc_sender_factory.GetWeakPtr()); | |
| 482 | |
| 483 // Install one extension that observes the final headers. | |
| 484 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( | |
| 485 &profile_, extension3_id, extension3_id, keys::kOnSendHeaders, | |
| 486 std::string(keys::kOnSendHeaders) + "/3", filter, | |
| 487 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, | |
| 488 ipc_sender_factory.GetWeakPtr()); | |
| 489 | |
| 490 GURL request_url("http://doesnotexist/does_not_exist.html"); | |
| 491 net::URLRequest request(request_url, &delegate_); | |
| 492 request.set_context(context_); | |
| 493 | |
| 494 // Initialize headers available before extensions are notified of the | |
| 495 // onBeforeSendHeaders event. | |
| 496 HeaderModificationTest test = GetParam(); | |
| 497 net::HttpRequestHeaders before_headers; | |
| 498 for (int i = 0; i < test.before_size; ++i) | |
| 499 before_headers.SetHeader(test.before[i].name, test.before[i].value); | |
| 500 request.SetExtraRequestHeaders(before_headers); | |
| 501 | |
| 502 // Gather the modifications to the headers for the respective extensions. | |
| 503 // We assume here that all modifications of one extension are listed | |
| 504 // in a continuous block of |test.modifications_|. | |
| 505 ExtensionWebRequestEventRouter::EventResponse* response = NULL; | |
| 506 for (int i = 0; i < test.modification_size; ++i) { | |
| 507 const HeaderModificationTest_Modification& mod = test.modification[i]; | |
| 508 if (response == NULL) { | |
| 509 response = new ExtensionWebRequestEventRouter::EventResponse( | |
| 510 mod.extension_id == 1 ? extension1_id : extension2_id, | |
| 511 base::Time::FromDoubleT(mod.extension_id)); | |
| 512 response->request_headers.reset(new net::HttpRequestHeaders()); | |
| 513 response->request_headers->MergeFrom(request.extra_request_headers()); | |
| 514 } | |
| 515 | |
| 516 switch (mod.type) { | |
| 517 case HeaderModificationTest_Modification::SET: | |
| 518 response->request_headers->SetHeader(mod.key, mod.value); | |
| 519 break; | |
| 520 case HeaderModificationTest_Modification::REMOVE: | |
| 521 response->request_headers->RemoveHeader(mod.key); | |
| 522 break; | |
| 523 } | |
| 524 | |
| 525 // Trigger the result when this is the last modification statement or | |
| 526 // the block of modifications for the next extension starts. | |
| 527 if (i+1 == test.modification_size || | |
| 528 mod.extension_id != test.modification[i+1].extension_id) { | |
| 529 ipc_sender_.PushTask( | |
| 530 base::Bind(&EventHandledOnIOThread, | |
| 531 &profile_, mod.extension_id == 1 ? extension1_id : extension2_id, | |
| 532 kEventName, kEventName + (mod.extension_id == 1 ? "/1" : "/2"), | |
| 533 request.identifier(), response)); | |
| 534 response = NULL; | |
| 535 } | |
| 536 } | |
| 537 | |
| 538 // Don't do anything for the onSendHeaders message. | |
| 539 ipc_sender_.PushTask(base::Bind(&base::DoNothing)); | |
| 540 | |
| 541 // Note that we mess up the headers slightly: | |
| 542 // request.Start() will first add additional headers (e.g. the User-Agent) | |
| 543 // and then send an event to the extension. When we have prepared our | |
| 544 // answers to the onBeforeSendHeaders events above, these headers did not | |
| 545 // exists and are therefore not listed in the responses. This makes | |
| 546 // them seem deleted. | |
| 547 request.Start(); | |
| 548 MessageLoop::current()->Run(); | |
| 549 | |
| 550 EXPECT_TRUE(!request.is_pending()); | |
| 551 // This cannot succeed as we send the request to a server that does not exist. | |
| 552 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); | |
| 553 EXPECT_EQ(request_url, request.url()); | |
| 554 EXPECT_EQ(1U, request.url_chain().size()); | |
| 555 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); | |
| 556 | |
| 557 // Calculate the expected headers. | |
| 558 net::HttpRequestHeaders expected_headers; | |
| 559 for (int i = 0; i < test.after_size; ++i) { | |
| 560 expected_headers.SetHeader(test.after[i].name, | |
| 561 test.after[i].value); | |
| 562 } | |
| 563 | |
| 564 // Counter for the number of observed onSendHeaders events. | |
| 565 int num_headers_observed = 0; | |
| 566 | |
| 567 // Search the onSendHeaders signal in the IPC messages and check that | |
| 568 // it contained the correct headers. | |
| 569 TestIPCSender::SentMessages::const_iterator i; | |
| 570 for (i = ipc_sender_.sent_begin(); i != ipc_sender_.sent_end(); ++i) { | |
| 571 IPC::Message* message = i->get(); | |
| 572 if (ExtensionMsg_MessageInvoke::ID != message->type()) | |
| 573 continue; | |
| 574 ExtensionMsg_MessageInvoke::Param message_tuple; | |
| 575 ExtensionMsg_MessageInvoke::Read(message, &message_tuple); | |
| 576 ListValue& args = message_tuple.c; | |
| 577 | |
| 578 std::string event_name; | |
| 579 if (!args.GetString(0, &event_name) || | |
| 580 event_name != std::string(keys::kOnSendHeaders) + "/3") { | |
| 581 continue; | |
| 582 } | |
| 583 | |
| 584 std::string event_arg_string; | |
| 585 ASSERT_TRUE(args.GetString(1, &event_arg_string)); | |
| 586 | |
| 587 scoped_ptr<Value> event_arg_value( | |
| 588 JSONStringValueSerializer(event_arg_string).Deserialize(NULL, NULL)); | |
| 589 ASSERT_TRUE(event_arg_value.get() && | |
| 590 event_arg_value->IsType(Value::TYPE_LIST)); | |
| 591 | |
| 592 DictionaryValue* event_arg_dict = NULL; | |
| 593 ASSERT_TRUE( | |
| 594 static_cast<ListValue*>(event_arg_value.get())->GetDictionary( | |
| 595 0, &event_arg_dict)); | |
| 596 | |
| 597 ListValue* request_headers = NULL; | |
| 598 ASSERT_TRUE(event_arg_dict->GetList(keys::kRequestHeadersKey, | |
| 599 &request_headers)); | |
| 600 | |
| 601 net::HttpRequestHeaders observed_headers; | |
| 602 for (size_t j = 0; j < request_headers->GetSize(); ++j) { | |
| 603 DictionaryValue* header = NULL; | |
| 604 ASSERT_TRUE(request_headers->GetDictionary(j, &header)); | |
| 605 std::string key; | |
| 606 std::string value; | |
| 607 ASSERT_TRUE(header->GetString(keys::kHeaderNameKey, &key)); | |
| 608 ASSERT_TRUE(header->GetString(keys::kHeaderValueKey, &value)); | |
| 609 observed_headers.SetHeader(key, value); | |
| 610 } | |
| 611 | |
| 612 EXPECT_EQ(expected_headers.ToString(), observed_headers.ToString()); | |
| 613 ++num_headers_observed; | |
| 614 } | |
| 615 EXPECT_EQ(1, num_headers_observed); | |
| 616 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 617 &profile_, extension1_id, kEventName + "/1"); | |
| 618 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 619 &profile_, extension2_id, kEventName + "/2"); | |
| 620 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | |
| 621 &profile_, extension3_id, std::string(keys::kOnSendHeaders) + "/3"); | |
| 622 }; | |
| 623 | |
| 624 namespace { | |
| 625 | |
| 626 void TestInitFromValue(const std::string& values, bool expected_return_code, | |
| 627 int expected_extra_info_spec) { | |
| 628 // Create a ListValue of strings. | |
| 629 std::vector<std::string> split_values; | |
| 630 scoped_ptr<base::ListValue> list_value(new base::ListValue()); | |
| 631 size_t num_values = Tokenize(values, ",", &split_values); | |
| 632 for (size_t i = 0; i < num_values ; ++i) | |
| 633 list_value->Append(new base::StringValue(split_values[i])); | |
| 634 int actual_info_spec; | |
| 635 bool actual_return_code = | |
| 636 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue( | |
| 637 *list_value, &actual_info_spec); | |
| 638 EXPECT_EQ(expected_return_code, actual_return_code); | |
| 639 if (expected_return_code) | |
| 640 EXPECT_EQ(expected_extra_info_spec, actual_info_spec); | |
| 641 } | |
| 642 | |
| 643 } | |
| 644 TEST_F(ExtensionWebRequestTest, InitFromValue) { | |
| 645 TestInitFromValue("", true, 0); | |
| 646 | |
| 647 // Single valid values. | |
| 648 TestInitFromValue( | |
| 649 "requestHeaders", | |
| 650 true, | |
| 651 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS); | |
| 652 TestInitFromValue( | |
| 653 "responseHeaders", | |
| 654 true, | |
| 655 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS); | |
| 656 TestInitFromValue( | |
| 657 "blocking", | |
| 658 true, | |
| 659 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); | |
| 660 TestInitFromValue( | |
| 661 "asyncBlocking", | |
| 662 true, | |
| 663 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING); | |
| 664 | |
| 665 // Multiple valid values are bitwise-or'ed. | |
| 666 TestInitFromValue( | |
| 667 "requestHeaders,blocking", | |
| 668 true, | |
| 669 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS | | |
| 670 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); | |
| 671 | |
| 672 // Any invalid values lead to a bad parse. | |
| 673 TestInitFromValue("invalidValue", false, 0); | |
| 674 TestInitFromValue("blocking,invalidValue", false, 0); | |
| 675 TestInitFromValue("invalidValue1,invalidValue2", false, 0); | |
| 676 | |
| 677 // BLOCKING and ASYNC_BLOCKING are mutually exclusive. | |
| 678 TestInitFromValue("blocking,asyncBlocking", false, 0); | |
| 679 } | |
| 680 | |
| 681 namespace { | |
| 682 | |
| 683 const HeaderModificationTest_Modification::Type SET = | |
| 684 HeaderModificationTest_Modification::SET; | |
| 685 const HeaderModificationTest_Modification::Type REMOVE = | |
| 686 HeaderModificationTest_Modification::REMOVE; | |
| 687 | |
| 688 HeaderModificationTest kTests[] = { | |
| 689 // Check that extension 2 always wins when settings the same header. | |
| 690 { | |
| 691 // Headers before test. | |
| 692 2, { {"header1", "value1"}, | |
| 693 {"header2", "value2"} }, | |
| 694 // Modifications in test. | |
| 695 2, { {1, SET, "header1", "foo"}, | |
| 696 {2, SET, "header1", "bar"} }, | |
| 697 // Headers after test. | |
| 698 2, { {"header1", "bar"}, | |
| 699 {"header2", "value2"} } | |
| 700 }, | |
| 701 // Same as before in reverse execution order. | |
| 702 { | |
| 703 // Headers before test. | |
| 704 2, { {"header1", "value1"}, | |
| 705 {"header2", "value2"} }, | |
| 706 // Modifications in test. | |
| 707 2, { {2, SET, "header1", "bar"}, | |
| 708 {1, SET, "header1", "foo"} }, | |
| 709 // Headers after test. | |
| 710 2, { {"header1", "bar"}, | |
| 711 {"header2", "value2"} } | |
| 712 }, | |
| 713 // Check that two extensions can modify different headers that do not | |
| 714 // conflict. | |
| 715 { | |
| 716 // Headers before test. | |
| 717 2, { {"header1", "value1"}, | |
| 718 {"header2", "value2"} }, | |
| 719 // Modifications in test. | |
| 720 2, { {1, SET, "header1", "foo"}, | |
| 721 {2, SET, "header2", "bar"} }, | |
| 722 // Headers after test. | |
| 723 2, { {"header1", "foo"}, | |
| 724 {"header2", "bar"} } | |
| 725 }, | |
| 726 // Check insert/delete conflict. | |
| 727 { | |
| 728 // Headers before test. | |
| 729 1, { {"header1", "value1"} }, | |
| 730 // Modifications in test. | |
| 731 2, { {1, SET, "header1", "foo"}, | |
| 732 {2, REMOVE, "header1", NULL} }, | |
| 733 // Headers after test. | |
| 734 0, { } | |
| 735 }, | |
| 736 { | |
| 737 // Headers before test. | |
| 738 1, { {"header1", "value1"} }, | |
| 739 // Modifications in test. | |
| 740 2, { {2, REMOVE, "header1", NULL}, | |
| 741 {1, SET, "header1", "foo"} }, | |
| 742 // Headers after test. | |
| 743 0, {} | |
| 744 }, | |
| 745 { | |
| 746 // Headers before test. | |
| 747 1, { {"header1", "value1"} }, | |
| 748 // Modifications in test. | |
| 749 2, { {1, REMOVE, "header1", NULL}, | |
| 750 {2, SET, "header1", "foo"} }, | |
| 751 // Headers after test. | |
| 752 1, { {"header1", "foo"} } | |
| 753 }, | |
| 754 { | |
| 755 // Headers before test. | |
| 756 1, { {"header1", "value1"} }, | |
| 757 // Modifications in test. | |
| 758 2, { {2, SET, "header1", "foo"}, | |
| 759 {1, REMOVE, "header1", NULL} }, | |
| 760 // Headers after test. | |
| 761 1, { {"header1", "foo"} } | |
| 762 }, | |
| 763 // Check that edits are atomic (i.e. either all edit requests of an | |
| 764 // extension are executed or none). | |
| 765 { | |
| 766 // Headers before test. | |
| 767 0, { }, | |
| 768 // Modifications in test. | |
| 769 3, { {1, SET, "header1", "value1"}, | |
| 770 {1, SET, "header2", "value2"}, | |
| 771 {2, SET, "header1", "foo"} }, | |
| 772 // Headers after test. | |
| 773 1, { {"header1", "foo"} } // set(header2) is ignored | |
| 774 }, | |
| 775 // Check that identical edits do not conflict (set(header2) would be ignored | |
| 776 // if set(header1) were considered a conflict). | |
| 777 { | |
| 778 // Headers before test. | |
| 779 0, { }, | |
| 780 // Modifications in test. | |
| 781 3, { {1, SET, "header1", "value2"}, | |
| 782 {1, SET, "header2", "foo"}, | |
| 783 {2, SET, "header1", "value2"} }, | |
| 784 // Headers after test. | |
| 785 2, { {"header1", "value2"}, | |
| 786 {"header2", "foo"} } | |
| 787 }, | |
| 788 // Check that identical deletes do not conflict (set(header2) would be ignored | |
| 789 // if delete(header1) were considered a conflict). | |
| 790 { | |
| 791 // Headers before test. | |
| 792 1, { {"header1", "value1"} }, | |
| 793 // Modifications in test. | |
| 794 3, { {1, REMOVE, "header1", NULL}, | |
| 795 {1, SET, "header2", "foo"}, | |
| 796 {2, REMOVE, "header1", NULL} }, | |
| 797 // Headers after test. | |
| 798 1, { {"header2", "foo"} } | |
| 799 }, | |
| 800 // Check that setting a value to an identical value is not considered an | |
| 801 // edit operation that can conflict. | |
| 802 { | |
| 803 // Headers before test. | |
| 804 1, { {"header1", "value1"} }, | |
| 805 // Modifications in test. | |
| 806 3, { {1, SET, "header1", "foo"}, | |
| 807 {1, SET, "header2", "bar"}, | |
| 808 {2, SET, "header1", "value1"} }, | |
| 809 // Headers after test. | |
| 810 2, { {"header1", "foo"}, | |
| 811 {"header2", "bar"} } | |
| 812 }, | |
| 813 }; | |
| 814 | |
| 815 INSTANTIATE_TEST_CASE_P( | |
| 816 ExtensionWebRequest, | |
| 817 ExtensionWebRequestHeaderModificationTest, | |
| 818 ::testing::ValuesIn(kTests)); | |
| 819 | |
| 820 } // namespace | |
| 821 | |
| 822 | |
| 823 TEST(ExtensionWebRequestHelpersTest, | |
| 824 TestInDecreasingExtensionInstallationTimeOrder) { | |
| 825 linked_ptr<EventResponseDelta> a( | |
| 826 new EventResponseDelta("ext_1", base::Time::FromInternalValue(0))); | |
| 827 linked_ptr<EventResponseDelta> b( | |
| 828 new EventResponseDelta("ext_2", base::Time::FromInternalValue(1000))); | |
| 829 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, a)); | |
| 830 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, b)); | |
| 831 EXPECT_TRUE(InDecreasingExtensionInstallationTimeOrder(b, a)); | |
| 832 } | |
| 833 | |
| 834 TEST(ExtensionWebRequestHelpersTest, TestStringToCharList) { | |
| 835 ListValue list_value; | |
| 836 list_value.Append(Value::CreateIntegerValue('1')); | |
| 837 list_value.Append(Value::CreateIntegerValue('2')); | |
| 838 list_value.Append(Value::CreateIntegerValue('3')); | |
| 839 list_value.Append(Value::CreateIntegerValue(0xFE)); | |
| 840 list_value.Append(Value::CreateIntegerValue(0xD1)); | |
| 841 | |
| 842 unsigned char char_value[] = {'1', '2', '3', 0xFE, 0xD1}; | |
| 843 std::string string_value(reinterpret_cast<char *>(char_value), 5); | |
| 844 | |
| 845 scoped_ptr<ListValue> converted_list(StringToCharList(string_value)); | |
| 846 EXPECT_TRUE(list_value.Equals(converted_list.get())); | |
| 847 | |
| 848 std::string converted_string; | |
| 849 EXPECT_TRUE(CharListToString(&list_value, &converted_string)); | |
| 850 EXPECT_EQ(string_value, converted_string); | |
| 851 } | |
| 852 | |
| 853 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeRequestDelta) { | |
| 854 const bool cancel = true; | |
| 855 const GURL localhost("http://localhost"); | |
| 856 scoped_ptr<EventResponseDelta> delta( | |
| 857 CalculateOnBeforeRequestDelta("extid", base::Time::Now(), | |
| 858 cancel, localhost)); | |
| 859 ASSERT_TRUE(delta.get()); | |
| 860 EXPECT_TRUE(delta->cancel); | |
| 861 EXPECT_EQ(localhost, delta->new_url); | |
| 862 } | |
| 863 | |
| 864 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeSendHeadersDelta) { | |
| 865 const bool cancel = true; | |
| 866 std::string value; | |
| 867 net::HttpRequestHeaders old_headers; | |
| 868 old_headers.AddHeadersFromString("key1: value1\r\n" | |
| 869 "key2: value2\r\n"); | |
| 870 | |
| 871 // Test adding a header. | |
| 872 net::HttpRequestHeaders new_headers_added; | |
| 873 new_headers_added.AddHeadersFromString("key1: value1\r\n" | |
| 874 "key3: value3\r\n" | |
| 875 "key2: value2\r\n"); | |
| 876 scoped_ptr<EventResponseDelta> delta_added( | |
| 877 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, | |
| 878 &old_headers, &new_headers_added)); | |
| 879 ASSERT_TRUE(delta_added.get()); | |
| 880 EXPECT_TRUE(delta_added->cancel); | |
| 881 ASSERT_TRUE(delta_added->modified_request_headers.GetHeader("key3", &value)); | |
| 882 EXPECT_EQ("value3", value); | |
| 883 | |
| 884 // Test deleting a header. | |
| 885 net::HttpRequestHeaders new_headers_deleted; | |
| 886 new_headers_deleted.AddHeadersFromString("key1: value1\r\n"); | |
| 887 scoped_ptr<EventResponseDelta> delta_deleted( | |
| 888 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, | |
| 889 &old_headers, &new_headers_deleted)); | |
| 890 ASSERT_TRUE(delta_deleted.get()); | |
| 891 ASSERT_EQ(1u, delta_deleted->deleted_request_headers.size()); | |
| 892 ASSERT_EQ("key2", delta_deleted->deleted_request_headers.front()); | |
| 893 | |
| 894 // Test modifying a header. | |
| 895 net::HttpRequestHeaders new_headers_modified; | |
| 896 new_headers_modified.AddHeadersFromString("key1: value1\r\n" | |
| 897 "key2: value3\r\n"); | |
| 898 scoped_ptr<EventResponseDelta> delta_modified( | |
| 899 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, | |
| 900 &old_headers, &new_headers_modified)); | |
| 901 ASSERT_TRUE(delta_modified.get()); | |
| 902 EXPECT_TRUE(delta_modified->deleted_request_headers.empty()); | |
| 903 ASSERT_TRUE( | |
| 904 delta_modified->modified_request_headers.GetHeader("key2", &value)); | |
| 905 EXPECT_EQ("value3", value); | |
| 906 | |
| 907 // Test modifying a header if extension author just appended a new (key, | |
| 908 // value) pair with a key that existed before. This is incorrect | |
| 909 // usage of the API that shall be handled gracefully. | |
| 910 net::HttpRequestHeaders new_headers_modified2; | |
| 911 new_headers_modified2.AddHeadersFromString("key1: value1\r\n" | |
| 912 "key2: value2\r\n" | |
| 913 "key2: value3\r\n"); | |
| 914 scoped_ptr<EventResponseDelta> delta_modified2( | |
| 915 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, | |
| 916 &old_headers, &new_headers_modified)); | |
| 917 ASSERT_TRUE(delta_modified2.get()); | |
| 918 EXPECT_TRUE(delta_modified2->deleted_request_headers.empty()); | |
| 919 ASSERT_TRUE( | |
| 920 delta_modified2->modified_request_headers.GetHeader("key2", &value)); | |
| 921 EXPECT_EQ("value3", value); | |
| 922 } | |
| 923 | |
| 924 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnHeadersReceivedDelta) { | |
| 925 const bool cancel = true; | |
| 926 char base_headers_string[] = | |
| 927 "HTTP/1.0 200 OK\r\n" | |
| 928 "Key1: Value1\r\n" | |
| 929 "Key2: Value2\r\n" | |
| 930 "Key3: Value3\r\n" | |
| 931 "\r\n"; | |
| 932 scoped_refptr<net::HttpResponseHeaders> base_headers( | |
| 933 new net::HttpResponseHeaders( | |
| 934 net::HttpUtil::AssembleRawHeaders( | |
| 935 base_headers_string, sizeof(base_headers_string)))); | |
| 936 | |
| 937 ResponseHeaders new_headers; | |
| 938 new_headers.push_back(ResponseHeader("kEy1", "Value1")); // Unchanged | |
| 939 new_headers.push_back(ResponseHeader("Key2", "Value1")); // Modified | |
| 940 // Key3 is deleted | |
| 941 new_headers.push_back(ResponseHeader("Key4", "Value4")); // Added | |
| 942 | |
| 943 scoped_ptr<EventResponseDelta> delta( | |
| 944 CalculateOnHeadersReceivedDelta("extid", base::Time::Now(), cancel, | |
| 945 base_headers, &new_headers)); | |
| 946 ASSERT_TRUE(delta.get()); | |
| 947 EXPECT_TRUE(delta->cancel); | |
| 948 EXPECT_EQ(2u, delta->added_response_headers.size()); | |
| 949 EXPECT_TRUE(Contains(delta->added_response_headers, | |
| 950 ResponseHeader("Key2", "Value1"))); | |
| 951 EXPECT_TRUE(Contains(delta->added_response_headers, | |
| 952 ResponseHeader("Key4", "Value4"))); | |
| 953 EXPECT_EQ(2u, delta->deleted_response_headers.size()); | |
| 954 EXPECT_TRUE(Contains(delta->deleted_response_headers, | |
| 955 ResponseHeader("Key2", "Value2"))); | |
| 956 EXPECT_TRUE(Contains(delta->deleted_response_headers, | |
| 957 ResponseHeader("Key3", "Value3"))); | |
| 958 } | |
| 959 | |
| 960 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnAuthRequiredDelta) { | |
| 961 const bool cancel = true; | |
| 962 | |
| 963 string16 username = ASCIIToUTF16("foo"); | |
| 964 string16 password = ASCIIToUTF16("bar"); | |
| 965 scoped_ptr<net::AuthCredentials> credentials( | |
| 966 new net::AuthCredentials(username, password)); | |
| 967 | |
| 968 scoped_ptr<EventResponseDelta> delta( | |
| 969 CalculateOnAuthRequiredDelta("extid", base::Time::Now(), cancel, | |
| 970 &credentials)); | |
| 971 ASSERT_TRUE(delta.get()); | |
| 972 EXPECT_TRUE(delta->cancel); | |
| 973 ASSERT_TRUE(delta->auth_credentials.get()); | |
| 974 EXPECT_EQ(username, delta->auth_credentials->username()); | |
| 975 EXPECT_EQ(password, delta->auth_credentials->password()); | |
| 976 } | |
| 977 | |
| 978 TEST(ExtensionWebRequestHelpersTest, TestMergeCancelOfResponses) { | |
| 979 EventResponseDeltas deltas; | |
| 980 EventLogEntries event_log; | |
| 981 bool canceled = false; | |
| 982 | |
| 983 // Single event that does not cancel. | |
| 984 linked_ptr<EventResponseDelta> d1( | |
| 985 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000))); | |
| 986 d1->cancel = false; | |
| 987 deltas.push_back(d1); | |
| 988 MergeCancelOfResponses(deltas, &canceled, &event_log); | |
| 989 EXPECT_FALSE(canceled); | |
| 990 EXPECT_TRUE(event_log.empty()); | |
| 991 | |
| 992 // Second event that cancels the request | |
| 993 linked_ptr<EventResponseDelta> d2( | |
| 994 new EventResponseDelta("extid2", base::Time::FromInternalValue(500))); | |
| 995 d2->cancel = true; | |
| 996 deltas.push_back(d2); | |
| 997 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 998 MergeCancelOfResponses(deltas, &canceled, &event_log); | |
| 999 EXPECT_TRUE(canceled); | |
| 1000 EXPECT_EQ(1u, event_log.size()); | |
| 1001 } | |
| 1002 | |
| 1003 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses) { | |
| 1004 EventResponseDeltas deltas; | |
| 1005 EventLogEntries event_log; | |
| 1006 std::set<std::string> conflicting_extensions; | |
| 1007 GURL effective_new_url; | |
| 1008 | |
| 1009 // No redirect | |
| 1010 linked_ptr<EventResponseDelta> d0( | |
| 1011 new EventResponseDelta("extid0", base::Time::FromInternalValue(0))); | |
| 1012 deltas.push_back(d0); | |
| 1013 MergeOnBeforeRequestResponses( | |
| 1014 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1015 EXPECT_TRUE(effective_new_url.is_empty()); | |
| 1016 | |
| 1017 // Single redirect. | |
| 1018 GURL new_url_1("http://foo.com"); | |
| 1019 linked_ptr<EventResponseDelta> d1( | |
| 1020 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000))); | |
| 1021 d1->new_url = GURL(new_url_1); | |
| 1022 deltas.push_back(d1); | |
| 1023 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1024 event_log.clear(); | |
| 1025 MergeOnBeforeRequestResponses( | |
| 1026 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1027 EXPECT_EQ(new_url_1, effective_new_url); | |
| 1028 EXPECT_TRUE(conflicting_extensions.empty()); | |
| 1029 EXPECT_EQ(1u, event_log.size()); | |
| 1030 | |
| 1031 // Ignored redirect (due to precedence). | |
| 1032 GURL new_url_2("http://bar.com"); | |
| 1033 linked_ptr<EventResponseDelta> d2( | |
| 1034 new EventResponseDelta("extid2", base::Time::FromInternalValue(500))); | |
| 1035 d2->new_url = GURL(new_url_2); | |
| 1036 deltas.push_back(d2); | |
| 1037 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1038 event_log.clear(); | |
| 1039 MergeOnBeforeRequestResponses( | |
| 1040 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1041 EXPECT_EQ(new_url_1, effective_new_url); | |
| 1042 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1043 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1044 EXPECT_EQ(2u, event_log.size()); | |
| 1045 | |
| 1046 // Overriding redirect. | |
| 1047 GURL new_url_3("http://baz.com"); | |
| 1048 linked_ptr<EventResponseDelta> d3( | |
| 1049 new EventResponseDelta("extid3", base::Time::FromInternalValue(1500))); | |
| 1050 d3->new_url = GURL(new_url_3); | |
| 1051 deltas.push_back(d3); | |
| 1052 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1053 conflicting_extensions.clear(); | |
| 1054 event_log.clear(); | |
| 1055 MergeOnBeforeRequestResponses( | |
| 1056 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1057 EXPECT_EQ(new_url_3, effective_new_url); | |
| 1058 EXPECT_EQ(2u, conflicting_extensions.size()); | |
| 1059 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid1")); | |
| 1060 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1061 EXPECT_EQ(3u, event_log.size()); | |
| 1062 | |
| 1063 // Check that identical redirects don't cause a conflict. | |
| 1064 linked_ptr<EventResponseDelta> d4( | |
| 1065 new EventResponseDelta("extid4", base::Time::FromInternalValue(2000))); | |
| 1066 d4->new_url = GURL(new_url_3); | |
| 1067 deltas.push_back(d4); | |
| 1068 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1069 conflicting_extensions.clear(); | |
| 1070 event_log.clear(); | |
| 1071 MergeOnBeforeRequestResponses( | |
| 1072 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1073 EXPECT_EQ(new_url_3, effective_new_url); | |
| 1074 EXPECT_EQ(2u, conflicting_extensions.size()); | |
| 1075 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid1")); | |
| 1076 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1077 EXPECT_EQ(4u, event_log.size()); | |
| 1078 } | |
| 1079 | |
| 1080 // This tests that we can redirect to data:// urls, which is considered | |
| 1081 // a kind of cancelling requests. | |
| 1082 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses2) { | |
| 1083 EventResponseDeltas deltas; | |
| 1084 EventLogEntries event_log; | |
| 1085 std::set<std::string> conflicting_extensions; | |
| 1086 GURL effective_new_url; | |
| 1087 | |
| 1088 // Single redirect. | |
| 1089 GURL new_url_0("http://foo.com"); | |
| 1090 linked_ptr<EventResponseDelta> d0( | |
| 1091 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000))); | |
| 1092 d0->new_url = GURL(new_url_0); | |
| 1093 deltas.push_back(d0); | |
| 1094 MergeOnBeforeRequestResponses( | |
| 1095 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1096 EXPECT_EQ(new_url_0, effective_new_url); | |
| 1097 | |
| 1098 // Cancel request by redirecting to a data:// URL. This shall override | |
| 1099 // the other redirect but not cause any conflict warnings. | |
| 1100 GURL new_url_1("data://foo"); | |
| 1101 linked_ptr<EventResponseDelta> d1( | |
| 1102 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500))); | |
| 1103 d1->new_url = GURL(new_url_1); | |
| 1104 deltas.push_back(d1); | |
| 1105 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1106 event_log.clear(); | |
| 1107 MergeOnBeforeRequestResponses( | |
| 1108 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1109 EXPECT_EQ(new_url_1, effective_new_url); | |
| 1110 EXPECT_TRUE(conflicting_extensions.empty()); | |
| 1111 EXPECT_EQ(1u, event_log.size()); | |
| 1112 | |
| 1113 // Cancel request by redirecting to the same data:// URL. This shall | |
| 1114 // not create any conflicts as it is in line with d1. | |
| 1115 GURL new_url_2("data://foo"); | |
| 1116 linked_ptr<EventResponseDelta> d2( | |
| 1117 new EventResponseDelta("extid2", base::Time::FromInternalValue(1000))); | |
| 1118 d2->new_url = GURL(new_url_2); | |
| 1119 deltas.push_back(d2); | |
| 1120 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1121 event_log.clear(); | |
| 1122 MergeOnBeforeRequestResponses( | |
| 1123 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1124 EXPECT_EQ(new_url_1, effective_new_url); | |
| 1125 EXPECT_TRUE(conflicting_extensions.empty()); | |
| 1126 EXPECT_EQ(2u, event_log.size()); | |
| 1127 | |
| 1128 // Cancel redirect by redirecting to a different data:// URL. This needs | |
| 1129 // to create a conflict. | |
| 1130 GURL new_url_3("data://something_totally_different"); | |
| 1131 linked_ptr<EventResponseDelta> d3( | |
| 1132 new EventResponseDelta("extid3", base::Time::FromInternalValue(500))); | |
| 1133 d3->new_url = GURL(new_url_3); | |
| 1134 deltas.push_back(d3); | |
| 1135 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1136 event_log.clear(); | |
| 1137 MergeOnBeforeRequestResponses( | |
| 1138 deltas, &effective_new_url, &conflicting_extensions, &event_log); | |
| 1139 EXPECT_EQ(new_url_1, effective_new_url); | |
| 1140 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1141 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid3")); | |
| 1142 EXPECT_EQ(3u, event_log.size()); | |
| 1143 } | |
| 1144 | |
| 1145 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) { | |
| 1146 net::HttpRequestHeaders base_headers; | |
| 1147 base_headers.AddHeaderFromString("key1: value 1"); | |
| 1148 base_headers.AddHeaderFromString("key2: value 2"); | |
| 1149 EventLogEntries event_log; | |
| 1150 std::set<std::string> conflicting_extensions; | |
| 1151 std::string header_value; | |
| 1152 EventResponseDeltas deltas; | |
| 1153 | |
| 1154 // Check that we can handle not changing the headers. | |
| 1155 linked_ptr<EventResponseDelta> d0( | |
| 1156 new EventResponseDelta("extid0", base::Time::FromInternalValue(2500))); | |
| 1157 deltas.push_back(d0); | |
| 1158 net::HttpRequestHeaders headers0; | |
| 1159 headers0.MergeFrom(base_headers); | |
| 1160 MergeOnBeforeSendHeadersResponses( | |
| 1161 deltas, &headers0, &conflicting_extensions, &event_log); | |
| 1162 ASSERT_TRUE(headers0.GetHeader("key1", &header_value)); | |
| 1163 EXPECT_EQ("value 1", header_value); | |
| 1164 ASSERT_TRUE(headers0.GetHeader("key2", &header_value)); | |
| 1165 EXPECT_EQ("value 2", header_value); | |
| 1166 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1167 EXPECT_EQ(0u, event_log.size()); | |
| 1168 | |
| 1169 // Delete, modify and add a header. | |
| 1170 linked_ptr<EventResponseDelta> d1( | |
| 1171 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); | |
| 1172 d1->deleted_request_headers.push_back("key1"); | |
| 1173 d1->modified_request_headers.AddHeaderFromString("key2: value 3"); | |
| 1174 d1->modified_request_headers.AddHeaderFromString("key3: value 3"); | |
| 1175 deltas.push_back(d1); | |
| 1176 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1177 net::HttpRequestHeaders headers1; | |
| 1178 headers1.MergeFrom(base_headers); | |
| 1179 MergeOnBeforeSendHeadersResponses( | |
| 1180 deltas, &headers1, &conflicting_extensions, &event_log); | |
| 1181 EXPECT_FALSE(headers1.HasHeader("key1")); | |
| 1182 ASSERT_TRUE(headers1.GetHeader("key2", &header_value)); | |
| 1183 EXPECT_EQ("value 3", header_value); | |
| 1184 ASSERT_TRUE(headers1.GetHeader("key3", &header_value)); | |
| 1185 EXPECT_EQ("value 3", header_value); | |
| 1186 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1187 EXPECT_EQ(1u, event_log.size()); | |
| 1188 | |
| 1189 // Check that conflicts are atomic, i.e. if one header modification | |
| 1190 // collides all other conflicts of the same extension are declined as well. | |
| 1191 linked_ptr<EventResponseDelta> d2( | |
| 1192 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); | |
| 1193 // This one conflicts: | |
| 1194 d2->modified_request_headers.AddHeaderFromString("key3: value 0"); | |
| 1195 d2->modified_request_headers.AddHeaderFromString("key4: value 4"); | |
| 1196 deltas.push_back(d2); | |
| 1197 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1198 conflicting_extensions.clear(); | |
| 1199 event_log.clear(); | |
| 1200 net::HttpRequestHeaders headers2; | |
| 1201 headers2.MergeFrom(base_headers); | |
| 1202 MergeOnBeforeSendHeadersResponses( | |
| 1203 deltas, &headers2, &conflicting_extensions, &event_log); | |
| 1204 EXPECT_FALSE(headers2.HasHeader("key1")); | |
| 1205 ASSERT_TRUE(headers2.GetHeader("key2", &header_value)); | |
| 1206 EXPECT_EQ("value 3", header_value); | |
| 1207 ASSERT_TRUE(headers2.GetHeader("key3", &header_value)); | |
| 1208 EXPECT_EQ("value 3", header_value); | |
| 1209 EXPECT_FALSE(headers2.HasHeader("key4")); | |
| 1210 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1211 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1212 EXPECT_EQ(2u, event_log.size()); | |
| 1213 | |
| 1214 // Check that identical modifications don't conflict and operations | |
| 1215 // can be merged. | |
| 1216 linked_ptr<EventResponseDelta> d3( | |
| 1217 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000))); | |
| 1218 d3->deleted_request_headers.push_back("key1"); | |
| 1219 d3->modified_request_headers.AddHeaderFromString("key2: value 3"); | |
| 1220 d3->modified_request_headers.AddHeaderFromString("key5: value 5"); | |
| 1221 deltas.push_back(d3); | |
| 1222 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1223 conflicting_extensions.clear(); | |
| 1224 event_log.clear(); | |
| 1225 net::HttpRequestHeaders headers3; | |
| 1226 headers3.MergeFrom(base_headers); | |
| 1227 MergeOnBeforeSendHeadersResponses( | |
| 1228 deltas, &headers3, &conflicting_extensions, &event_log); | |
| 1229 EXPECT_FALSE(headers3.HasHeader("key1")); | |
| 1230 ASSERT_TRUE(headers3.GetHeader("key2", &header_value)); | |
| 1231 EXPECT_EQ("value 3", header_value); | |
| 1232 ASSERT_TRUE(headers3.GetHeader("key3", &header_value)); | |
| 1233 EXPECT_EQ("value 3", header_value); | |
| 1234 ASSERT_TRUE(headers3.GetHeader("key5", &header_value)); | |
| 1235 EXPECT_EQ("value 5", header_value); | |
| 1236 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1237 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1238 EXPECT_EQ(3u, event_log.size()); | |
| 1239 } | |
| 1240 | |
| 1241 TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) { | |
| 1242 EventLogEntries event_log; | |
| 1243 std::set<std::string> conflicting_extensions; | |
| 1244 std::string header_value; | |
| 1245 EventResponseDeltas deltas; | |
| 1246 | |
| 1247 char base_headers_string[] = | |
| 1248 "HTTP/1.0 200 OK\r\n" | |
| 1249 "Key1: Value1\r\n" | |
| 1250 "Key2: Value2\r\n" | |
| 1251 "\r\n"; | |
| 1252 scoped_refptr<net::HttpResponseHeaders> base_headers( | |
| 1253 new net::HttpResponseHeaders( | |
| 1254 net::HttpUtil::AssembleRawHeaders( | |
| 1255 base_headers_string, sizeof(base_headers_string)))); | |
| 1256 | |
| 1257 // Check that we can handle if not touching the response headers. | |
| 1258 linked_ptr<EventResponseDelta> d0( | |
| 1259 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000))); | |
| 1260 deltas.push_back(d0); | |
| 1261 scoped_refptr<net::HttpResponseHeaders> new_headers0; | |
| 1262 MergeOnHeadersReceivedResponses( | |
| 1263 deltas, base_headers.get(), &new_headers0, &conflicting_extensions, | |
| 1264 &event_log); | |
| 1265 EXPECT_FALSE(new_headers0.get()); | |
| 1266 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1267 EXPECT_EQ(0u, event_log.size()); | |
| 1268 | |
| 1269 linked_ptr<EventResponseDelta> d1( | |
| 1270 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); | |
| 1271 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value1")); | |
| 1272 d1->deleted_response_headers.push_back(ResponseHeader("KEY2", "Value2")); | |
| 1273 d1->added_response_headers.push_back(ResponseHeader("Key2", "Value3")); | |
| 1274 deltas.push_back(d1); | |
| 1275 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1276 conflicting_extensions.clear(); | |
| 1277 event_log.clear(); | |
| 1278 scoped_refptr<net::HttpResponseHeaders> new_headers1; | |
| 1279 MergeOnHeadersReceivedResponses( | |
| 1280 deltas, base_headers.get(), &new_headers1, &conflicting_extensions, | |
| 1281 &event_log); | |
| 1282 ASSERT_TRUE(new_headers1.get()); | |
| 1283 std::multimap<std::string, std::string> expected1; | |
| 1284 expected1.insert(std::pair<std::string, std::string>("Key2", "Value3")); | |
| 1285 void* iter = NULL; | |
| 1286 std::string name; | |
| 1287 std::string value; | |
| 1288 std::multimap<std::string, std::string> actual1; | |
| 1289 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) { | |
| 1290 actual1.insert(std::pair<std::string, std::string>(name, value)); | |
| 1291 } | |
| 1292 EXPECT_EQ(expected1, actual1); | |
| 1293 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1294 EXPECT_EQ(1u, event_log.size()); | |
| 1295 | |
| 1296 // Check that we replace response headers only once. | |
| 1297 linked_ptr<EventResponseDelta> d2( | |
| 1298 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); | |
| 1299 // Note that we use a different capitalization of KeY2. This should not | |
| 1300 // matter. | |
| 1301 d2->deleted_response_headers.push_back(ResponseHeader("KeY2", "Value2")); | |
| 1302 d2->added_response_headers.push_back(ResponseHeader("Key2", "Value4")); | |
| 1303 deltas.push_back(d2); | |
| 1304 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1305 conflicting_extensions.clear(); | |
| 1306 event_log.clear(); | |
| 1307 scoped_refptr<net::HttpResponseHeaders> new_headers2; | |
| 1308 MergeOnHeadersReceivedResponses( | |
| 1309 deltas, base_headers.get(), &new_headers2, &conflicting_extensions, | |
| 1310 &event_log); | |
| 1311 ASSERT_TRUE(new_headers2.get()); | |
| 1312 iter = NULL; | |
| 1313 std::multimap<std::string, std::string> actual2; | |
| 1314 while (new_headers2->EnumerateHeaderLines(&iter, &name, &value)) { | |
| 1315 actual2.insert(std::pair<std::string, std::string>(name, value)); | |
| 1316 } | |
| 1317 EXPECT_EQ(expected1, actual2); | |
| 1318 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1319 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1320 EXPECT_EQ(2u, event_log.size()); | |
| 1321 } | |
| 1322 | |
| 1323 // Check that we do not delete too much | |
| 1324 TEST(ExtensionWebRequestHelpersTest, | |
| 1325 TestMergeOnHeadersReceivedResponsesDeletion) { | |
| 1326 EventLogEntries event_log; | |
| 1327 std::set<std::string> conflicting_extensions; | |
| 1328 std::string header_value; | |
| 1329 EventResponseDeltas deltas; | |
| 1330 | |
| 1331 char base_headers_string[] = | |
| 1332 "HTTP/1.0 200 OK\r\n" | |
| 1333 "Key1: Value1\r\n" | |
| 1334 "Key1: Value2\r\n" | |
| 1335 "Key1: Value3\r\n" | |
| 1336 "Key2: Value4\r\n" | |
| 1337 "\r\n"; | |
| 1338 scoped_refptr<net::HttpResponseHeaders> base_headers( | |
| 1339 new net::HttpResponseHeaders( | |
| 1340 net::HttpUtil::AssembleRawHeaders( | |
| 1341 base_headers_string, sizeof(base_headers_string)))); | |
| 1342 | |
| 1343 linked_ptr<EventResponseDelta> d1( | |
| 1344 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); | |
| 1345 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value2")); | |
| 1346 deltas.push_back(d1); | |
| 1347 scoped_refptr<net::HttpResponseHeaders> new_headers1; | |
| 1348 MergeOnHeadersReceivedResponses( | |
| 1349 deltas, base_headers.get(), &new_headers1, &conflicting_extensions, | |
| 1350 &event_log); | |
| 1351 ASSERT_TRUE(new_headers1.get()); | |
| 1352 std::multimap<std::string, std::string> expected1; | |
| 1353 expected1.insert(std::pair<std::string, std::string>("Key1", "Value1")); | |
| 1354 expected1.insert(std::pair<std::string, std::string>("Key1", "Value3")); | |
| 1355 expected1.insert(std::pair<std::string, std::string>("Key2", "Value4")); | |
| 1356 void* iter = NULL; | |
| 1357 std::string name; | |
| 1358 std::string value; | |
| 1359 std::multimap<std::string, std::string> actual1; | |
| 1360 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) { | |
| 1361 actual1.insert(std::pair<std::string, std::string>(name, value)); | |
| 1362 } | |
| 1363 EXPECT_EQ(expected1, actual1); | |
| 1364 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1365 EXPECT_EQ(1u, event_log.size()); | |
| 1366 } | |
| 1367 | |
| 1368 TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) { | |
| 1369 EventLogEntries event_log; | |
| 1370 std::set<std::string> conflicting_extensions; | |
| 1371 EventResponseDeltas deltas; | |
| 1372 string16 username = ASCIIToUTF16("foo"); | |
| 1373 string16 password = ASCIIToUTF16("bar"); | |
| 1374 string16 password2 = ASCIIToUTF16("baz"); | |
| 1375 | |
| 1376 // Check that we can handle if not returning credentials. | |
| 1377 linked_ptr<EventResponseDelta> d0( | |
| 1378 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000))); | |
| 1379 deltas.push_back(d0); | |
| 1380 net::AuthCredentials auth0; | |
| 1381 bool credentials_set = MergeOnAuthRequiredResponses( | |
| 1382 deltas, &auth0, &conflicting_extensions, &event_log); | |
| 1383 EXPECT_FALSE(credentials_set); | |
| 1384 EXPECT_TRUE(auth0.Empty()); | |
| 1385 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1386 EXPECT_EQ(0u, event_log.size()); | |
| 1387 | |
| 1388 // Check that we can set AuthCredentials. | |
| 1389 linked_ptr<EventResponseDelta> d1( | |
| 1390 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); | |
| 1391 d1->auth_credentials.reset(new net::AuthCredentials(username, password)); | |
| 1392 deltas.push_back(d1); | |
| 1393 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1394 conflicting_extensions.clear(); | |
| 1395 event_log.clear(); | |
| 1396 net::AuthCredentials auth1; | |
| 1397 credentials_set = MergeOnAuthRequiredResponses( | |
| 1398 deltas, &auth1, &conflicting_extensions, &event_log); | |
| 1399 EXPECT_TRUE(credentials_set); | |
| 1400 EXPECT_FALSE(auth1.Empty()); | |
| 1401 EXPECT_EQ(username, auth1.username()); | |
| 1402 EXPECT_EQ(password, auth1.password()); | |
| 1403 EXPECT_EQ(0u, conflicting_extensions.size()); | |
| 1404 EXPECT_EQ(1u, event_log.size()); | |
| 1405 | |
| 1406 // Check that we set AuthCredentials only once. | |
| 1407 linked_ptr<EventResponseDelta> d2( | |
| 1408 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); | |
| 1409 d2->auth_credentials.reset(new net::AuthCredentials(username, password2)); | |
| 1410 deltas.push_back(d2); | |
| 1411 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1412 conflicting_extensions.clear(); | |
| 1413 event_log.clear(); | |
| 1414 net::AuthCredentials auth2; | |
| 1415 credentials_set = MergeOnAuthRequiredResponses( | |
| 1416 deltas, &auth2, &conflicting_extensions, &event_log); | |
| 1417 EXPECT_TRUE(credentials_set); | |
| 1418 EXPECT_FALSE(auth2.Empty()); | |
| 1419 EXPECT_EQ(username, auth1.username()); | |
| 1420 EXPECT_EQ(password, auth1.password()); | |
| 1421 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1422 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1423 EXPECT_EQ(2u, event_log.size()); | |
| 1424 | |
| 1425 // Check that we can set identical AuthCredentials twice without causing | |
| 1426 // a conflict. | |
| 1427 linked_ptr<EventResponseDelta> d3( | |
| 1428 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000))); | |
| 1429 d3->auth_credentials.reset(new net::AuthCredentials(username, password)); | |
| 1430 deltas.push_back(d3); | |
| 1431 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); | |
| 1432 conflicting_extensions.clear(); | |
| 1433 event_log.clear(); | |
| 1434 net::AuthCredentials auth3; | |
| 1435 credentials_set = MergeOnAuthRequiredResponses( | |
| 1436 deltas, &auth3, &conflicting_extensions, &event_log); | |
| 1437 EXPECT_TRUE(credentials_set); | |
| 1438 EXPECT_FALSE(auth3.Empty()); | |
| 1439 EXPECT_EQ(username, auth1.username()); | |
| 1440 EXPECT_EQ(password, auth1.password()); | |
| 1441 EXPECT_EQ(1u, conflicting_extensions.size()); | |
| 1442 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); | |
| 1443 EXPECT_EQ(3u, event_log.size()); | |
| 1444 } | |
| OLD | NEW |