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