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 <map> 6 #include <queue> 7 8 #include "base/basictypes.h" 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/files/file_path.h" 12 #include "base/json/json_reader.h" 13 #include "base/json/json_string_value_serializer.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/path_service.h" 17 #include "base/prefs/pref_member.h" 18 #include "base/stl_util.h" 19 #include "base/strings/string_piece.h" 20 #include "base/strings/stringprintf.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/time/time.h" 23 #include "chrome/browser/content_settings/cookie_settings.h" 24 #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h" 25 #include "chrome/browser/extensions/api/web_request/web_request_api.h" 26 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h" 27 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 28 #include "chrome/browser/extensions/event_router_forwarder.h" 29 #include "chrome/browser/extensions/extension_warning_set.h" 30 #include "chrome/browser/net/about_protocol_handler.h" 31 #include "chrome/browser/net/chrome_network_delegate.h" 32 #include "chrome/common/extensions/extension_messages.h" 33 #include "chrome/common/extensions/features/feature.h" 34 #include "chrome/common/pref_names.h" 35 #include "chrome/test/base/testing_browser_process.h" 36 #include "chrome/test/base/testing_pref_service_syncable.h" 37 #include "chrome/test/base/testing_profile.h" 38 #include "chrome/test/base/testing_profile_manager.h" 39 #include "content/public/common/url_constants.h" 40 #include "content/public/test/test_browser_thread_bundle.h" 41 #include "net/base/auth.h" 42 #include "net/base/capturing_net_log.h" 43 #include "net/base/net_util.h" 44 #include "net/base/upload_bytes_element_reader.h" 45 #include "net/base/upload_data_stream.h" 46 #include "net/base/upload_file_element_reader.h" 47 #include "net/dns/mock_host_resolver.h" 48 #include "net/url_request/url_request_job_factory_impl.h" 49 #include "net/url_request/url_request_test_util.h" 50 #include "testing/gtest/include/gtest/gtest-message.h" 51 #include "testing/gtest/include/gtest/gtest.h" 52 53 namespace helpers = extension_web_request_api_helpers; 54 namespace keys = extension_web_request_api_constants; 55 56 using base::BinaryValue; 57 using base::DictionaryValue; 58 using base::ListValue; 59 using base::StringValue; 60 using base::Time; 61 using base::TimeDelta; 62 using base::Value; 63 using chrome::VersionInfo; 64 using extensions::Feature; 65 using helpers::CalculateOnAuthRequiredDelta; 66 using helpers::CalculateOnBeforeRequestDelta; 67 using helpers::CalculateOnBeforeSendHeadersDelta; 68 using helpers::CalculateOnHeadersReceivedDelta; 69 using helpers::CharListToString; 70 using helpers::EventResponseDelta; 71 using helpers::EventResponseDeltas; 72 using helpers::EventResponseDeltas; 73 using helpers::InDecreasingExtensionInstallationTimeOrder; 74 using helpers::MergeCancelOfResponses; 75 using helpers::MergeOnBeforeRequestResponses; 76 using helpers::RequestCookieModification; 77 using helpers::ResponseCookieModification; 78 using helpers::ResponseHeader; 79 using helpers::ResponseHeaders; 80 using helpers::StringToCharList; 81 82 namespace extensions { 83 84 namespace { 85 static void EventHandledOnIOThread( 86 void* profile, 87 const std::string& extension_id, 88 const std::string& event_name, 89 const std::string& sub_event_name, 90 uint64 request_id, 91 ExtensionWebRequestEventRouter::EventResponse* response) { 92 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled( 93 profile, extension_id, event_name, sub_event_name, request_id, 94 response); 95 } 96 97 // Searches |key| in |collection| by iterating over its elements and returns 98 // true if found. 99 template <typename Collection, typename Key> 100 bool Contains(const Collection& collection, const Key& key) { 101 return std::find(collection.begin(), collection.end(), key) != 102 collection.end(); 103 } 104 105 // Returns whether |warnings| contains an extension for |extension_id|. 106 bool HasWarning(const ExtensionWarningSet& warnings, 107 const std::string& extension_id) { 108 for (ExtensionWarningSet::const_iterator i = warnings.begin(); 109 i != warnings.end(); ++i) { 110 if (i->extension_id() == extension_id) 111 return true; 112 } 113 return false; 114 } 115 116 // Parses the JSON data attached to the |message| and tries to return it. 117 // |param| must outlive |out|. Returns NULL on failure. 118 void GetPartOfMessageArguments(IPC::Message* message, 119 const DictionaryValue** out, 120 ExtensionMsg_MessageInvoke::Param* param) { 121 ASSERT_EQ(ExtensionMsg_MessageInvoke::ID, message->type()); 122 ASSERT_TRUE(ExtensionMsg_MessageInvoke::Read(message, param)); 123 ASSERT_GE(param->d.GetSize(), 2u); 124 const Value* value = NULL; 125 ASSERT_TRUE(param->d.Get(1, &value)); 126 const ListValue* list = NULL; 127 ASSERT_TRUE(value->GetAsList(&list)); 128 ASSERT_EQ(1u, list->GetSize()); 129 ASSERT_TRUE(list->GetDictionary(0, out)); 130 } 131 132 } // namespace 133 134 // A mock event router that responds to events with a pre-arranged queue of 135 // Tasks. 136 class TestIPCSender : public IPC::Sender { 137 public: 138 typedef std::list<linked_ptr<IPC::Message> > SentMessages; 139 140 // Adds a Task to the queue. We will fire these in order as events are 141 // dispatched. 142 void PushTask(const base::Closure& task) { 143 task_queue_.push(task); 144 } 145 146 size_t GetNumTasks() { return task_queue_.size(); } 147 148 SentMessages::const_iterator sent_begin() const { 149 return sent_messages_.begin(); 150 } 151 152 SentMessages::const_iterator sent_end() const { 153 return sent_messages_.end(); 154 } 155 156 private: 157 // IPC::Sender 158 virtual bool Send(IPC::Message* message) OVERRIDE { 159 EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type()); 160 161 EXPECT_FALSE(task_queue_.empty()); 162 base::MessageLoop::current()->PostTask(FROM_HERE, task_queue_.front()); 163 task_queue_.pop(); 164 165 sent_messages_.push_back(linked_ptr<IPC::Message>(message)); 166 return true; 167 } 168 169 std::queue<base::Closure> task_queue_; 170 SentMessages sent_messages_; 171 }; 172 173 class ExtensionWebRequestTest : public testing::Test { 174 public: 175 ExtensionWebRequestTest() 176 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 177 profile_manager_(TestingBrowserProcess::GetGlobal()), 178 event_router_(new EventRouterForwarder) {} 179 180 protected: 181 virtual void SetUp() OVERRIDE { 182 ASSERT_TRUE(profile_manager_.SetUp()); 183 ChromeNetworkDelegate::InitializePrefsOnUIThread( 184 &enable_referrers_, NULL, NULL, profile_.GetTestingPrefService()); 185 network_delegate_.reset( 186 new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); 187 network_delegate_->set_profile(&profile_); 188 network_delegate_->set_cookie_settings( 189 CookieSettings::Factory::GetForProfile(&profile_).get()); 190 context_.reset(new net::TestURLRequestContext(true)); 191 context_->set_network_delegate(network_delegate_.get()); 192 context_->Init(); 193 } 194 195 // Fires a URLRequest with the specified |method|, |content_type| and three 196 // elements of upload data: bytes_1, a dummy empty file, bytes_2. 197 void FireURLRequestWithData(const std::string& method, 198 const char* content_type, 199 const std::vector<char>& bytes_1, 200 const std::vector<char>& bytes_2); 201 202 content::TestBrowserThreadBundle thread_bundle_; 203 TestingProfile profile_; 204 TestingProfileManager profile_manager_; 205 net::TestDelegate delegate_; 206 BooleanPrefMember enable_referrers_; 207 TestIPCSender ipc_sender_; 208 scoped_refptr<EventRouterForwarder> event_router_; 209 scoped_refptr<ExtensionInfoMap> extension_info_map_; 210 scoped_ptr<ChromeNetworkDelegate> network_delegate_; 211 scoped_ptr<net::TestURLRequestContext> context_; 212 }; 213 214 // Tests that we handle disagreements among extensions about responses to 215 // blocking events (redirection) by choosing the response from the 216 // most-recently-installed extension. 217 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) { 218 std::string extension1_id("1"); 219 std::string extension2_id("2"); 220 ExtensionWebRequestEventRouter::RequestFilter filter; 221 const std::string kEventName(keys::kOnBeforeRequestEvent); 222 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 223 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 224 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", 225 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 226 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 227 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 228 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", 229 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 230 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 231 232 net::URLRequestJobFactoryImpl job_factory; 233 job_factory.SetProtocolHandler( 234 chrome::kAboutScheme, 235 new chrome_browser_net::AboutProtocolHandler()); 236 context_->set_job_factory(&job_factory); 237 238 GURL redirect_url("about:redirected"); 239 GURL not_chosen_redirect_url("about:not_chosen"); 240 241 net::URLRequest request(GURL("about:blank"), &delegate_, context_.get()); 242 { 243 // onBeforeRequest will be dispatched twice initially. The second response - 244 // the redirect - should win, since it has a later |install_time|. The 245 // redirect will dispatch another pair of onBeforeRequest. There, the first 246 // response should win (later |install_time|). 247 ExtensionWebRequestEventRouter::EventResponse* response = NULL; 248 249 // Extension1 response. Arrives first, but ignored due to install_time. 250 response = new ExtensionWebRequestEventRouter::EventResponse( 251 extension1_id, base::Time::FromDoubleT(1)); 252 response->new_url = not_chosen_redirect_url; 253 ipc_sender_.PushTask( 254 base::Bind(&EventHandledOnIOThread, 255 &profile_, extension1_id, kEventName, kEventName + "/1", 256 request.identifier(), response)); 257 258 // Extension2 response. Arrives second, and chosen because of install_time. 259 response = new ExtensionWebRequestEventRouter::EventResponse( 260 extension2_id, base::Time::FromDoubleT(2)); 261 response->new_url = redirect_url; 262 ipc_sender_.PushTask( 263 base::Bind(&EventHandledOnIOThread, 264 &profile_, extension2_id, kEventName, kEventName + "/2", 265 request.identifier(), response)); 266 267 // Extension2 response to the redirected URL. Arrives first, and chosen. 268 response = new ExtensionWebRequestEventRouter::EventResponse( 269 extension2_id, base::Time::FromDoubleT(2)); 270 ipc_sender_.PushTask( 271 base::Bind(&EventHandledOnIOThread, 272 &profile_, extension2_id, kEventName, kEventName + "/2", 273 request.identifier(), response)); 274 275 // Extension1 response to the redirected URL. Arrives second, and ignored. 276 response = new ExtensionWebRequestEventRouter::EventResponse( 277 extension1_id, base::Time::FromDoubleT(1)); 278 ipc_sender_.PushTask( 279 base::Bind(&EventHandledOnIOThread, 280 &profile_, extension1_id, kEventName, kEventName + "/1", 281 request.identifier(), response)); 282 283 request.Start(); 284 base::MessageLoop::current()->Run(); 285 286 EXPECT_TRUE(!request.is_pending()); 287 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); 288 EXPECT_EQ(0, request.status().error()); 289 EXPECT_EQ(redirect_url, request.url()); 290 EXPECT_EQ(2U, request.url_chain().size()); 291 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 292 } 293 294 // Now test the same thing but the extensions answer in reverse order. 295 net::URLRequest request2(GURL("about:blank"), &delegate_, context_.get()); 296 { 297 ExtensionWebRequestEventRouter::EventResponse* response = NULL; 298 299 // Extension2 response. Arrives first, and chosen because of install_time. 300 response = new ExtensionWebRequestEventRouter::EventResponse( 301 extension2_id, base::Time::FromDoubleT(2)); 302 response->new_url = redirect_url; 303 ipc_sender_.PushTask( 304 base::Bind(&EventHandledOnIOThread, 305 &profile_, extension2_id, kEventName, kEventName + "/2", 306 request2.identifier(), response)); 307 308 // Extension1 response. Arrives second, but ignored due to install_time. 309 response = new ExtensionWebRequestEventRouter::EventResponse( 310 extension1_id, base::Time::FromDoubleT(1)); 311 response->new_url = not_chosen_redirect_url; 312 ipc_sender_.PushTask( 313 base::Bind(&EventHandledOnIOThread, 314 &profile_, extension1_id, kEventName, kEventName + "/1", 315 request2.identifier(), response)); 316 317 // Extension2 response to the redirected URL. Arrives first, and chosen. 318 response = new ExtensionWebRequestEventRouter::EventResponse( 319 extension2_id, base::Time::FromDoubleT(2)); 320 ipc_sender_.PushTask( 321 base::Bind(&EventHandledOnIOThread, 322 &profile_, extension2_id, kEventName, kEventName + "/2", 323 request2.identifier(), response)); 324 325 // Extension1 response to the redirected URL. Arrives second, and ignored. 326 response = new ExtensionWebRequestEventRouter::EventResponse( 327 extension1_id, base::Time::FromDoubleT(1)); 328 ipc_sender_.PushTask( 329 base::Bind(&EventHandledOnIOThread, 330 &profile_, extension1_id, kEventName, kEventName + "/1", 331 request2.identifier(), response)); 332 333 request2.Start(); 334 base::MessageLoop::current()->Run(); 335 336 EXPECT_TRUE(!request2.is_pending()); 337 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request2.status().status()); 338 EXPECT_EQ(0, request2.status().error()); 339 EXPECT_EQ(redirect_url, request2.url()); 340 EXPECT_EQ(2U, request2.url_chain().size()); 341 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 342 } 343 344 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 345 &profile_, extension1_id, kEventName + "/1"); 346 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 347 &profile_, extension2_id, kEventName + "/2"); 348 } 349 350 // Test that a request is canceled if this is requested by any extension 351 // regardless whether it is the extension with the highest precedence. 352 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceCancel) { 353 std::string extension1_id("1"); 354 std::string extension2_id("2"); 355 ExtensionWebRequestEventRouter::RequestFilter filter; 356 const std::string kEventName(keys::kOnBeforeRequestEvent); 357 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 358 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 359 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", 360 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 361 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 362 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 363 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", 364 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 365 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 366 367 GURL request_url("about:blank"); 368 net::URLRequest request(request_url, &delegate_, context_.get()); 369 370 // onBeforeRequest will be dispatched twice. The second response - 371 // the redirect - would win, since it has a later |install_time|, but 372 // the first response takes precedence because cancel >> redirect. 373 GURL redirect_url("about:redirected"); 374 ExtensionWebRequestEventRouter::EventResponse* response = NULL; 375 376 // Extension1 response. Arrives first, would be ignored in principle due to 377 // install_time but "cancel" always wins. 378 response = new ExtensionWebRequestEventRouter::EventResponse( 379 extension1_id, base::Time::FromDoubleT(1)); 380 response->cancel = true; 381 ipc_sender_.PushTask( 382 base::Bind(&EventHandledOnIOThread, 383 &profile_, extension1_id, kEventName, kEventName + "/1", 384 request.identifier(), response)); 385 386 // Extension2 response. Arrives second, but has higher precedence 387 // due to its later install_time. 388 response = new ExtensionWebRequestEventRouter::EventResponse( 389 extension2_id, base::Time::FromDoubleT(2)); 390 response->new_url = redirect_url; 391 ipc_sender_.PushTask( 392 base::Bind(&EventHandledOnIOThread, 393 &profile_, extension2_id, kEventName, kEventName + "/2", 394 request.identifier(), response)); 395 396 request.Start(); 397 398 base::MessageLoop::current()->Run(); 399 400 EXPECT_TRUE(!request.is_pending()); 401 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 402 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, request.status().error()); 403 EXPECT_EQ(request_url, request.url()); 404 EXPECT_EQ(1U, request.url_chain().size()); 405 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 406 407 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 408 &profile_, extension1_id, kEventName + "/1"); 409 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 410 &profile_, extension2_id, kEventName + "/2"); 411 } 412 413 TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) { 414 // We subscribe to OnBeforeRequest and OnErrorOccurred. 415 // While the OnBeforeRequest handler is blocked, we cancel the request. 416 // We verify that the response of the blocked OnBeforeRequest handler 417 // is ignored. 418 419 std::string extension_id("1"); 420 ExtensionWebRequestEventRouter::RequestFilter filter; 421 422 // Subscribe to OnBeforeRequest and OnErrorOccurred. 423 const std::string kEventName(keys::kOnBeforeRequestEvent); 424 const std::string kEventName2(keys::kOnErrorOccurredEvent); 425 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 426 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 427 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", 428 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 429 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 430 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 431 &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1", 432 filter, 0, -1, MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 433 434 GURL request_url("about:blank"); 435 net::URLRequest request(request_url, &delegate_, context_.get()); 436 437 ExtensionWebRequestEventRouter::EventResponse* response = NULL; 438 439 // Extension response for the OnBeforeRequest handler. This should not be 440 // processed because request is canceled before the handler responds. 441 response = new ExtensionWebRequestEventRouter::EventResponse( 442 extension_id, base::Time::FromDoubleT(1)); 443 GURL redirect_url("about:redirected"); 444 response->new_url = redirect_url; 445 ipc_sender_.PushTask( 446 base::Bind(&EventHandledOnIOThread, 447 &profile_, extension_id, kEventName, kEventName + "/1", 448 request.identifier(), response)); 449 450 // Extension response for OnErrorOccurred: Terminate the message loop. 451 ipc_sender_.PushTask( 452 base::Bind(&base::MessageLoop::PostTask, 453 base::Unretained(base::MessageLoop::current()), 454 FROM_HERE, base::MessageLoop::QuitClosure())); 455 456 request.Start(); 457 // request.Start() will have submitted OnBeforeRequest by the time we cancel. 458 request.Cancel(); 459 base::MessageLoop::current()->Run(); 460 461 EXPECT_TRUE(!request.is_pending()); 462 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status()); 463 EXPECT_EQ(net::ERR_ABORTED, request.status().error()); 464 EXPECT_EQ(request_url, request.url()); 465 EXPECT_EQ(1U, request.url_chain().size()); 466 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 467 468 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 469 &profile_, extension_id, kEventName + "/1"); 470 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 471 &profile_, extension_id, kEventName2 + "/1"); 472 } 473 474 namespace { 475 476 // Create the numerical representation of |values|, strings passed as 477 // extraInfoSpec by the event handler. Returns true on success, otherwise false. 478 bool GenerateInfoSpec(const std::string& values, int* result) { 479 // Create a ListValue of strings. 480 std::vector<std::string> split_values; 481 base::ListValue list_value; 482 size_t num_values = Tokenize(values, ",", &split_values); 483 for (size_t i = 0; i < num_values ; ++i) 484 list_value.Append(new base::StringValue(split_values[i])); 485 return ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue( 486 list_value, result); 487 } 488 489 } // namespace 490 491 void ExtensionWebRequestTest::FireURLRequestWithData( 492 const std::string& method, 493 const char* content_type, 494 const std::vector<char>& bytes_1, 495 const std::vector<char>& bytes_2) { 496 // The request URL can be arbitrary but must have an HTTP or HTTPS scheme. 497 GURL request_url("http://www.example.com"); 498 net::URLRequest request(request_url, &delegate_, context_.get()); 499 request.set_method(method); 500 if (content_type != NULL) 501 request.SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType, 502 content_type, 503 true /* overwrite */); 504 ScopedVector<net::UploadElementReader> element_readers; 505 element_readers.push_back(new net::UploadBytesElementReader( 506 &(bytes_1[0]), bytes_1.size())); 507 element_readers.push_back( 508 new net::UploadFileElementReader(base::MessageLoopProxy::current().get(), 509 base::FilePath(), 510 0, 511 0, 512 base::Time())); 513 element_readers.push_back( 514 new net::UploadBytesElementReader(&(bytes_2[0]), bytes_2.size())); 515 request.set_upload(make_scoped_ptr( 516 new net::UploadDataStream(&element_readers, 0))); 517 ipc_sender_.PushTask(base::Bind(&base::DoNothing)); 518 request.Start(); 519 } 520 521 TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) { 522 // We verify that URLRequest body is accessible to OnBeforeRequest listeners. 523 // These testing steps are repeated twice in a row: 524 // 1. Register an extension requesting "requestBody" in ExtraInfoSpec and 525 // file a POST URLRequest with a multipart-encoded form. See it getting 526 // parsed. 527 // 2. Do the same, but without requesting "requestBody". Nothing should be 528 // parsed. 529 // 3. With "requestBody", fire a POST URLRequest which is not a parseable 530 // HTML form. Raw data should be returned. 531 // 4. Do the same, but with a PUT method. Result should be the same. 532 const std::string kMethodPost("POST"); 533 const std::string kMethodPut("PUT"); 534 535 // Input. 536 const char kPlainBlock1[] = "abcd\n"; 537 const size_t kPlainBlock1Length = sizeof(kPlainBlock1) - 1; 538 std::vector<char> plain_1(kPlainBlock1, kPlainBlock1 + kPlainBlock1Length); 539 const char kPlainBlock2[] = "1234\n"; 540 const size_t kPlainBlock2Length = sizeof(kPlainBlock2) - 1; 541 std::vector<char> plain_2(kPlainBlock2, kPlainBlock2 + kPlainBlock2Length); 542 #define kBoundary "THIS_IS_A_BOUNDARY" 543 const char kFormBlock1[] = "--" kBoundary "\r\n" 544 "Content-Disposition: form-data; name=\"A\"\r\n" 545 "\r\n" 546 "test text\r\n" 547 "--" kBoundary "\r\n" 548 "Content-Disposition: form-data; name=\"B\"; filename=\"\"\r\n" 549 "Content-Type: application/octet-stream\r\n" 550 "\r\n"; 551 std::vector<char> form_1(kFormBlock1, kFormBlock1 + sizeof(kFormBlock1) - 1); 552 const char kFormBlock2[] = "\r\n" 553 "--" kBoundary "\r\n" 554 "Content-Disposition: form-data; name=\"C\"\r\n" 555 "\r\n" 556 "test password\r\n" 557 "--" kBoundary "--"; 558 std::vector<char> form_2(kFormBlock2, kFormBlock2 + sizeof(kFormBlock2) - 1); 559 560 // Expected output. 561 // Paths to look for in returned dictionaries. 562 const std::string kBodyPath(keys::kRequestBodyKey); 563 const std::string kFormDataPath( 564 kBodyPath + "." + keys::kRequestBodyFormDataKey); 565 const std::string kRawPath(kBodyPath + "." + keys::kRequestBodyRawKey); 566 const std::string kErrorPath(kBodyPath + "." + keys::kRequestBodyErrorKey); 567 const std::string* const kPath[] = { 568 &kFormDataPath, 569 &kBodyPath, 570 &kRawPath, 571 &kRawPath 572 }; 573 // Contents of formData. 574 const char kFormData[] = 575 "{\"A\":[\"test text\"],\"B\":[\"\"],\"C\":[\"test password\"]}"; 576 scoped_ptr<const Value> form_data(base::JSONReader::Read(kFormData)); 577 ASSERT_TRUE(form_data.get() != NULL); 578 ASSERT_TRUE(form_data->GetType() == Value::TYPE_DICTIONARY); 579 // Contents of raw. 580 ListValue raw; 581 extensions::subtle::AppendKeyValuePair( 582 keys::kRequestBodyRawBytesKey, 583 BinaryValue::CreateWithCopiedBuffer(kPlainBlock1, kPlainBlock1Length), 584 &raw); 585 extensions::subtle::AppendKeyValuePair( 586 keys::kRequestBodyRawFileKey, 587 Value::CreateStringValue(std::string()), 588 &raw); 589 extensions::subtle::AppendKeyValuePair( 590 keys::kRequestBodyRawBytesKey, 591 BinaryValue::CreateWithCopiedBuffer(kPlainBlock2, kPlainBlock2Length), 592 &raw); 593 // Summary. 594 const Value* const kExpected[] = { 595 form_data.get(), 596 NULL, 597 &raw, 598 &raw, 599 }; 600 COMPILE_ASSERT(arraysize(kPath) == arraysize(kExpected), 601 the_arrays_kPath_and_kExpected_need_to_be_the_same_size); 602 // Header. 603 const char kMultipart[] = "multipart/form-data; boundary=" kBoundary; 604 #undef kBoundary 605 606 // Set up a dummy extension name. 607 const std::string kEventName(keys::kOnBeforeRequestEvent); 608 ExtensionWebRequestEventRouter::RequestFilter filter; 609 std::string extension_id("1"); 610 const std::string string_spec_post("blocking,requestBody"); 611 const std::string string_spec_no_post("blocking"); 612 int extra_info_spec_empty = 0; 613 int extra_info_spec_body = 0; 614 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 615 616 // Part 1. 617 // Subscribe to OnBeforeRequest with requestBody requirement. 618 ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_body)); 619 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 620 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", 621 filter, extra_info_spec_body, -1, MSG_ROUTING_NONE, -1, 622 ipc_sender_factory.GetWeakPtr()); 623 624 FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2); 625 626 // We inspect the result in the message list of |ipc_sender_| later. 627 base::MessageLoop::current()->RunUntilIdle(); 628 629 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 630 &profile_, extension_id, kEventName + "/1"); 631 632 // Part 2. 633 // Now subscribe to OnBeforeRequest *without* the requestBody requirement. 634 ASSERT_TRUE( 635 GenerateInfoSpec(string_spec_no_post, &extra_info_spec_empty)); 636 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 637 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", 638 filter, extra_info_spec_empty, -1, MSG_ROUTING_NONE, -1, 639 ipc_sender_factory.GetWeakPtr()); 640 641 FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2); 642 643 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 644 &profile_, extension_id, kEventName + "/1"); 645 646 // Subscribe to OnBeforeRequest with requestBody requirement. 647 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 648 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", 649 filter, extra_info_spec_body, -1, MSG_ROUTING_NONE, -1, 650 ipc_sender_factory.GetWeakPtr()); 651 652 // Part 3. 653 // Now send a POST request with body which is not parseable as a form. 654 FireURLRequestWithData(kMethodPost, NULL /*no header*/, plain_1, plain_2); 655 656 // Part 4. 657 // Now send a PUT request with the same body as above. 658 FireURLRequestWithData(kMethodPut, NULL /*no header*/, plain_1, plain_2); 659 660 base::MessageLoop::current()->RunUntilIdle(); 661 662 // Clean-up. 663 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 664 &profile_, extension_id, kEventName + "/1"); 665 666 IPC::Message* message = NULL; 667 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin(); 668 for (size_t test = 0; test < arraysize(kExpected); ++test) { 669 SCOPED_TRACE(testing::Message("iteration number ") << test); 670 EXPECT_NE(i, ipc_sender_.sent_end()); 671 message = (i++)->get(); 672 const DictionaryValue* details; 673 ExtensionMsg_MessageInvoke::Param param; 674 GetPartOfMessageArguments(message, &details, ¶m); 675 ASSERT_TRUE(details != NULL); 676 const Value* result = NULL; 677 if (kExpected[test]) { 678 EXPECT_TRUE(details->Get(*(kPath[test]), &result)); 679 EXPECT_TRUE(kExpected[test]->Equals(result)); 680 } else { 681 EXPECT_FALSE(details->Get(*(kPath[test]), &result)); 682 } 683 } 684 685 EXPECT_EQ(i, ipc_sender_.sent_end()); 686 } 687 688 TEST_F(ExtensionWebRequestTest, NoAccessRequestBodyData) { 689 // We verify that URLRequest body is NOT accessible to OnBeforeRequest 690 // listeners when the type of the request is different from POST or PUT, or 691 // when the request body is empty. 3 requests are fired, without upload data, 692 // a POST, PUT and GET request. For none of them the "requestBody" object 693 // property should be present in the details passed to the onBeforeRequest 694 // event listener. 695 const char* kMethods[] = { "POST", "PUT", "GET" }; 696 697 // Set up a dummy extension name. 698 const std::string kEventName(keys::kOnBeforeRequestEvent); 699 ExtensionWebRequestEventRouter::RequestFilter filter; 700 const std::string extension_id("1"); 701 int extra_info_spec = 0; 702 ASSERT_TRUE(GenerateInfoSpec("blocking,requestBody", &extra_info_spec)); 703 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 704 705 // Subscribe to OnBeforeRequest with requestBody requirement. 706 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 707 &profile_, extension_id, extension_id, kEventName, kEventName + "/1", 708 filter, extra_info_spec, -1, MSG_ROUTING_NONE, -1, 709 ipc_sender_factory.GetWeakPtr()); 710 711 // The request URL can be arbitrary but must have an HTTP or HTTPS scheme. 712 const GURL request_url("http://www.example.com"); 713 714 for (size_t i = 0; i < arraysize(kMethods); ++i) { 715 net::URLRequest request(request_url, &delegate_, context_.get()); 716 request.set_method(kMethods[i]); 717 ipc_sender_.PushTask(base::Bind(&base::DoNothing)); 718 request.Start(); 719 } 720 721 // We inspect the result in the message list of |ipc_sender_| later. 722 base::MessageLoop::current()->RunUntilIdle(); 723 724 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 725 &profile_, extension_id, kEventName + "/1"); 726 727 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin(); 728 for (size_t test = 0; test < arraysize(kMethods); ++test, ++i) { 729 SCOPED_TRACE(testing::Message("iteration number ") << test); 730 EXPECT_NE(i, ipc_sender_.sent_end()); 731 IPC::Message* message = i->get(); 732 const DictionaryValue* details = NULL; 733 ExtensionMsg_MessageInvoke::Param param; 734 GetPartOfMessageArguments(message, &details, ¶m); 735 ASSERT_TRUE(details != NULL); 736 EXPECT_FALSE(details->HasKey(keys::kRequestBodyKey)); 737 } 738 739 EXPECT_EQ(i, ipc_sender_.sent_end()); 740 } 741 742 struct HeaderModificationTest_Header { 743 const char* name; 744 const char* value; 745 }; 746 747 struct HeaderModificationTest_Modification { 748 enum Type { 749 SET, 750 REMOVE 751 }; 752 753 int extension_id; 754 Type type; 755 const char* key; 756 const char* value; 757 }; 758 759 struct HeaderModificationTest { 760 int before_size; 761 HeaderModificationTest_Header before[10]; 762 int modification_size; 763 HeaderModificationTest_Modification modification[10]; 764 int after_size; 765 HeaderModificationTest_Header after[10]; 766 }; 767 768 class ExtensionWebRequestHeaderModificationTest 769 : public testing::TestWithParam<HeaderModificationTest> { 770 public: 771 ExtensionWebRequestHeaderModificationTest() 772 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 773 profile_manager_(TestingBrowserProcess::GetGlobal()), 774 event_router_(new EventRouterForwarder) {} 775 776 protected: 777 virtual void SetUp() { 778 ASSERT_TRUE(profile_manager_.SetUp()); 779 ChromeNetworkDelegate::InitializePrefsOnUIThread( 780 &enable_referrers_, NULL, NULL, profile_.GetTestingPrefService()); 781 network_delegate_.reset( 782 new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); 783 network_delegate_->set_profile(&profile_); 784 network_delegate_->set_cookie_settings( 785 CookieSettings::Factory::GetForProfile(&profile_).get()); 786 context_.reset(new net::TestURLRequestContext(true)); 787 host_resolver_.reset(new net::MockHostResolver()); 788 host_resolver_->rules()->AddSimulatedFailure("doesnotexist"); 789 context_->set_host_resolver(host_resolver_.get()); 790 context_->set_network_delegate(network_delegate_.get()); 791 context_->Init(); 792 } 793 794 content::TestBrowserThreadBundle thread_bundle_; 795 TestingProfile profile_; 796 TestingProfileManager profile_manager_; 797 net::TestDelegate delegate_; 798 BooleanPrefMember enable_referrers_; 799 TestIPCSender ipc_sender_; 800 scoped_refptr<EventRouterForwarder> event_router_; 801 scoped_refptr<ExtensionInfoMap> extension_info_map_; 802 scoped_ptr<ChromeNetworkDelegate> network_delegate_; 803 scoped_ptr<net::MockHostResolver> host_resolver_; 804 scoped_ptr<net::TestURLRequestContext> context_; 805 }; 806 807 TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) { 808 std::string extension1_id("1"); 809 std::string extension2_id("2"); 810 std::string extension3_id("3"); 811 ExtensionWebRequestEventRouter::RequestFilter filter; 812 const std::string kEventName(keys::kOnBeforeSendHeadersEvent); 813 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_); 814 815 // Install two extensions that can modify headers. Extension 2 has 816 // higher precedence than extension 1. 817 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 818 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1", 819 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 820 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 821 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 822 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2", 823 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, -1, 824 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 825 826 // Install one extension that observes the final headers. 827 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( 828 &profile_, extension3_id, extension3_id, keys::kOnSendHeadersEvent, 829 std::string(keys::kOnSendHeadersEvent) + "/3", filter, 830 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, -1, 831 MSG_ROUTING_NONE, -1, ipc_sender_factory.GetWeakPtr()); 832 833 GURL request_url("http://doesnotexist/does_not_exist.html"); 834 net::URLRequest request(request_url, &delegate_, context_.get()); 835 836 // Initialize headers available before extensions are notified of the 837 // onBeforeSendHeaders event. 838 HeaderModificationTest test = GetParam(); 839 net::HttpRequestHeaders before_headers; 840 for (int i = 0; i < test.before_size; ++i) 841 before_headers.SetHeader(test.before[i].name, test.before[i].value); 842 request.SetExtraRequestHeaders(before_headers); 843 844 // Gather the modifications to the headers for the respective extensions. 845 // We assume here that all modifications of one extension are listed 846 // in a continuous block of |test.modifications_|. 847 ExtensionWebRequestEventRouter::EventResponse* response = NULL; 848 for (int i = 0; i < test.modification_size; ++i) { 849 const HeaderModificationTest_Modification& mod = test.modification[i]; 850 if (response == NULL) { 851 response = new ExtensionWebRequestEventRouter::EventResponse( 852 mod.extension_id == 1 ? extension1_id : extension2_id, 853 base::Time::FromDoubleT(mod.extension_id)); 854 response->request_headers.reset(new net::HttpRequestHeaders()); 855 response->request_headers->MergeFrom(request.extra_request_headers()); 856 } 857 858 switch (mod.type) { 859 case HeaderModificationTest_Modification::SET: 860 response->request_headers->SetHeader(mod.key, mod.value); 861 break; 862 case HeaderModificationTest_Modification::REMOVE: 863 response->request_headers->RemoveHeader(mod.key); 864 break; 865 } 866 867 // Trigger the result when this is the last modification statement or 868 // the block of modifications for the next extension starts. 869 if (i+1 == test.modification_size || 870 mod.extension_id != test.modification[i+1].extension_id) { 871 ipc_sender_.PushTask( 872 base::Bind(&EventHandledOnIOThread, 873 &profile_, mod.extension_id == 1 ? extension1_id : extension2_id, 874 kEventName, kEventName + (mod.extension_id == 1 ? "/1" : "/2"), 875 request.identifier(), response)); 876 response = NULL; 877 } 878 } 879 880 // Don't do anything for the onSendHeaders message. 881 ipc_sender_.PushTask(base::Bind(&base::DoNothing)); 882 883 // Note that we mess up the headers slightly: 884 // request.Start() will first add additional headers (e.g. the User-Agent) 885 // and then send an event to the extension. When we have prepared our 886 // answers to the onBeforeSendHeaders events above, these headers did not 887 // exists and are therefore not listed in the responses. This makes 888 // them seem deleted. 889 request.Start(); 890 base::MessageLoop::current()->Run(); 891 892 EXPECT_TRUE(!request.is_pending()); 893 // This cannot succeed as we send the request to a server that does not exist. 894 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 895 EXPECT_EQ(request_url, request.url()); 896 EXPECT_EQ(1U, request.url_chain().size()); 897 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 898 899 // Calculate the expected headers. 900 net::HttpRequestHeaders expected_headers; 901 for (int i = 0; i < test.after_size; ++i) { 902 expected_headers.SetHeader(test.after[i].name, 903 test.after[i].value); 904 } 905 906 // Counter for the number of observed onSendHeaders events. 907 int num_headers_observed = 0; 908 909 // Search the onSendHeaders signal in the IPC messages and check that 910 // it contained the correct headers. 911 TestIPCSender::SentMessages::const_iterator i; 912 for (i = ipc_sender_.sent_begin(); i != ipc_sender_.sent_end(); ++i) { 913 IPC::Message* message = i->get(); 914 if (ExtensionMsg_MessageInvoke::ID != message->type()) 915 continue; 916 ExtensionMsg_MessageInvoke::Param message_tuple; 917 ExtensionMsg_MessageInvoke::Read(message, &message_tuple); 918 ListValue& args = message_tuple.d; 919 920 std::string event_name; 921 if (!args.GetString(0, &event_name) || 922 event_name != std::string(keys::kOnSendHeadersEvent) + "/3") { 923 continue; 924 } 925 926 ListValue* event_arg = NULL; 927 ASSERT_TRUE(args.GetList(1, &event_arg)); 928 929 DictionaryValue* event_arg_dict = NULL; 930 ASSERT_TRUE(event_arg->GetDictionary(0, &event_arg_dict)); 931 932 ListValue* request_headers = NULL; 933 ASSERT_TRUE(event_arg_dict->GetList(keys::kRequestHeadersKey, 934 &request_headers)); 935 936 net::HttpRequestHeaders observed_headers; 937 for (size_t j = 0; j < request_headers->GetSize(); ++j) { 938 DictionaryValue* header = NULL; 939 ASSERT_TRUE(request_headers->GetDictionary(j, &header)); 940 std::string key; 941 std::string value; 942 ASSERT_TRUE(header->GetString(keys::kHeaderNameKey, &key)); 943 ASSERT_TRUE(header->GetString(keys::kHeaderValueKey, &value)); 944 observed_headers.SetHeader(key, value); 945 } 946 947 EXPECT_EQ(expected_headers.ToString(), observed_headers.ToString()); 948 ++num_headers_observed; 949 } 950 EXPECT_EQ(1, num_headers_observed); 951 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 952 &profile_, extension1_id, kEventName + "/1"); 953 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 954 &profile_, extension2_id, kEventName + "/2"); 955 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 956 &profile_, extension3_id, std::string(keys::kOnSendHeadersEvent) + "/3"); 957 }; 958 959 namespace { 960 961 void TestInitFromValue(const std::string& values, bool expected_return_code, 962 int expected_extra_info_spec) { 963 int actual_info_spec; 964 bool actual_return_code = GenerateInfoSpec(values, &actual_info_spec); 965 EXPECT_EQ(expected_return_code, actual_return_code); 966 if (expected_return_code) 967 EXPECT_EQ(expected_extra_info_spec, actual_info_spec); 968 } 969 970 } // namespace 971 972 TEST_F(ExtensionWebRequestTest, InitFromValue) { 973 TestInitFromValue(std::string(), true, 0); 974 975 // Single valid values. 976 TestInitFromValue( 977 "requestHeaders", 978 true, 979 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS); 980 TestInitFromValue( 981 "responseHeaders", 982 true, 983 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS); 984 TestInitFromValue( 985 "blocking", 986 true, 987 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 988 TestInitFromValue( 989 "asyncBlocking", 990 true, 991 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING); 992 TestInitFromValue( 993 "requestBody", 994 true, 995 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_BODY); 996 997 // Multiple valid values are bitwise-or'ed. 998 TestInitFromValue( 999 "requestHeaders,blocking", 1000 true, 1001 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS | 1002 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 1003 1004 // Any invalid values lead to a bad parse. 1005 TestInitFromValue("invalidValue", false, 0); 1006 TestInitFromValue("blocking,invalidValue", false, 0); 1007 TestInitFromValue("invalidValue1,invalidValue2", false, 0); 1008 1009 // BLOCKING and ASYNC_BLOCKING are mutually exclusive. 1010 TestInitFromValue("blocking,asyncBlocking", false, 0); 1011 } 1012 1013 namespace { 1014 1015 const HeaderModificationTest_Modification::Type SET = 1016 HeaderModificationTest_Modification::SET; 1017 const HeaderModificationTest_Modification::Type REMOVE = 1018 HeaderModificationTest_Modification::REMOVE; 1019 1020 HeaderModificationTest kTests[] = { 1021 // Check that extension 2 always wins when settings the same header. 1022 { 1023 // Headers before test. 1024 2, { {"header1", "value1"}, 1025 {"header2", "value2"} }, 1026 // Modifications in test. 1027 2, { {1, SET, "header1", "foo"}, 1028 {2, SET, "header1", "bar"} }, 1029 // Headers after test. 1030 2, { {"header1", "bar"}, 1031 {"header2", "value2"} } 1032 }, 1033 // Same as before in reverse execution order. 1034 { 1035 // Headers before test. 1036 2, { {"header1", "value1"}, 1037 {"header2", "value2"} }, 1038 // Modifications in test. 1039 2, { {2, SET, "header1", "bar"}, 1040 {1, SET, "header1", "foo"} }, 1041 // Headers after test. 1042 2, { {"header1", "bar"}, 1043 {"header2", "value2"} } 1044 }, 1045 // Check that two extensions can modify different headers that do not 1046 // conflict. 1047 { 1048 // Headers before test. 1049 2, { {"header1", "value1"}, 1050 {"header2", "value2"} }, 1051 // Modifications in test. 1052 2, { {1, SET, "header1", "foo"}, 1053 {2, SET, "header2", "bar"} }, 1054 // Headers after test. 1055 2, { {"header1", "foo"}, 1056 {"header2", "bar"} } 1057 }, 1058 // Check insert/delete conflict. 1059 { 1060 // Headers before test. 1061 1, { {"header1", "value1"} }, 1062 // Modifications in test. 1063 2, { {1, SET, "header1", "foo"}, 1064 {2, REMOVE, "header1", NULL} }, 1065 // Headers after test. 1066 0, { } 1067 }, 1068 { 1069 // Headers before test. 1070 1, { {"header1", "value1"} }, 1071 // Modifications in test. 1072 2, { {2, REMOVE, "header1", NULL}, 1073 {1, SET, "header1", "foo"} }, 1074 // Headers after test. 1075 0, {} 1076 }, 1077 { 1078 // Headers before test. 1079 1, { {"header1", "value1"} }, 1080 // Modifications in test. 1081 2, { {1, REMOVE, "header1", NULL}, 1082 {2, SET, "header1", "foo"} }, 1083 // Headers after test. 1084 1, { {"header1", "foo"} } 1085 }, 1086 { 1087 // Headers before test. 1088 1, { {"header1", "value1"} }, 1089 // Modifications in test. 1090 2, { {2, SET, "header1", "foo"}, 1091 {1, REMOVE, "header1", NULL} }, 1092 // Headers after test. 1093 1, { {"header1", "foo"} } 1094 }, 1095 // Check that edits are atomic (i.e. either all edit requests of an 1096 // extension are executed or none). 1097 { 1098 // Headers before test. 1099 0, { }, 1100 // Modifications in test. 1101 3, { {1, SET, "header1", "value1"}, 1102 {1, SET, "header2", "value2"}, 1103 {2, SET, "header1", "foo"} }, 1104 // Headers after test. 1105 1, { {"header1", "foo"} } // set(header2) is ignored 1106 }, 1107 // Check that identical edits do not conflict (set(header2) would be ignored 1108 // if set(header1) were considered a conflict). 1109 { 1110 // Headers before test. 1111 0, { }, 1112 // Modifications in test. 1113 3, { {1, SET, "header1", "value2"}, 1114 {1, SET, "header2", "foo"}, 1115 {2, SET, "header1", "value2"} }, 1116 // Headers after test. 1117 2, { {"header1", "value2"}, 1118 {"header2", "foo"} } 1119 }, 1120 // Check that identical deletes do not conflict (set(header2) would be ignored 1121 // if delete(header1) were considered a conflict). 1122 { 1123 // Headers before test. 1124 1, { {"header1", "value1"} }, 1125 // Modifications in test. 1126 3, { {1, REMOVE, "header1", NULL}, 1127 {1, SET, "header2", "foo"}, 1128 {2, REMOVE, "header1", NULL} }, 1129 // Headers after test. 1130 1, { {"header2", "foo"} } 1131 }, 1132 // Check that setting a value to an identical value is not considered an 1133 // edit operation that can conflict. 1134 { 1135 // Headers before test. 1136 1, { {"header1", "value1"} }, 1137 // Modifications in test. 1138 3, { {1, SET, "header1", "foo"}, 1139 {1, SET, "header2", "bar"}, 1140 {2, SET, "header1", "value1"} }, 1141 // Headers after test. 1142 2, { {"header1", "foo"}, 1143 {"header2", "bar"} } 1144 }, 1145 }; 1146 1147 INSTANTIATE_TEST_CASE_P( 1148 ExtensionWebRequest, 1149 ExtensionWebRequestHeaderModificationTest, 1150 ::testing::ValuesIn(kTests)); 1151 1152 } // namespace 1153 1154 1155 TEST(ExtensionWebRequestHelpersTest, 1156 TestInDecreasingExtensionInstallationTimeOrder) { 1157 linked_ptr<EventResponseDelta> a( 1158 new EventResponseDelta("ext_1", base::Time::FromInternalValue(0))); 1159 linked_ptr<EventResponseDelta> b( 1160 new EventResponseDelta("ext_2", base::Time::FromInternalValue(1000))); 1161 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, a)); 1162 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, b)); 1163 EXPECT_TRUE(InDecreasingExtensionInstallationTimeOrder(b, a)); 1164 } 1165 1166 TEST(ExtensionWebRequestHelpersTest, TestStringToCharList) { 1167 ListValue list_value; 1168 list_value.Append(Value::CreateIntegerValue('1')); 1169 list_value.Append(Value::CreateIntegerValue('2')); 1170 list_value.Append(Value::CreateIntegerValue('3')); 1171 list_value.Append(Value::CreateIntegerValue(0xFE)); 1172 list_value.Append(Value::CreateIntegerValue(0xD1)); 1173 1174 unsigned char char_value[] = {'1', '2', '3', 0xFE, 0xD1}; 1175 std::string string_value(reinterpret_cast<char *>(char_value), 5); 1176 1177 scoped_ptr<ListValue> converted_list(StringToCharList(string_value)); 1178 EXPECT_TRUE(list_value.Equals(converted_list.get())); 1179 1180 std::string converted_string; 1181 EXPECT_TRUE(CharListToString(&list_value, &converted_string)); 1182 EXPECT_EQ(string_value, converted_string); 1183 } 1184 1185 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeRequestDelta) { 1186 const bool cancel = true; 1187 const GURL localhost("http://localhost"); 1188 scoped_ptr<EventResponseDelta> delta( 1189 CalculateOnBeforeRequestDelta("extid", base::Time::Now(), 1190 cancel, localhost)); 1191 ASSERT_TRUE(delta.get()); 1192 EXPECT_TRUE(delta->cancel); 1193 EXPECT_EQ(localhost, delta->new_url); 1194 } 1195 1196 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeSendHeadersDelta) { 1197 const bool cancel = true; 1198 std::string value; 1199 net::HttpRequestHeaders old_headers; 1200 old_headers.AddHeadersFromString("key1: value1\r\n" 1201 "key2: value2\r\n"); 1202 1203 // Test adding a header. 1204 net::HttpRequestHeaders new_headers_added; 1205 new_headers_added.AddHeadersFromString("key1: value1\r\n" 1206 "key3: value3\r\n" 1207 "key2: value2\r\n"); 1208 scoped_ptr<EventResponseDelta> delta_added( 1209 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, 1210 &old_headers, &new_headers_added)); 1211 ASSERT_TRUE(delta_added.get()); 1212 EXPECT_TRUE(delta_added->cancel); 1213 ASSERT_TRUE(delta_added->modified_request_headers.GetHeader("key3", &value)); 1214 EXPECT_EQ("value3", value); 1215 1216 // Test deleting a header. 1217 net::HttpRequestHeaders new_headers_deleted; 1218 new_headers_deleted.AddHeadersFromString("key1: value1\r\n"); 1219 scoped_ptr<EventResponseDelta> delta_deleted( 1220 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, 1221 &old_headers, &new_headers_deleted)); 1222 ASSERT_TRUE(delta_deleted.get()); 1223 ASSERT_EQ(1u, delta_deleted->deleted_request_headers.size()); 1224 ASSERT_EQ("key2", delta_deleted->deleted_request_headers.front()); 1225 1226 // Test modifying a header. 1227 net::HttpRequestHeaders new_headers_modified; 1228 new_headers_modified.AddHeadersFromString("key1: value1\r\n" 1229 "key2: value3\r\n"); 1230 scoped_ptr<EventResponseDelta> delta_modified( 1231 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, 1232 &old_headers, &new_headers_modified)); 1233 ASSERT_TRUE(delta_modified.get()); 1234 EXPECT_TRUE(delta_modified->deleted_request_headers.empty()); 1235 ASSERT_TRUE( 1236 delta_modified->modified_request_headers.GetHeader("key2", &value)); 1237 EXPECT_EQ("value3", value); 1238 1239 // Test modifying a header if extension author just appended a new (key, 1240 // value) pair with a key that existed before. This is incorrect 1241 // usage of the API that shall be handled gracefully. 1242 net::HttpRequestHeaders new_headers_modified2; 1243 new_headers_modified2.AddHeadersFromString("key1: value1\r\n" 1244 "key2: value2\r\n" 1245 "key2: value3\r\n"); 1246 scoped_ptr<EventResponseDelta> delta_modified2( 1247 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel, 1248 &old_headers, &new_headers_modified)); 1249 ASSERT_TRUE(delta_modified2.get()); 1250 EXPECT_TRUE(delta_modified2->deleted_request_headers.empty()); 1251 ASSERT_TRUE( 1252 delta_modified2->modified_request_headers.GetHeader("key2", &value)); 1253 EXPECT_EQ("value3", value); 1254 } 1255 1256 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnHeadersReceivedDelta) { 1257 const bool cancel = true; 1258 char base_headers_string[] = 1259 "HTTP/1.0 200 OK\r\n" 1260 "Key1: Value1\r\n" 1261 "Key2: Value2, Bar\r\n" 1262 "Key3: Value3\r\n" 1263 "\r\n"; 1264 scoped_refptr<net::HttpResponseHeaders> base_headers( 1265 new net::HttpResponseHeaders( 1266 net::HttpUtil::AssembleRawHeaders( 1267 base_headers_string, sizeof(base_headers_string)))); 1268 1269 ResponseHeaders new_headers; 1270 new_headers.push_back(ResponseHeader("kEy1", "Value1")); // Unchanged 1271 new_headers.push_back(ResponseHeader("Key2", "Value1")); // Modified 1272 // Key3 is deleted 1273 new_headers.push_back(ResponseHeader("Key4", "Value4")); // Added 1274 1275 scoped_ptr<EventResponseDelta> delta(CalculateOnHeadersReceivedDelta( 1276 "extid", base::Time::Now(), cancel, base_headers.get(), &new_headers)); 1277 ASSERT_TRUE(delta.get()); 1278 EXPECT_TRUE(delta->cancel); 1279 EXPECT_EQ(2u, delta->added_response_headers.size()); 1280 EXPECT_TRUE(Contains(delta->added_response_headers, 1281 ResponseHeader("Key2", "Value1"))); 1282 EXPECT_TRUE(Contains(delta->added_response_headers, 1283 ResponseHeader("Key4", "Value4"))); 1284 EXPECT_EQ(2u, delta->deleted_response_headers.size()); 1285 EXPECT_TRUE(Contains(delta->deleted_response_headers, 1286 ResponseHeader("Key2", "Value2, Bar"))); 1287 EXPECT_TRUE(Contains(delta->deleted_response_headers, 1288 ResponseHeader("Key3", "Value3"))); 1289 } 1290 1291 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnAuthRequiredDelta) { 1292 const bool cancel = true; 1293 1294 string16 username = ASCIIToUTF16("foo"); 1295 string16 password = ASCIIToUTF16("bar"); 1296 scoped_ptr<net::AuthCredentials> credentials( 1297 new net::AuthCredentials(username, password)); 1298 1299 scoped_ptr<EventResponseDelta> delta( 1300 CalculateOnAuthRequiredDelta("extid", base::Time::Now(), cancel, 1301 &credentials)); 1302 ASSERT_TRUE(delta.get()); 1303 EXPECT_TRUE(delta->cancel); 1304 ASSERT_TRUE(delta->auth_credentials.get()); 1305 EXPECT_EQ(username, delta->auth_credentials->username()); 1306 EXPECT_EQ(password, delta->auth_credentials->password()); 1307 } 1308 1309 TEST(ExtensionWebRequestHelpersTest, TestMergeCancelOfResponses) { 1310 EventResponseDeltas deltas; 1311 net::CapturingBoundNetLog capturing_net_log; 1312 net::BoundNetLog net_log = capturing_net_log.bound(); 1313 bool canceled = false; 1314 1315 // Single event that does not cancel. 1316 linked_ptr<EventResponseDelta> d1( 1317 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000))); 1318 d1->cancel = false; 1319 deltas.push_back(d1); 1320 MergeCancelOfResponses(deltas, &canceled, &net_log); 1321 EXPECT_FALSE(canceled); 1322 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1323 1324 // Second event that cancels the request 1325 linked_ptr<EventResponseDelta> d2( 1326 new EventResponseDelta("extid2", base::Time::FromInternalValue(500))); 1327 d2->cancel = true; 1328 deltas.push_back(d2); 1329 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1330 MergeCancelOfResponses(deltas, &canceled, &net_log); 1331 EXPECT_TRUE(canceled); 1332 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1333 } 1334 1335 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses) { 1336 EventResponseDeltas deltas; 1337 net::CapturingBoundNetLog capturing_net_log; 1338 net::BoundNetLog net_log = capturing_net_log.bound(); 1339 ExtensionWarningSet warning_set; 1340 GURL effective_new_url; 1341 1342 // No redirect 1343 linked_ptr<EventResponseDelta> d0( 1344 new EventResponseDelta("extid0", base::Time::FromInternalValue(0))); 1345 deltas.push_back(d0); 1346 MergeOnBeforeRequestResponses( 1347 deltas, &effective_new_url, &warning_set, &net_log); 1348 EXPECT_TRUE(effective_new_url.is_empty()); 1349 1350 // Single redirect. 1351 GURL new_url_1("http://foo.com"); 1352 linked_ptr<EventResponseDelta> d1( 1353 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000))); 1354 d1->new_url = GURL(new_url_1); 1355 deltas.push_back(d1); 1356 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1357 capturing_net_log.Clear(); 1358 MergeOnBeforeRequestResponses( 1359 deltas, &effective_new_url, &warning_set, &net_log); 1360 EXPECT_EQ(new_url_1, effective_new_url); 1361 EXPECT_TRUE(warning_set.empty()); 1362 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1363 1364 // Ignored redirect (due to precedence). 1365 GURL new_url_2("http://bar.com"); 1366 linked_ptr<EventResponseDelta> d2( 1367 new EventResponseDelta("extid2", base::Time::FromInternalValue(500))); 1368 d2->new_url = GURL(new_url_2); 1369 deltas.push_back(d2); 1370 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1371 warning_set.clear(); 1372 capturing_net_log.Clear(); 1373 MergeOnBeforeRequestResponses( 1374 deltas, &effective_new_url, &warning_set, &net_log); 1375 EXPECT_EQ(new_url_1, effective_new_url); 1376 EXPECT_EQ(1u, warning_set.size()); 1377 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 1378 EXPECT_EQ(2u, capturing_net_log.GetSize()); 1379 1380 // Overriding redirect. 1381 GURL new_url_3("http://baz.com"); 1382 linked_ptr<EventResponseDelta> d3( 1383 new EventResponseDelta("extid3", base::Time::FromInternalValue(1500))); 1384 d3->new_url = GURL(new_url_3); 1385 deltas.push_back(d3); 1386 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1387 warning_set.clear(); 1388 capturing_net_log.Clear(); 1389 MergeOnBeforeRequestResponses( 1390 deltas, &effective_new_url, &warning_set, &net_log); 1391 EXPECT_EQ(new_url_3, effective_new_url); 1392 EXPECT_EQ(2u, warning_set.size()); 1393 EXPECT_TRUE(HasWarning(warning_set, "extid1")); 1394 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 1395 EXPECT_EQ(3u, capturing_net_log.GetSize()); 1396 1397 // Check that identical redirects don't cause a conflict. 1398 linked_ptr<EventResponseDelta> d4( 1399 new EventResponseDelta("extid4", base::Time::FromInternalValue(2000))); 1400 d4->new_url = GURL(new_url_3); 1401 deltas.push_back(d4); 1402 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1403 warning_set.clear(); 1404 capturing_net_log.Clear(); 1405 MergeOnBeforeRequestResponses( 1406 deltas, &effective_new_url, &warning_set, &net_log); 1407 EXPECT_EQ(new_url_3, effective_new_url); 1408 EXPECT_EQ(2u, warning_set.size()); 1409 EXPECT_TRUE(HasWarning(warning_set, "extid1")); 1410 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 1411 EXPECT_EQ(4u, capturing_net_log.GetSize()); 1412 } 1413 1414 // This tests that we can redirect to data:// urls, which is considered 1415 // a kind of cancelling requests. 1416 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses2) { 1417 EventResponseDeltas deltas; 1418 net::CapturingBoundNetLog capturing_net_log; 1419 net::BoundNetLog net_log = capturing_net_log.bound(); 1420 ExtensionWarningSet warning_set; 1421 GURL effective_new_url; 1422 1423 // Single redirect. 1424 GURL new_url_0("http://foo.com"); 1425 linked_ptr<EventResponseDelta> d0( 1426 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000))); 1427 d0->new_url = GURL(new_url_0); 1428 deltas.push_back(d0); 1429 MergeOnBeforeRequestResponses( 1430 deltas, &effective_new_url, &warning_set, &net_log); 1431 EXPECT_EQ(new_url_0, effective_new_url); 1432 1433 // Cancel request by redirecting to a data:// URL. This shall override 1434 // the other redirect but not cause any conflict warnings. 1435 GURL new_url_1("data://foo"); 1436 linked_ptr<EventResponseDelta> d1( 1437 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500))); 1438 d1->new_url = GURL(new_url_1); 1439 deltas.push_back(d1); 1440 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1441 warning_set.clear(); 1442 capturing_net_log.Clear(); 1443 MergeOnBeforeRequestResponses( 1444 deltas, &effective_new_url, &warning_set, &net_log); 1445 EXPECT_EQ(new_url_1, effective_new_url); 1446 EXPECT_TRUE(warning_set.empty()); 1447 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1448 1449 // Cancel request by redirecting to the same data:// URL. This shall 1450 // not create any conflicts as it is in line with d1. 1451 GURL new_url_2("data://foo"); 1452 linked_ptr<EventResponseDelta> d2( 1453 new EventResponseDelta("extid2", base::Time::FromInternalValue(1000))); 1454 d2->new_url = GURL(new_url_2); 1455 deltas.push_back(d2); 1456 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1457 warning_set.clear(); 1458 capturing_net_log.Clear(); 1459 MergeOnBeforeRequestResponses( 1460 deltas, &effective_new_url, &warning_set, &net_log); 1461 EXPECT_EQ(new_url_1, effective_new_url); 1462 EXPECT_TRUE(warning_set.empty()); 1463 EXPECT_EQ(2u, capturing_net_log.GetSize()); 1464 1465 // Cancel redirect by redirecting to a different data:// URL. This needs 1466 // to create a conflict. 1467 GURL new_url_3("data://something_totally_different"); 1468 linked_ptr<EventResponseDelta> d3( 1469 new EventResponseDelta("extid3", base::Time::FromInternalValue(500))); 1470 d3->new_url = GURL(new_url_3); 1471 deltas.push_back(d3); 1472 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1473 warning_set.clear(); 1474 capturing_net_log.Clear(); 1475 MergeOnBeforeRequestResponses( 1476 deltas, &effective_new_url, &warning_set, &net_log); 1477 EXPECT_EQ(new_url_1, effective_new_url); 1478 EXPECT_EQ(1u, warning_set.size()); 1479 EXPECT_TRUE(HasWarning(warning_set, "extid3")); 1480 EXPECT_EQ(3u, capturing_net_log.GetSize()); 1481 } 1482 1483 // This tests that we can redirect to about:blank, which is considered 1484 // a kind of cancelling requests. 1485 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses3) { 1486 EventResponseDeltas deltas; 1487 net::CapturingBoundNetLog capturing_net_log; 1488 net::BoundNetLog net_log = capturing_net_log.bound(); 1489 ExtensionWarningSet warning_set; 1490 GURL effective_new_url; 1491 1492 // Single redirect. 1493 GURL new_url_0("http://foo.com"); 1494 linked_ptr<EventResponseDelta> d0( 1495 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000))); 1496 d0->new_url = GURL(new_url_0); 1497 deltas.push_back(d0); 1498 MergeOnBeforeRequestResponses( 1499 deltas, &effective_new_url, &warning_set, &net_log); 1500 EXPECT_EQ(new_url_0, effective_new_url); 1501 1502 // Cancel request by redirecting to about:blank. This shall override 1503 // the other redirect but not cause any conflict warnings. 1504 GURL new_url_1("about:blank"); 1505 linked_ptr<EventResponseDelta> d1( 1506 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500))); 1507 d1->new_url = GURL(new_url_1); 1508 deltas.push_back(d1); 1509 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1510 warning_set.clear(); 1511 capturing_net_log.Clear(); 1512 MergeOnBeforeRequestResponses( 1513 deltas, &effective_new_url, &warning_set, &net_log); 1514 EXPECT_EQ(new_url_1, effective_new_url); 1515 EXPECT_TRUE(warning_set.empty()); 1516 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1517 } 1518 1519 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) { 1520 net::HttpRequestHeaders base_headers; 1521 base_headers.AddHeaderFromString("key1: value 1"); 1522 base_headers.AddHeaderFromString("key2: value 2"); 1523 net::CapturingBoundNetLog capturing_net_log; 1524 net::BoundNetLog net_log = capturing_net_log.bound(); 1525 ExtensionWarningSet warning_set; 1526 std::string header_value; 1527 EventResponseDeltas deltas; 1528 1529 // Check that we can handle not changing the headers. 1530 linked_ptr<EventResponseDelta> d0( 1531 new EventResponseDelta("extid0", base::Time::FromInternalValue(2500))); 1532 deltas.push_back(d0); 1533 net::HttpRequestHeaders headers0; 1534 headers0.MergeFrom(base_headers); 1535 MergeOnBeforeSendHeadersResponses(deltas, &headers0, &warning_set, &net_log); 1536 ASSERT_TRUE(headers0.GetHeader("key1", &header_value)); 1537 EXPECT_EQ("value 1", header_value); 1538 ASSERT_TRUE(headers0.GetHeader("key2", &header_value)); 1539 EXPECT_EQ("value 2", header_value); 1540 EXPECT_EQ(0u, warning_set.size()); 1541 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1542 1543 // Delete, modify and add a header. 1544 linked_ptr<EventResponseDelta> d1( 1545 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); 1546 d1->deleted_request_headers.push_back("key1"); 1547 d1->modified_request_headers.AddHeaderFromString("key2: value 3"); 1548 d1->modified_request_headers.AddHeaderFromString("key3: value 3"); 1549 deltas.push_back(d1); 1550 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1551 warning_set.clear(); 1552 capturing_net_log.Clear(); 1553 net::HttpRequestHeaders headers1; 1554 headers1.MergeFrom(base_headers); 1555 MergeOnBeforeSendHeadersResponses(deltas, &headers1, &warning_set, &net_log); 1556 EXPECT_FALSE(headers1.HasHeader("key1")); 1557 ASSERT_TRUE(headers1.GetHeader("key2", &header_value)); 1558 EXPECT_EQ("value 3", header_value); 1559 ASSERT_TRUE(headers1.GetHeader("key3", &header_value)); 1560 EXPECT_EQ("value 3", header_value); 1561 EXPECT_EQ(0u, warning_set.size()); 1562 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1563 1564 // Check that conflicts are atomic, i.e. if one header modification 1565 // collides all other conflicts of the same extension are declined as well. 1566 linked_ptr<EventResponseDelta> d2( 1567 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); 1568 // This one conflicts: 1569 d2->modified_request_headers.AddHeaderFromString("key3: value 0"); 1570 d2->modified_request_headers.AddHeaderFromString("key4: value 4"); 1571 deltas.push_back(d2); 1572 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1573 warning_set.clear(); 1574 capturing_net_log.Clear(); 1575 net::HttpRequestHeaders headers2; 1576 headers2.MergeFrom(base_headers); 1577 MergeOnBeforeSendHeadersResponses(deltas, &headers2, &warning_set, &net_log); 1578 EXPECT_FALSE(headers2.HasHeader("key1")); 1579 ASSERT_TRUE(headers2.GetHeader("key2", &header_value)); 1580 EXPECT_EQ("value 3", header_value); 1581 ASSERT_TRUE(headers2.GetHeader("key3", &header_value)); 1582 EXPECT_EQ("value 3", header_value); 1583 EXPECT_FALSE(headers2.HasHeader("key4")); 1584 EXPECT_EQ(1u, warning_set.size()); 1585 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 1586 EXPECT_EQ(2u, capturing_net_log.GetSize()); 1587 1588 // Check that identical modifications don't conflict and operations 1589 // can be merged. 1590 linked_ptr<EventResponseDelta> d3( 1591 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000))); 1592 d3->deleted_request_headers.push_back("key1"); 1593 d3->modified_request_headers.AddHeaderFromString("key2: value 3"); 1594 d3->modified_request_headers.AddHeaderFromString("key5: value 5"); 1595 deltas.push_back(d3); 1596 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1597 warning_set.clear(); 1598 capturing_net_log.Clear(); 1599 net::HttpRequestHeaders headers3; 1600 headers3.MergeFrom(base_headers); 1601 MergeOnBeforeSendHeadersResponses(deltas, &headers3, &warning_set, &net_log); 1602 EXPECT_FALSE(headers3.HasHeader("key1")); 1603 ASSERT_TRUE(headers3.GetHeader("key2", &header_value)); 1604 EXPECT_EQ("value 3", header_value); 1605 ASSERT_TRUE(headers3.GetHeader("key3", &header_value)); 1606 EXPECT_EQ("value 3", header_value); 1607 ASSERT_TRUE(headers3.GetHeader("key5", &header_value)); 1608 EXPECT_EQ("value 5", header_value); 1609 EXPECT_EQ(1u, warning_set.size()); 1610 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 1611 EXPECT_EQ(3u, capturing_net_log.GetSize()); 1612 } 1613 1614 TEST(ExtensionWebRequestHelpersTest, 1615 TestMergeOnBeforeSendHeadersResponses_Cookies) { 1616 net::HttpRequestHeaders base_headers; 1617 base_headers.AddHeaderFromString( 1618 "Cookie: name=value; name2=value2; name3=\"value3\""); 1619 net::CapturingBoundNetLog capturing_net_log; 1620 net::BoundNetLog net_log = capturing_net_log.bound(); 1621 ExtensionWarningSet warning_set; 1622 std::string header_value; 1623 EventResponseDeltas deltas; 1624 1625 linked_ptr<RequestCookieModification> add_cookie = 1626 make_linked_ptr(new RequestCookieModification); 1627 add_cookie->type = helpers::ADD; 1628 add_cookie->modification.reset(new helpers::RequestCookie); 1629 add_cookie->modification->name.reset(new std::string("name4")); 1630 add_cookie->modification->value.reset(new std::string("\"value 4\"")); 1631 1632 linked_ptr<RequestCookieModification> add_cookie_2 = 1633 make_linked_ptr(new RequestCookieModification); 1634 add_cookie_2->type = helpers::ADD; 1635 add_cookie_2->modification.reset(new helpers::RequestCookie); 1636 add_cookie_2->modification->name.reset(new std::string("name")); 1637 add_cookie_2->modification->value.reset(new std::string("new value")); 1638 1639 linked_ptr<RequestCookieModification> edit_cookie = 1640 make_linked_ptr(new RequestCookieModification); 1641 edit_cookie->type = helpers::EDIT; 1642 edit_cookie->filter.reset(new helpers::RequestCookie); 1643 edit_cookie->filter->name.reset(new std::string("name2")); 1644 edit_cookie->modification.reset(new helpers::RequestCookie); 1645 edit_cookie->modification->value.reset(new std::string("new value")); 1646 1647 linked_ptr<RequestCookieModification> remove_cookie = 1648 make_linked_ptr(new RequestCookieModification); 1649 remove_cookie->type = helpers::REMOVE; 1650 remove_cookie->filter.reset(new helpers::RequestCookie); 1651 remove_cookie->filter->name.reset(new std::string("name3")); 1652 1653 linked_ptr<RequestCookieModification> operations[] = { 1654 add_cookie, add_cookie_2, edit_cookie, remove_cookie 1655 }; 1656 1657 for (size_t i = 0; i < arraysize(operations); ++i) { 1658 linked_ptr<EventResponseDelta> delta( 1659 new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5))); 1660 delta->request_cookie_modifications.push_back(operations[i]); 1661 deltas.push_back(delta); 1662 } 1663 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1664 net::HttpRequestHeaders headers1; 1665 headers1.MergeFrom(base_headers); 1666 warning_set.clear(); 1667 MergeOnBeforeSendHeadersResponses(deltas, &headers1, &warning_set, &net_log); 1668 EXPECT_TRUE(headers1.HasHeader("Cookie")); 1669 ASSERT_TRUE(headers1.GetHeader("Cookie", &header_value)); 1670 EXPECT_EQ("name=new value; name2=new value; name4=\"value 4\"", header_value); 1671 EXPECT_EQ(0u, warning_set.size()); 1672 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1673 } 1674 1675 namespace { 1676 1677 std::string GetCookieExpirationDate(int delta_secs) { 1678 const char* const kWeekDays[] = { 1679 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 1680 }; 1681 const char* const kMonthNames[] = { 1682 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1683 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 1684 }; 1685 1686 Time::Exploded exploded_time; 1687 (Time::Now() + TimeDelta::FromSeconds(delta_secs)).UTCExplode(&exploded_time); 1688 1689 return base::StringPrintf("%s, %d %s %d %.2d:%.2d:%.2d GMT", 1690 kWeekDays[exploded_time.day_of_week], 1691 exploded_time.day_of_month, 1692 kMonthNames[exploded_time.month - 1], 1693 exploded_time.year, 1694 exploded_time.hour, 1695 exploded_time.minute, 1696 exploded_time.second); 1697 } 1698 1699 } // namespace 1700 1701 TEST(ExtensionWebRequestHelpersTest, 1702 TestMergeCookiesInOnHeadersReceivedResponses) { 1703 net::CapturingBoundNetLog capturing_net_log; 1704 net::BoundNetLog net_log = capturing_net_log.bound(); 1705 ExtensionWarningSet warning_set; 1706 std::string header_value; 1707 EventResponseDeltas deltas; 1708 1709 std::string cookie_expiration = GetCookieExpirationDate(1200); 1710 std::string base_headers_string = 1711 "HTTP/1.0 200 OK\r\n" 1712 "Foo: Bar\r\n" 1713 "Set-Cookie: name=value; DOMAIN=google.com; Secure\r\n" 1714 "Set-Cookie: name2=value2\r\n" 1715 "Set-Cookie: name3=value3\r\n" 1716 "Set-Cookie: lBound1=value5; Expires=" + cookie_expiration + "\r\n" 1717 "Set-Cookie: lBound2=value6; Max-Age=1200\r\n" 1718 "Set-Cookie: lBound3=value7; Max-Age=2000\r\n" 1719 "Set-Cookie: uBound1=value8; Expires=" + cookie_expiration + "\r\n" 1720 "Set-Cookie: uBound2=value9; Max-Age=1200\r\n" 1721 "Set-Cookie: uBound3=value10; Max-Age=2000\r\n" 1722 "Set-Cookie: uBound4=value11; Max-Age=2500\r\n" 1723 "Set-Cookie: uBound5=value12; Max-Age=600; Expires=" + 1724 cookie_expiration + "\r\n" 1725 "Set-Cookie: uBound6=removed; Max-Age=600\r\n" 1726 "Set-Cookie: sessionCookie=removed; Max-Age=INVALID\r\n" 1727 "Set-Cookie: sessionCookie2=removed\r\n" 1728 "\r\n"; 1729 scoped_refptr<net::HttpResponseHeaders> base_headers( 1730 new net::HttpResponseHeaders( 1731 net::HttpUtil::AssembleRawHeaders( 1732 base_headers_string.c_str(), base_headers_string.size()))); 1733 1734 // Check that we can handle if not touching the response headers. 1735 linked_ptr<EventResponseDelta> d0( 1736 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000))); 1737 deltas.push_back(d0); 1738 scoped_refptr<net::HttpResponseHeaders> new_headers0; 1739 MergeCookiesInOnHeadersReceivedResponses( 1740 deltas, base_headers.get(), &new_headers0, &warning_set, &net_log); 1741 EXPECT_FALSE(new_headers0.get()); 1742 EXPECT_EQ(0u, warning_set.size()); 1743 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1744 1745 linked_ptr<ResponseCookieModification> add_cookie = 1746 make_linked_ptr(new ResponseCookieModification); 1747 add_cookie->type = helpers::ADD; 1748 add_cookie->modification.reset(new helpers::ResponseCookie); 1749 add_cookie->modification->name.reset(new std::string("name4")); 1750 add_cookie->modification->value.reset(new std::string("\"value4\"")); 1751 1752 linked_ptr<ResponseCookieModification> edit_cookie = 1753 make_linked_ptr(new ResponseCookieModification); 1754 edit_cookie->type = helpers::EDIT; 1755 edit_cookie->filter.reset(new helpers::FilterResponseCookie); 1756 edit_cookie->filter->name.reset(new std::string("name2")); 1757 edit_cookie->modification.reset(new helpers::ResponseCookie); 1758 edit_cookie->modification->value.reset(new std::string("new value")); 1759 1760 linked_ptr<ResponseCookieModification> edit_cookie_2 = 1761 make_linked_ptr(new ResponseCookieModification); 1762 edit_cookie_2->type = helpers::EDIT; 1763 edit_cookie_2->filter.reset(new helpers::FilterResponseCookie); 1764 edit_cookie_2->filter->secure.reset(new bool(false)); 1765 edit_cookie_2->modification.reset(new helpers::ResponseCookie); 1766 edit_cookie_2->modification->secure.reset(new bool(true)); 1767 1768 // Tests 'ageLowerBound' filter when cookie lifetime is set 1769 // in cookie's 'max-age' attribute and its value is greater than 1770 // the filter's value. 1771 linked_ptr<ResponseCookieModification> edit_cookie_3 = 1772 make_linked_ptr(new ResponseCookieModification); 1773 edit_cookie_3->type = helpers::EDIT; 1774 edit_cookie_3->filter.reset(new helpers::FilterResponseCookie); 1775 edit_cookie_3->filter->name.reset(new std::string("lBound1")); 1776 edit_cookie_3->filter->age_lower_bound.reset(new int(600)); 1777 edit_cookie_3->modification.reset(new helpers::ResponseCookie); 1778 edit_cookie_3->modification->value.reset(new std::string("greater_1")); 1779 1780 // Cookie lifetime is set in the cookie's 'expires' attribute. 1781 linked_ptr<ResponseCookieModification> edit_cookie_4 = 1782 make_linked_ptr(new ResponseCookieModification); 1783 edit_cookie_4->type = helpers::EDIT; 1784 edit_cookie_4->filter.reset(new helpers::FilterResponseCookie); 1785 edit_cookie_4->filter->name.reset(new std::string("lBound2")); 1786 edit_cookie_4->filter->age_lower_bound.reset(new int(600)); 1787 edit_cookie_4->modification.reset(new helpers::ResponseCookie); 1788 edit_cookie_4->modification->value.reset(new std::string("greater_2")); 1789 1790 // Tests equality of the cookie lifetime with the filter value when 1791 // lifetime is set in the cookie's 'max-age' attribute. 1792 // Note: we don't test the equality when the lifetime is set in the 'expires' 1793 // attribute because the tests will be flaky. The reason is calculations will 1794 // depend on fetching the current time. 1795 linked_ptr<ResponseCookieModification> edit_cookie_5 = 1796 make_linked_ptr(new ResponseCookieModification); 1797 edit_cookie_5->type = helpers::EDIT; 1798 edit_cookie_5->filter.reset(new helpers::FilterResponseCookie); 1799 edit_cookie_5->filter->name.reset(new std::string("lBound3")); 1800 edit_cookie_5->filter->age_lower_bound.reset(new int(2000)); 1801 edit_cookie_5->modification.reset(new helpers::ResponseCookie); 1802 edit_cookie_5->modification->value.reset(new std::string("equal_2")); 1803 1804 // Tests 'ageUpperBound' filter when cookie lifetime is set 1805 // in cookie's 'max-age' attribute and its value is lower than 1806 // the filter's value. 1807 linked_ptr<ResponseCookieModification> edit_cookie_6 = 1808 make_linked_ptr(new ResponseCookieModification); 1809 edit_cookie_6->type = helpers::EDIT; 1810 edit_cookie_6->filter.reset(new helpers::FilterResponseCookie); 1811 edit_cookie_6->filter->name.reset(new std::string("uBound1")); 1812 edit_cookie_6->filter->age_upper_bound.reset(new int(2000)); 1813 edit_cookie_6->modification.reset(new helpers::ResponseCookie); 1814 edit_cookie_6->modification->value.reset(new std::string("smaller_1")); 1815 1816 // Cookie lifetime is set in the cookie's 'expires' attribute. 1817 linked_ptr<ResponseCookieModification> edit_cookie_7 = 1818 make_linked_ptr(new ResponseCookieModification); 1819 edit_cookie_7->type = helpers::EDIT; 1820 edit_cookie_7->filter.reset(new helpers::FilterResponseCookie); 1821 edit_cookie_7->filter->name.reset(new std::string("uBound2")); 1822 edit_cookie_7->filter->age_upper_bound.reset(new int(2000)); 1823 edit_cookie_7->modification.reset(new helpers::ResponseCookie); 1824 edit_cookie_7->modification->value.reset(new std::string("smaller_2")); 1825 1826 // Tests equality of the cookie lifetime with the filter value when 1827 // lifetime is set in the cookie's 'max-age' attribute. 1828 linked_ptr<ResponseCookieModification> edit_cookie_8 = 1829 make_linked_ptr(new ResponseCookieModification); 1830 edit_cookie_8->type = helpers::EDIT; 1831 edit_cookie_8->filter.reset(new helpers::FilterResponseCookie); 1832 edit_cookie_8->filter->name.reset(new std::string("uBound3")); 1833 edit_cookie_8->filter->age_upper_bound.reset(new int(2000)); 1834 edit_cookie_8->modification.reset(new helpers::ResponseCookie); 1835 edit_cookie_8->modification->value.reset(new std::string("equal_4")); 1836 1837 // Tests 'ageUpperBound' filter when cookie lifetime is greater 1838 // than the filter value. No modification is expected to be applied. 1839 linked_ptr<ResponseCookieModification> edit_cookie_9 = 1840 make_linked_ptr(new ResponseCookieModification); 1841 edit_cookie_9->type = helpers::EDIT; 1842 edit_cookie_9->filter.reset(new helpers::FilterResponseCookie); 1843 edit_cookie_9->filter->name.reset(new std::string("uBound4")); 1844 edit_cookie_9->filter->age_upper_bound.reset(new int(2501)); 1845 edit_cookie_9->modification.reset(new helpers::ResponseCookie); 1846 edit_cookie_9->modification->value.reset(new std::string("Will not change")); 1847 1848 // Tests 'ageUpperBound' filter when both 'max-age' and 'expires' cookie 1849 // attributes are provided. 'expires' value matches the filter, however 1850 // no modification to the cookie is expected because 'max-age' overrides 1851 // 'expires' and it does not match the filter. 1852 linked_ptr<ResponseCookieModification> edit_cookie_10 = 1853 make_linked_ptr(new ResponseCookieModification); 1854 edit_cookie_10->type = helpers::EDIT; 1855 edit_cookie_10->filter.reset(new helpers::FilterResponseCookie); 1856 edit_cookie_10->filter->name.reset(new std::string("uBound5")); 1857 edit_cookie_10->filter->age_upper_bound.reset(new int(800)); 1858 edit_cookie_10->modification.reset(new helpers::ResponseCookie); 1859 edit_cookie_10->modification->value.reset(new std::string("Will not change")); 1860 1861 linked_ptr<ResponseCookieModification> remove_cookie = 1862 make_linked_ptr(new ResponseCookieModification); 1863 remove_cookie->type = helpers::REMOVE; 1864 remove_cookie->filter.reset(new helpers::FilterResponseCookie); 1865 remove_cookie->filter->name.reset(new std::string("name3")); 1866 1867 linked_ptr<ResponseCookieModification> remove_cookie_2 = 1868 make_linked_ptr(new ResponseCookieModification); 1869 remove_cookie_2->type = helpers::REMOVE; 1870 remove_cookie_2->filter.reset(new helpers::FilterResponseCookie); 1871 remove_cookie_2->filter->name.reset(new std::string("uBound6")); 1872 remove_cookie_2->filter->age_upper_bound.reset(new int(700)); 1873 1874 linked_ptr<ResponseCookieModification> remove_cookie_3 = 1875 make_linked_ptr(new ResponseCookieModification); 1876 remove_cookie_3->type = helpers::REMOVE; 1877 remove_cookie_3->filter.reset(new helpers::FilterResponseCookie); 1878 remove_cookie_3->filter->name.reset(new std::string("sessionCookie")); 1879 remove_cookie_3->filter->session_cookie.reset(new bool(true)); 1880 1881 linked_ptr<ResponseCookieModification> remove_cookie_4 = 1882 make_linked_ptr(new ResponseCookieModification); 1883 remove_cookie_4->type = helpers::REMOVE; 1884 remove_cookie_4->filter.reset(new helpers::FilterResponseCookie); 1885 remove_cookie_4->filter->name.reset(new std::string("sessionCookie2")); 1886 remove_cookie_4->filter->session_cookie.reset(new bool(true)); 1887 1888 linked_ptr<ResponseCookieModification> operations[] = { 1889 add_cookie, edit_cookie, edit_cookie_2, edit_cookie_3, edit_cookie_4, 1890 edit_cookie_5, edit_cookie_6, edit_cookie_7, edit_cookie_8, 1891 edit_cookie_9, edit_cookie_10, remove_cookie, remove_cookie_2, 1892 remove_cookie_3, remove_cookie_4 1893 }; 1894 1895 for (size_t i = 0; i < arraysize(operations); ++i) { 1896 linked_ptr<EventResponseDelta> delta( 1897 new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5))); 1898 delta->response_cookie_modifications.push_back(operations[i]); 1899 deltas.push_back(delta); 1900 } 1901 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1902 scoped_refptr<net::HttpResponseHeaders> headers1( 1903 new net::HttpResponseHeaders( 1904 net::HttpUtil::AssembleRawHeaders( 1905 base_headers_string.c_str(), base_headers_string.size()))); 1906 scoped_refptr<net::HttpResponseHeaders> new_headers1; 1907 warning_set.clear(); 1908 MergeCookiesInOnHeadersReceivedResponses( 1909 deltas, headers1.get(), &new_headers1, &warning_set, &net_log); 1910 1911 EXPECT_TRUE(new_headers1->HasHeader("Foo")); 1912 void* iter = NULL; 1913 std::string cookie_string; 1914 std::set<std::string> expected_cookies; 1915 expected_cookies.insert("name=value; domain=google.com; secure"); 1916 expected_cookies.insert("name2=value2; secure"); 1917 expected_cookies.insert("name4=\"value4\"; secure"); 1918 expected_cookies.insert( 1919 "lBound1=greater_1; expires=" + cookie_expiration + "; secure"); 1920 expected_cookies.insert("lBound2=greater_2; max-age=1200; secure"); 1921 expected_cookies.insert("lBound3=equal_2; max-age=2000; secure"); 1922 expected_cookies.insert( 1923 "uBound1=smaller_1; expires=" + cookie_expiration + "; secure"); 1924 expected_cookies.insert("uBound2=smaller_2; max-age=1200; secure"); 1925 expected_cookies.insert("uBound3=equal_4; max-age=2000; secure"); 1926 expected_cookies.insert("uBound4=value11; max-age=2500; secure"); 1927 expected_cookies.insert( 1928 "uBound5=value12; max-age=600; expires=" + cookie_expiration+ "; secure"); 1929 std::set<std::string> actual_cookies; 1930 while (new_headers1->EnumerateHeader(&iter, "Set-Cookie", &cookie_string)) 1931 actual_cookies.insert(cookie_string); 1932 EXPECT_EQ(expected_cookies, actual_cookies); 1933 EXPECT_EQ(0u, warning_set.size()); 1934 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1935 } 1936 1937 TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) { 1938 net::CapturingBoundNetLog capturing_net_log; 1939 net::BoundNetLog net_log = capturing_net_log.bound(); 1940 ExtensionWarningSet warning_set; 1941 std::string header_value; 1942 EventResponseDeltas deltas; 1943 1944 char base_headers_string[] = 1945 "HTTP/1.0 200 OK\r\n" 1946 "Key1: Value1\r\n" 1947 "Key2: Value2, Foo\r\n" 1948 "\r\n"; 1949 scoped_refptr<net::HttpResponseHeaders> base_headers( 1950 new net::HttpResponseHeaders( 1951 net::HttpUtil::AssembleRawHeaders( 1952 base_headers_string, sizeof(base_headers_string)))); 1953 1954 // Check that we can handle if not touching the response headers. 1955 linked_ptr<EventResponseDelta> d0( 1956 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000))); 1957 deltas.push_back(d0); 1958 scoped_refptr<net::HttpResponseHeaders> new_headers0; 1959 MergeOnHeadersReceivedResponses(deltas, base_headers.get(), &new_headers0, 1960 &warning_set, &net_log); 1961 EXPECT_FALSE(new_headers0.get()); 1962 EXPECT_EQ(0u, warning_set.size()); 1963 EXPECT_EQ(0u, capturing_net_log.GetSize()); 1964 1965 linked_ptr<EventResponseDelta> d1( 1966 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); 1967 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value1")); 1968 d1->deleted_response_headers.push_back(ResponseHeader("KEY2", "Value2, Foo")); 1969 d1->added_response_headers.push_back(ResponseHeader("Key2", "Value3")); 1970 deltas.push_back(d1); 1971 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 1972 warning_set.clear(); 1973 capturing_net_log.Clear(); 1974 scoped_refptr<net::HttpResponseHeaders> new_headers1; 1975 MergeOnHeadersReceivedResponses( 1976 deltas, base_headers.get(), &new_headers1, &warning_set, &net_log); 1977 ASSERT_TRUE(new_headers1.get()); 1978 std::multimap<std::string, std::string> expected1; 1979 expected1.insert(std::pair<std::string, std::string>("Key2", "Value3")); 1980 void* iter = NULL; 1981 std::string name; 1982 std::string value; 1983 std::multimap<std::string, std::string> actual1; 1984 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) { 1985 actual1.insert(std::pair<std::string, std::string>(name, value)); 1986 } 1987 EXPECT_EQ(expected1, actual1); 1988 EXPECT_EQ(0u, warning_set.size()); 1989 EXPECT_EQ(1u, capturing_net_log.GetSize()); 1990 1991 // Check that we replace response headers only once. 1992 linked_ptr<EventResponseDelta> d2( 1993 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); 1994 // Note that we use a different capitalization of KeY2. This should not 1995 // matter. 1996 d2->deleted_response_headers.push_back(ResponseHeader("KeY2", "Value2, Foo")); 1997 d2->added_response_headers.push_back(ResponseHeader("Key2", "Value4")); 1998 deltas.push_back(d2); 1999 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 2000 warning_set.clear(); 2001 capturing_net_log.Clear(); 2002 scoped_refptr<net::HttpResponseHeaders> new_headers2; 2003 MergeOnHeadersReceivedResponses( 2004 deltas, base_headers.get(), &new_headers2, &warning_set, &net_log); 2005 ASSERT_TRUE(new_headers2.get()); 2006 iter = NULL; 2007 std::multimap<std::string, std::string> actual2; 2008 while (new_headers2->EnumerateHeaderLines(&iter, &name, &value)) { 2009 actual2.insert(std::pair<std::string, std::string>(name, value)); 2010 } 2011 EXPECT_EQ(expected1, actual2); 2012 EXPECT_EQ(1u, warning_set.size()); 2013 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 2014 EXPECT_EQ(2u, capturing_net_log.GetSize()); 2015 } 2016 2017 // Check that we do not delete too much 2018 TEST(ExtensionWebRequestHelpersTest, 2019 TestMergeOnHeadersReceivedResponsesDeletion) { 2020 net::CapturingBoundNetLog capturing_net_log; 2021 net::BoundNetLog net_log = capturing_net_log.bound(); 2022 ExtensionWarningSet warning_set; 2023 std::string header_value; 2024 EventResponseDeltas deltas; 2025 2026 char base_headers_string[] = 2027 "HTTP/1.0 200 OK\r\n" 2028 "Key1: Value1\r\n" 2029 "Key1: Value2\r\n" 2030 "Key1: Value3\r\n" 2031 "Key2: Value4\r\n" 2032 "\r\n"; 2033 scoped_refptr<net::HttpResponseHeaders> base_headers( 2034 new net::HttpResponseHeaders( 2035 net::HttpUtil::AssembleRawHeaders( 2036 base_headers_string, sizeof(base_headers_string)))); 2037 2038 linked_ptr<EventResponseDelta> d1( 2039 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); 2040 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value2")); 2041 deltas.push_back(d1); 2042 scoped_refptr<net::HttpResponseHeaders> new_headers1; 2043 MergeOnHeadersReceivedResponses( 2044 deltas, base_headers.get(), &new_headers1, &warning_set, &net_log); 2045 ASSERT_TRUE(new_headers1.get()); 2046 std::multimap<std::string, std::string> expected1; 2047 expected1.insert(std::pair<std::string, std::string>("Key1", "Value1")); 2048 expected1.insert(std::pair<std::string, std::string>("Key1", "Value3")); 2049 expected1.insert(std::pair<std::string, std::string>("Key2", "Value4")); 2050 void* iter = NULL; 2051 std::string name; 2052 std::string value; 2053 std::multimap<std::string, std::string> actual1; 2054 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) { 2055 actual1.insert(std::pair<std::string, std::string>(name, value)); 2056 } 2057 EXPECT_EQ(expected1, actual1); 2058 EXPECT_EQ(0u, warning_set.size()); 2059 EXPECT_EQ(1u, capturing_net_log.GetSize()); 2060 } 2061 2062 TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) { 2063 net::CapturingBoundNetLog capturing_net_log; 2064 net::BoundNetLog net_log = capturing_net_log.bound(); 2065 ExtensionWarningSet warning_set; 2066 EventResponseDeltas deltas; 2067 string16 username = ASCIIToUTF16("foo"); 2068 string16 password = ASCIIToUTF16("bar"); 2069 string16 password2 = ASCIIToUTF16("baz"); 2070 2071 // Check that we can handle if not returning credentials. 2072 linked_ptr<EventResponseDelta> d0( 2073 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000))); 2074 deltas.push_back(d0); 2075 net::AuthCredentials auth0; 2076 bool credentials_set = MergeOnAuthRequiredResponses( 2077 deltas, &auth0, &warning_set, &net_log); 2078 EXPECT_FALSE(credentials_set); 2079 EXPECT_TRUE(auth0.Empty()); 2080 EXPECT_EQ(0u, warning_set.size()); 2081 EXPECT_EQ(0u, capturing_net_log.GetSize()); 2082 2083 // Check that we can set AuthCredentials. 2084 linked_ptr<EventResponseDelta> d1( 2085 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000))); 2086 d1->auth_credentials.reset(new net::AuthCredentials(username, password)); 2087 deltas.push_back(d1); 2088 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 2089 warning_set.clear(); 2090 capturing_net_log.Clear(); 2091 net::AuthCredentials auth1; 2092 credentials_set = MergeOnAuthRequiredResponses( 2093 deltas, &auth1, &warning_set, &net_log); 2094 EXPECT_TRUE(credentials_set); 2095 EXPECT_FALSE(auth1.Empty()); 2096 EXPECT_EQ(username, auth1.username()); 2097 EXPECT_EQ(password, auth1.password()); 2098 EXPECT_EQ(0u, warning_set.size()); 2099 EXPECT_EQ(1u, capturing_net_log.GetSize()); 2100 2101 // Check that we set AuthCredentials only once. 2102 linked_ptr<EventResponseDelta> d2( 2103 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500))); 2104 d2->auth_credentials.reset(new net::AuthCredentials(username, password2)); 2105 deltas.push_back(d2); 2106 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 2107 warning_set.clear(); 2108 capturing_net_log.Clear(); 2109 net::AuthCredentials auth2; 2110 credentials_set = MergeOnAuthRequiredResponses( 2111 deltas, &auth2, &warning_set, &net_log); 2112 EXPECT_TRUE(credentials_set); 2113 EXPECT_FALSE(auth2.Empty()); 2114 EXPECT_EQ(username, auth1.username()); 2115 EXPECT_EQ(password, auth1.password()); 2116 EXPECT_EQ(1u, warning_set.size()); 2117 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 2118 EXPECT_EQ(2u, capturing_net_log.GetSize()); 2119 2120 // Check that we can set identical AuthCredentials twice without causing 2121 // a conflict. 2122 linked_ptr<EventResponseDelta> d3( 2123 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000))); 2124 d3->auth_credentials.reset(new net::AuthCredentials(username, password)); 2125 deltas.push_back(d3); 2126 deltas.sort(&InDecreasingExtensionInstallationTimeOrder); 2127 warning_set.clear(); 2128 capturing_net_log.Clear(); 2129 net::AuthCredentials auth3; 2130 credentials_set = MergeOnAuthRequiredResponses( 2131 deltas, &auth3, &warning_set, &net_log); 2132 EXPECT_TRUE(credentials_set); 2133 EXPECT_FALSE(auth3.Empty()); 2134 EXPECT_EQ(username, auth1.username()); 2135 EXPECT_EQ(password, auth1.password()); 2136 EXPECT_EQ(1u, warning_set.size()); 2137 EXPECT_TRUE(HasWarning(warning_set, "extid2")); 2138 EXPECT_EQ(3u, capturing_net_log.GetSize()); 2139 } 2140 2141 } // namespace extensions 2142