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