Move Tuple to base namespace.
[chromium-blink-merge.git] / chrome / browser / extensions / api / web_request / web_request_api_unittest.cc
blob797bde9c30e62b76f5bf3a39821bd3fd4e22927b
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/scoped_ptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop/message_loop.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/thread_task_runner_handle.h"
23 #include "base/time/time.h"
24 #include "chrome/browser/content_settings/cookie_settings.h"
25 #include "chrome/browser/extensions/event_router_forwarder.h"
26 #include "chrome/browser/net/about_protocol_handler.h"
27 #include "chrome/browser/net/chrome_network_delegate.h"
28 #include "chrome/test/base/testing_browser_process.h"
29 #include "chrome/test/base/testing_pref_service_syncable.h"
30 #include "chrome/test/base/testing_profile.h"
31 #include "chrome/test/base/testing_profile_manager.h"
32 #include "content/public/common/url_constants.h"
33 #include "content/public/test/test_browser_thread_bundle.h"
34 #include "extensions/browser/api/web_request/upload_data_presenter.h"
35 #include "extensions/browser/api/web_request/web_request_api.h"
36 #include "extensions/browser/api/web_request/web_request_api_constants.h"
37 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
38 #include "extensions/browser/warning_set.h"
39 #include "extensions/common/api/web_request.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/elements_upload_data_stream.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_file_element_reader.h"
48 #include "net/dns/mock_host_resolver.h"
49 #include "net/log/test_net_log.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::core_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 WarningSet& warnings,
108 const std::string& extension_id) {
109 for (WarningSet::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(base::get<3>(*param).GetSize(), 2u);
125 const base::Value* value = NULL;
126 ASSERT_TRUE(base::get<3>(*param).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 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 void SetUp() override {
183 ASSERT_TRUE(profile_manager_.SetUp());
184 ChromeNetworkDelegate::InitializePrefsOnUIThread(
185 &enable_referrers_, NULL, NULL, NULL,
186 profile_.GetTestingPrefService());
187 network_delegate_.reset(
188 new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_));
189 network_delegate_->set_profile(&profile_);
190 network_delegate_->set_cookie_settings(
191 CookieSettings::Factory::GetForProfile(&profile_).get());
192 context_.reset(new net::TestURLRequestContext(true));
193 context_->set_network_delegate(network_delegate_.get());
194 context_->Init();
197 // Fires a URLRequest with the specified |method|, |content_type| and three
198 // elements of upload data: bytes_1, a dummy empty file, bytes_2.
199 void FireURLRequestWithData(const std::string& method,
200 const char* content_type,
201 const std::vector<char>& bytes_1,
202 const std::vector<char>& bytes_2);
204 content::TestBrowserThreadBundle thread_bundle_;
205 TestingProfile profile_;
206 TestingProfileManager profile_manager_;
207 net::TestDelegate delegate_;
208 BooleanPrefMember enable_referrers_;
209 TestIPCSender ipc_sender_;
210 scoped_refptr<EventRouterForwarder> event_router_;
211 scoped_refptr<InfoMap> extension_info_map_;
212 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
213 scoped_ptr<net::TestURLRequestContext> context_;
216 // Tests that we handle disagreements among extensions about responses to
217 // blocking events (redirection) by choosing the response from the
218 // most-recently-installed extension.
219 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) {
220 std::string extension1_id("1");
221 std::string extension2_id("2");
222 ExtensionWebRequestEventRouter::RequestFilter filter;
223 const std::string kEventName(web_request::OnBeforeRequest::kEventName);
224 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
225 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
226 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
227 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0,
228 ipc_sender_factory.GetWeakPtr());
229 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
230 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
231 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0,
232 ipc_sender_factory.GetWeakPtr());
234 net::URLRequestJobFactoryImpl job_factory;
235 job_factory.SetProtocolHandler(
236 url::kAboutScheme, 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 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
243 GURL("about:blank"), net::DEFAULT_PRIORITY, &delegate_));
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));
285 request->Start();
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 scoped_ptr<net::URLRequest> request2(context_->CreateRequest(
298 GURL("about:blank"), net::DEFAULT_PRIORITY, &delegate_));
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));
336 request2->Start();
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", 0, 0);
349 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
350 &profile_, extension2_id, kEventName + "/2", 0, 0);
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, 0, 0,
364 ipc_sender_factory.GetWeakPtr());
365 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
366 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
367 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0,
368 ipc_sender_factory.GetWeakPtr());
370 GURL request_url("about:blank");
371 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
372 request_url, net::DEFAULT_PRIORITY, &delegate_));
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));
400 request->Start();
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", 0, 0);
413 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
414 &profile_, extension2_id, kEventName + "/2", 0, 0);
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
421 // is ignored.
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, 0, 0,
433 ipc_sender_factory.GetWeakPtr());
434 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
435 &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1",
436 filter, 0, 0, 0, ipc_sender_factory.GetWeakPtr());
438 GURL request_url("about:blank");
439 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
440 request_url, net::DEFAULT_PRIORITY, &delegate_));
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()));
461 request->Start();
462 // request->Start() will have submitted OnBeforeRequest by the time we cancel.
463 request->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", 0, 0);
475 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
476 &profile_, extension_id, kEventName2 + "/1", 0, 0);
479 namespace {
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(
491 list_value, result);
494 } // namespace
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 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
504 request_url, net::DEFAULT_PRIORITY, &delegate_));
505 request->set_method(method);
506 if (content_type != NULL) {
507 request->SetExtraRequestHeaderByName(net::HttpRequestHeaders::kContentType,
508 content_type,
509 true /* overwrite */);
511 ScopedVector<net::UploadElementReader> element_readers;
512 element_readers.push_back(new net::UploadBytesElementReader(
513 &(bytes_1[0]), bytes_1.size()));
514 element_readers.push_back(
515 new net::UploadFileElementReader(
516 base::ThreadTaskRunnerHandle::Get()
517 .get(),
518 base::FilePath(),
521 base::Time()));
522 element_readers.push_back(
523 new net::UploadBytesElementReader(&(bytes_2[0]), bytes_2.size()));
524 request->set_upload(make_scoped_ptr(
525 new net::ElementsUploadDataStream(element_readers.Pass(), 0)));
526 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
527 request->Start();
530 TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) {
531 // We verify that URLRequest body is accessible to OnBeforeRequest listeners.
532 // These testing steps are repeated twice in a row:
533 // 1. Register an extension requesting "requestBody" in ExtraInfoSpec and
534 // file a POST URLRequest with a multipart-encoded form. See it getting
535 // parsed.
536 // 2. Do the same, but without requesting "requestBody". Nothing should be
537 // parsed.
538 // 3. With "requestBody", fire a POST URLRequest which is not a parseable
539 // HTML form. Raw data should be returned.
540 // 4. Do the same, but with a PUT method. Result should be the same.
541 const std::string kMethodPost("POST");
542 const std::string kMethodPut("PUT");
544 // Input.
545 const char kPlainBlock1[] = "abcd\n";
546 const size_t kPlainBlock1Length = sizeof(kPlainBlock1) - 1;
547 std::vector<char> plain_1(kPlainBlock1, kPlainBlock1 + kPlainBlock1Length);
548 const char kPlainBlock2[] = "1234\n";
549 const size_t kPlainBlock2Length = sizeof(kPlainBlock2) - 1;
550 std::vector<char> plain_2(kPlainBlock2, kPlainBlock2 + kPlainBlock2Length);
551 #define kBoundary "THIS_IS_A_BOUNDARY"
552 const char kFormBlock1[] = "--" kBoundary "\r\n"
553 "Content-Disposition: form-data; name=\"A\"\r\n"
554 "\r\n"
555 "test text\r\n"
556 "--" kBoundary "\r\n"
557 "Content-Disposition: form-data; name=\"B\"; filename=\"\"\r\n"
558 "Content-Type: application/octet-stream\r\n"
559 "\r\n";
560 std::vector<char> form_1(kFormBlock1, kFormBlock1 + sizeof(kFormBlock1) - 1);
561 const char kFormBlock2[] = "\r\n"
562 "--" kBoundary "\r\n"
563 "Content-Disposition: form-data; name=\"C\"\r\n"
564 "\r\n"
565 "test password\r\n"
566 "--" kBoundary "--";
567 std::vector<char> form_2(kFormBlock2, kFormBlock2 + sizeof(kFormBlock2) - 1);
569 // Expected output.
570 // Paths to look for in returned dictionaries.
571 const std::string kBodyPath(keys::kRequestBodyKey);
572 const std::string kFormDataPath(
573 kBodyPath + "." + keys::kRequestBodyFormDataKey);
574 const std::string kRawPath(kBodyPath + "." + keys::kRequestBodyRawKey);
575 const std::string kErrorPath(kBodyPath + "." + keys::kRequestBodyErrorKey);
576 const std::string* const kPath[] = {
577 &kFormDataPath,
578 &kBodyPath,
579 &kRawPath,
580 &kRawPath
582 // Contents of formData.
583 const char kFormData[] =
584 "{\"A\":[\"test text\"],\"B\":[\"\"],\"C\":[\"test password\"]}";
585 scoped_ptr<const base::Value> form_data(
586 base::JSONReader::DeprecatedRead(kFormData));
587 ASSERT_TRUE(form_data.get() != NULL);
588 ASSERT_TRUE(form_data->GetType() == base::Value::TYPE_DICTIONARY);
589 // Contents of raw.
590 base::ListValue raw;
591 extensions::subtle::AppendKeyValuePair(
592 keys::kRequestBodyRawBytesKey,
593 BinaryValue::CreateWithCopiedBuffer(kPlainBlock1, kPlainBlock1Length),
594 &raw);
595 extensions::subtle::AppendKeyValuePair(
596 keys::kRequestBodyRawFileKey,
597 new base::StringValue(std::string()),
598 &raw);
599 extensions::subtle::AppendKeyValuePair(
600 keys::kRequestBodyRawBytesKey,
601 BinaryValue::CreateWithCopiedBuffer(kPlainBlock2, kPlainBlock2Length),
602 &raw);
603 // Summary.
604 const base::Value* const kExpected[] = {
605 form_data.get(),
606 NULL,
607 &raw,
608 &raw,
610 static_assert(arraysize(kPath) == arraysize(kExpected),
611 "kPath and kExpected arrays should have the same number "
612 "of elements");
613 // Header.
614 const char kMultipart[] = "multipart/form-data; boundary=" kBoundary;
615 #undef kBoundary
617 // Set up a dummy extension name.
618 const std::string kEventName(web_request::OnBeforeRequest::kEventName);
619 ExtensionWebRequestEventRouter::RequestFilter filter;
620 std::string extension_id("1");
621 const std::string string_spec_post("blocking,requestBody");
622 const std::string string_spec_no_post("blocking");
623 int extra_info_spec_empty = 0;
624 int extra_info_spec_body = 0;
625 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
627 // Part 1.
628 // Subscribe to OnBeforeRequest with requestBody requirement.
629 ASSERT_TRUE(GenerateInfoSpec(string_spec_post, &extra_info_spec_body));
630 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
631 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
632 filter, extra_info_spec_body, 0, 0, ipc_sender_factory.GetWeakPtr());
634 FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
636 // We inspect the result in the message list of |ipc_sender_| later.
637 base::MessageLoop::current()->RunUntilIdle();
639 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
640 &profile_, extension_id, kEventName + "/1", 0, 0);
642 // Part 2.
643 // Now subscribe to OnBeforeRequest *without* the requestBody requirement.
644 ASSERT_TRUE(
645 GenerateInfoSpec(string_spec_no_post, &extra_info_spec_empty));
646 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
647 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
648 filter, extra_info_spec_empty, 0, 0, ipc_sender_factory.GetWeakPtr());
650 FireURLRequestWithData(kMethodPost, kMultipart, form_1, form_2);
652 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
653 &profile_, extension_id, kEventName + "/1", 0, 0);
655 // Subscribe to OnBeforeRequest with requestBody requirement.
656 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
657 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
658 filter, extra_info_spec_body, 0, 0, ipc_sender_factory.GetWeakPtr());
660 // Part 3.
661 // Now send a POST request with body which is not parseable as a form.
662 FireURLRequestWithData(kMethodPost, NULL /*no header*/, plain_1, plain_2);
664 // Part 4.
665 // Now send a PUT request with the same body as above.
666 FireURLRequestWithData(kMethodPut, NULL /*no header*/, plain_1, plain_2);
668 base::MessageLoop::current()->RunUntilIdle();
670 // Clean-up.
671 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
672 &profile_, extension_id, kEventName + "/1", 0, 0);
674 IPC::Message* message = NULL;
675 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin();
676 for (size_t test = 0; test < arraysize(kExpected); ++test) {
677 SCOPED_TRACE(testing::Message("iteration number ") << test);
678 EXPECT_NE(i, ipc_sender_.sent_end());
679 message = (i++)->get();
680 const base::DictionaryValue* details;
681 ExtensionMsg_MessageInvoke::Param param;
682 GetPartOfMessageArguments(message, &details, &param);
683 ASSERT_TRUE(details != NULL);
684 const base::Value* result = NULL;
685 if (kExpected[test]) {
686 EXPECT_TRUE(details->Get(*(kPath[test]), &result));
687 EXPECT_TRUE(kExpected[test]->Equals(result));
688 } else {
689 EXPECT_FALSE(details->Get(*(kPath[test]), &result));
693 EXPECT_EQ(i, ipc_sender_.sent_end());
696 TEST_F(ExtensionWebRequestTest, NoAccessRequestBodyData) {
697 // We verify that URLRequest body is NOT accessible to OnBeforeRequest
698 // listeners when the type of the request is different from POST or PUT, or
699 // when the request body is empty. 3 requests are fired, without upload data,
700 // a POST, PUT and GET request. For none of them the "requestBody" object
701 // property should be present in the details passed to the onBeforeRequest
702 // event listener.
703 const char* const kMethods[] = { "POST", "PUT", "GET" };
705 // Set up a dummy extension name.
706 const std::string kEventName(web_request::OnBeforeRequest::kEventName);
707 ExtensionWebRequestEventRouter::RequestFilter filter;
708 const std::string extension_id("1");
709 int extra_info_spec = 0;
710 ASSERT_TRUE(GenerateInfoSpec("blocking,requestBody", &extra_info_spec));
711 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
713 // Subscribe to OnBeforeRequest with requestBody requirement.
714 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
715 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
716 filter, extra_info_spec, 0, 0, ipc_sender_factory.GetWeakPtr());
718 // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
719 const GURL request_url("http://www.example.com");
721 for (size_t i = 0; i < arraysize(kMethods); ++i) {
722 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
723 request_url, net::DEFAULT_PRIORITY, &delegate_));
724 request->set_method(kMethods[i]);
725 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
726 request->Start();
729 // We inspect the result in the message list of |ipc_sender_| later.
730 base::MessageLoop::current()->RunUntilIdle();
732 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
733 &profile_, extension_id, kEventName + "/1", 0, 0);
735 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin();
736 for (size_t test = 0; test < arraysize(kMethods); ++test, ++i) {
737 SCOPED_TRACE(testing::Message("iteration number ") << test);
738 EXPECT_NE(i, ipc_sender_.sent_end());
739 IPC::Message* message = i->get();
740 const base::DictionaryValue* details = NULL;
741 ExtensionMsg_MessageInvoke::Param param;
742 GetPartOfMessageArguments(message, &details, &param);
743 ASSERT_TRUE(details != NULL);
744 EXPECT_FALSE(details->HasKey(keys::kRequestBodyKey));
747 EXPECT_EQ(i, ipc_sender_.sent_end());
750 struct HeaderModificationTest_Header {
751 const char* name;
752 const char* value;
755 struct HeaderModificationTest_Modification {
756 enum Type {
757 SET,
758 REMOVE
761 int extension_id;
762 Type type;
763 const char* key;
764 const char* value;
767 struct HeaderModificationTest {
768 int before_size;
769 HeaderModificationTest_Header before[10];
770 int modification_size;
771 HeaderModificationTest_Modification modification[10];
772 int after_size;
773 HeaderModificationTest_Header after[10];
776 class ExtensionWebRequestHeaderModificationTest
777 : public testing::TestWithParam<HeaderModificationTest> {
778 public:
779 ExtensionWebRequestHeaderModificationTest()
780 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
781 profile_manager_(TestingBrowserProcess::GetGlobal()),
782 event_router_(new EventRouterForwarder) {}
784 protected:
785 void SetUp() override {
786 ASSERT_TRUE(profile_manager_.SetUp());
787 ChromeNetworkDelegate::InitializePrefsOnUIThread(
788 &enable_referrers_, NULL, NULL, NULL,
789 profile_.GetTestingPrefService());
790 network_delegate_.reset(
791 new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_));
792 network_delegate_->set_profile(&profile_);
793 network_delegate_->set_cookie_settings(
794 CookieSettings::Factory::GetForProfile(&profile_).get());
795 context_.reset(new net::TestURLRequestContext(true));
796 host_resolver_.reset(new net::MockHostResolver());
797 host_resolver_->rules()->AddSimulatedFailure("doesnotexist");
798 context_->set_host_resolver(host_resolver_.get());
799 context_->set_network_delegate(network_delegate_.get());
800 context_->Init();
803 content::TestBrowserThreadBundle thread_bundle_;
804 TestingProfile profile_;
805 TestingProfileManager profile_manager_;
806 net::TestDelegate delegate_;
807 BooleanPrefMember enable_referrers_;
808 TestIPCSender ipc_sender_;
809 scoped_refptr<EventRouterForwarder> event_router_;
810 scoped_refptr<InfoMap> extension_info_map_;
811 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
812 scoped_ptr<net::MockHostResolver> host_resolver_;
813 scoped_ptr<net::TestURLRequestContext> context_;
816 TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) {
817 std::string extension1_id("1");
818 std::string extension2_id("2");
819 std::string extension3_id("3");
820 ExtensionWebRequestEventRouter::RequestFilter filter;
821 const std::string kEventName(keys::kOnBeforeSendHeadersEvent);
822 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
824 // Install two extensions that can modify headers. Extension 2 has
825 // higher precedence than extension 1.
826 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
827 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
828 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0,
829 ipc_sender_factory.GetWeakPtr());
830 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
831 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
832 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING, 0, 0,
833 ipc_sender_factory.GetWeakPtr());
835 // Install one extension that observes the final headers.
836 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
837 &profile_, extension3_id, extension3_id, keys::kOnSendHeadersEvent,
838 std::string(keys::kOnSendHeadersEvent) + "/3", filter,
839 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS, 0, 0,
840 ipc_sender_factory.GetWeakPtr());
842 GURL request_url("http://doesnotexist/does_not_exist.html");
843 scoped_ptr<net::URLRequest> request(context_->CreateRequest(
844 request_url, net::DEFAULT_PRIORITY, &delegate_));
846 // Initialize headers available before extensions are notified of the
847 // onBeforeSendHeaders event.
848 HeaderModificationTest test = GetParam();
849 net::HttpRequestHeaders before_headers;
850 for (int i = 0; i < test.before_size; ++i)
851 before_headers.SetHeader(test.before[i].name, test.before[i].value);
852 request->SetExtraRequestHeaders(before_headers);
854 // Gather the modifications to the headers for the respective extensions.
855 // We assume here that all modifications of one extension are listed
856 // in a continuous block of |test.modifications_|.
857 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
858 for (int i = 0; i < test.modification_size; ++i) {
859 const HeaderModificationTest_Modification& mod = test.modification[i];
860 if (response == NULL) {
861 response = new ExtensionWebRequestEventRouter::EventResponse(
862 mod.extension_id == 1 ? extension1_id : extension2_id,
863 base::Time::FromDoubleT(mod.extension_id));
864 response->request_headers.reset(new net::HttpRequestHeaders());
865 response->request_headers->MergeFrom(request->extra_request_headers());
868 switch (mod.type) {
869 case HeaderModificationTest_Modification::SET:
870 response->request_headers->SetHeader(mod.key, mod.value);
871 break;
872 case HeaderModificationTest_Modification::REMOVE:
873 response->request_headers->RemoveHeader(mod.key);
874 break;
877 // Trigger the result when this is the last modification statement or
878 // the block of modifications for the next extension starts.
879 if (i+1 == test.modification_size ||
880 mod.extension_id != test.modification[i+1].extension_id) {
881 ipc_sender_.PushTask(
882 base::Bind(&EventHandledOnIOThread,
883 &profile_, mod.extension_id == 1 ? extension1_id : extension2_id,
884 kEventName, kEventName + (mod.extension_id == 1 ? "/1" : "/2"),
885 request->identifier(), response));
886 response = NULL;
890 // Don't do anything for the onSendHeaders message.
891 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
893 // Note that we mess up the headers slightly:
894 // request->Start() will first add additional headers (e.g. the User-Agent)
895 // and then send an event to the extension. When we have prepared our
896 // answers to the onBeforeSendHeaders events above, these headers did not
897 // exists and are therefore not listed in the responses. This makes
898 // them seem deleted.
899 request->Start();
900 base::MessageLoop::current()->Run();
902 EXPECT_TRUE(!request->is_pending());
903 // This cannot succeed as we send the request to a server that does not exist.
904 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status());
905 EXPECT_EQ(request_url, request->url());
906 EXPECT_EQ(1U, request->url_chain().size());
907 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
909 // Calculate the expected headers.
910 net::HttpRequestHeaders expected_headers;
911 for (int i = 0; i < test.after_size; ++i) {
912 expected_headers.SetHeader(test.after[i].name,
913 test.after[i].value);
916 // Counter for the number of observed onSendHeaders events.
917 int num_headers_observed = 0;
919 // Search the onSendHeaders signal in the IPC messages and check that
920 // it contained the correct headers.
921 TestIPCSender::SentMessages::const_iterator i;
922 for (i = ipc_sender_.sent_begin(); i != ipc_sender_.sent_end(); ++i) {
923 IPC::Message* message = i->get();
924 if (ExtensionMsg_MessageInvoke::ID != message->type())
925 continue;
926 ExtensionMsg_MessageInvoke::Param message_tuple;
927 ExtensionMsg_MessageInvoke::Read(message, &message_tuple);
928 base::ListValue& args = base::get<3>(message_tuple);
930 std::string event_name;
931 if (!args.GetString(0, &event_name) ||
932 event_name != std::string(keys::kOnSendHeadersEvent) + "/3") {
933 continue;
936 base::ListValue* event_arg = NULL;
937 ASSERT_TRUE(args.GetList(1, &event_arg));
939 base::DictionaryValue* event_arg_dict = NULL;
940 ASSERT_TRUE(event_arg->GetDictionary(0, &event_arg_dict));
942 base::ListValue* request_headers = NULL;
943 ASSERT_TRUE(event_arg_dict->GetList(keys::kRequestHeadersKey,
944 &request_headers));
946 net::HttpRequestHeaders observed_headers;
947 for (size_t j = 0; j < request_headers->GetSize(); ++j) {
948 base::DictionaryValue* header = NULL;
949 ASSERT_TRUE(request_headers->GetDictionary(j, &header));
950 std::string key;
951 std::string value;
952 ASSERT_TRUE(header->GetString(keys::kHeaderNameKey, &key));
953 ASSERT_TRUE(header->GetString(keys::kHeaderValueKey, &value));
954 observed_headers.SetHeader(key, value);
957 EXPECT_EQ(expected_headers.ToString(), observed_headers.ToString());
958 ++num_headers_observed;
960 EXPECT_EQ(1, num_headers_observed);
961 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
962 &profile_, extension1_id, kEventName + "/1", 0, 0);
963 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
964 &profile_, extension2_id, kEventName + "/2", 0, 0);
965 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
966 &profile_, extension3_id,
967 std::string(keys::kOnSendHeadersEvent) + "/3", 0, 0);
970 namespace {
972 void TestInitFromValue(const std::string& values, bool expected_return_code,
973 int expected_extra_info_spec) {
974 int actual_info_spec;
975 bool actual_return_code = GenerateInfoSpec(values, &actual_info_spec);
976 EXPECT_EQ(expected_return_code, actual_return_code);
977 if (expected_return_code)
978 EXPECT_EQ(expected_extra_info_spec, actual_info_spec);
981 } // namespace
983 TEST_F(ExtensionWebRequestTest, InitFromValue) {
984 TestInitFromValue(std::string(), true, 0);
986 // Single valid values.
987 TestInitFromValue(
988 "requestHeaders",
989 true,
990 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS);
991 TestInitFromValue(
992 "responseHeaders",
993 true,
994 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS);
995 TestInitFromValue(
996 "blocking",
997 true,
998 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
999 TestInitFromValue(
1000 "asyncBlocking",
1001 true,
1002 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING);
1003 TestInitFromValue(
1004 "requestBody",
1005 true,
1006 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_BODY);
1008 // Multiple valid values are bitwise-or'ed.
1009 TestInitFromValue(
1010 "requestHeaders,blocking",
1011 true,
1012 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS |
1013 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
1015 // Any invalid values lead to a bad parse.
1016 TestInitFromValue("invalidValue", false, 0);
1017 TestInitFromValue("blocking,invalidValue", false, 0);
1018 TestInitFromValue("invalidValue1,invalidValue2", false, 0);
1020 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
1021 TestInitFromValue("blocking,asyncBlocking", false, 0);
1024 namespace {
1026 const HeaderModificationTest_Modification::Type SET =
1027 HeaderModificationTest_Modification::SET;
1028 const HeaderModificationTest_Modification::Type REMOVE =
1029 HeaderModificationTest_Modification::REMOVE;
1031 HeaderModificationTest kTests[] = {
1032 // Check that extension 2 always wins when settings the same header.
1034 // Headers before test.
1035 2, { {"header1", "value1"},
1036 {"header2", "value2"} },
1037 // Modifications in test.
1038 2, { {1, SET, "header1", "foo"},
1039 {2, SET, "header1", "bar"} },
1040 // Headers after test.
1041 2, { {"header1", "bar"},
1042 {"header2", "value2"} }
1044 // Same as before in reverse execution order.
1046 // Headers before test.
1047 2, { {"header1", "value1"},
1048 {"header2", "value2"} },
1049 // Modifications in test.
1050 2, { {2, SET, "header1", "bar"},
1051 {1, SET, "header1", "foo"} },
1052 // Headers after test.
1053 2, { {"header1", "bar"},
1054 {"header2", "value2"} }
1056 // Check that two extensions can modify different headers that do not
1057 // conflict.
1059 // Headers before test.
1060 2, { {"header1", "value1"},
1061 {"header2", "value2"} },
1062 // Modifications in test.
1063 2, { {1, SET, "header1", "foo"},
1064 {2, SET, "header2", "bar"} },
1065 // Headers after test.
1066 2, { {"header1", "foo"},
1067 {"header2", "bar"} }
1069 // Check insert/delete conflict.
1071 // Headers before test.
1072 1, { {"header1", "value1"} },
1073 // Modifications in test.
1074 2, { {1, SET, "header1", "foo"},
1075 {2, REMOVE, "header1", NULL} },
1076 // Headers after test.
1077 0, { }
1080 // Headers before test.
1081 1, { {"header1", "value1"} },
1082 // Modifications in test.
1083 2, { {2, REMOVE, "header1", NULL},
1084 {1, SET, "header1", "foo"} },
1085 // Headers after test.
1086 0, {}
1089 // Headers before test.
1090 1, { {"header1", "value1"} },
1091 // Modifications in test.
1092 2, { {1, REMOVE, "header1", NULL},
1093 {2, SET, "header1", "foo"} },
1094 // Headers after test.
1095 1, { {"header1", "foo"} }
1098 // Headers before test.
1099 1, { {"header1", "value1"} },
1100 // Modifications in test.
1101 2, { {2, SET, "header1", "foo"},
1102 {1, REMOVE, "header1", NULL} },
1103 // Headers after test.
1104 1, { {"header1", "foo"} }
1106 // Check that edits are atomic (i.e. either all edit requests of an
1107 // extension are executed or none).
1109 // Headers before test.
1110 0, { },
1111 // Modifications in test.
1112 3, { {1, SET, "header1", "value1"},
1113 {1, SET, "header2", "value2"},
1114 {2, SET, "header1", "foo"} },
1115 // Headers after test.
1116 1, { {"header1", "foo"} } // set(header2) is ignored
1118 // Check that identical edits do not conflict (set(header2) would be ignored
1119 // if set(header1) were considered a conflict).
1121 // Headers before test.
1122 0, { },
1123 // Modifications in test.
1124 3, { {1, SET, "header1", "value2"},
1125 {1, SET, "header2", "foo"},
1126 {2, SET, "header1", "value2"} },
1127 // Headers after test.
1128 2, { {"header1", "value2"},
1129 {"header2", "foo"} }
1131 // Check that identical deletes do not conflict (set(header2) would be ignored
1132 // if delete(header1) were considered a conflict).
1134 // Headers before test.
1135 1, { {"header1", "value1"} },
1136 // Modifications in test.
1137 3, { {1, REMOVE, "header1", NULL},
1138 {1, SET, "header2", "foo"},
1139 {2, REMOVE, "header1", NULL} },
1140 // Headers after test.
1141 1, { {"header2", "foo"} }
1143 // Check that setting a value to an identical value is not considered an
1144 // edit operation that can conflict.
1146 // Headers before test.
1147 1, { {"header1", "value1"} },
1148 // Modifications in test.
1149 3, { {1, SET, "header1", "foo"},
1150 {1, SET, "header2", "bar"},
1151 {2, SET, "header1", "value1"} },
1152 // Headers after test.
1153 2, { {"header1", "foo"},
1154 {"header2", "bar"} }
1158 INSTANTIATE_TEST_CASE_P(
1159 ExtensionWebRequest,
1160 ExtensionWebRequestHeaderModificationTest,
1161 ::testing::ValuesIn(kTests));
1163 } // namespace
1166 TEST(ExtensionWebRequestHelpersTest,
1167 TestInDecreasingExtensionInstallationTimeOrder) {
1168 linked_ptr<EventResponseDelta> a(
1169 new EventResponseDelta("ext_1", base::Time::FromInternalValue(0)));
1170 linked_ptr<EventResponseDelta> b(
1171 new EventResponseDelta("ext_2", base::Time::FromInternalValue(1000)));
1172 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, a));
1173 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, b));
1174 EXPECT_TRUE(InDecreasingExtensionInstallationTimeOrder(b, a));
1177 TEST(ExtensionWebRequestHelpersTest, TestStringToCharList) {
1178 base::ListValue list_value;
1179 list_value.Append(new base::FundamentalValue('1'));
1180 list_value.Append(new base::FundamentalValue('2'));
1181 list_value.Append(new base::FundamentalValue('3'));
1182 list_value.Append(new base::FundamentalValue(0xFE));
1183 list_value.Append(new base::FundamentalValue(0xD1));
1185 unsigned char char_value[] = {'1', '2', '3', 0xFE, 0xD1};
1186 std::string string_value(reinterpret_cast<char *>(char_value), 5);
1188 scoped_ptr<base::ListValue> converted_list(StringToCharList(string_value));
1189 EXPECT_TRUE(list_value.Equals(converted_list.get()));
1191 std::string converted_string;
1192 EXPECT_TRUE(CharListToString(&list_value, &converted_string));
1193 EXPECT_EQ(string_value, converted_string);
1196 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeRequestDelta) {
1197 const bool cancel = true;
1198 const GURL localhost("http://localhost");
1199 scoped_ptr<EventResponseDelta> delta(
1200 CalculateOnBeforeRequestDelta("extid", base::Time::Now(),
1201 cancel, localhost));
1202 ASSERT_TRUE(delta.get());
1203 EXPECT_TRUE(delta->cancel);
1204 EXPECT_EQ(localhost, delta->new_url);
1207 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeSendHeadersDelta) {
1208 const bool cancel = true;
1209 std::string value;
1210 net::HttpRequestHeaders old_headers;
1211 old_headers.AddHeadersFromString("key1: value1\r\n"
1212 "key2: value2\r\n");
1214 // Test adding a header.
1215 net::HttpRequestHeaders new_headers_added;
1216 new_headers_added.AddHeadersFromString("key1: value1\r\n"
1217 "key3: value3\r\n"
1218 "key2: value2\r\n");
1219 scoped_ptr<EventResponseDelta> delta_added(
1220 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
1221 &old_headers, &new_headers_added));
1222 ASSERT_TRUE(delta_added.get());
1223 EXPECT_TRUE(delta_added->cancel);
1224 ASSERT_TRUE(delta_added->modified_request_headers.GetHeader("key3", &value));
1225 EXPECT_EQ("value3", value);
1227 // Test deleting a header.
1228 net::HttpRequestHeaders new_headers_deleted;
1229 new_headers_deleted.AddHeadersFromString("key1: value1\r\n");
1230 scoped_ptr<EventResponseDelta> delta_deleted(
1231 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
1232 &old_headers, &new_headers_deleted));
1233 ASSERT_TRUE(delta_deleted.get());
1234 ASSERT_EQ(1u, delta_deleted->deleted_request_headers.size());
1235 ASSERT_EQ("key2", delta_deleted->deleted_request_headers.front());
1237 // Test modifying a header.
1238 net::HttpRequestHeaders new_headers_modified;
1239 new_headers_modified.AddHeadersFromString("key1: value1\r\n"
1240 "key2: value3\r\n");
1241 scoped_ptr<EventResponseDelta> delta_modified(
1242 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
1243 &old_headers, &new_headers_modified));
1244 ASSERT_TRUE(delta_modified.get());
1245 EXPECT_TRUE(delta_modified->deleted_request_headers.empty());
1246 ASSERT_TRUE(
1247 delta_modified->modified_request_headers.GetHeader("key2", &value));
1248 EXPECT_EQ("value3", value);
1250 // Test modifying a header if extension author just appended a new (key,
1251 // value) pair with a key that existed before. This is incorrect
1252 // usage of the API that shall be handled gracefully.
1253 net::HttpRequestHeaders new_headers_modified2;
1254 new_headers_modified2.AddHeadersFromString("key1: value1\r\n"
1255 "key2: value2\r\n"
1256 "key2: value3\r\n");
1257 scoped_ptr<EventResponseDelta> delta_modified2(
1258 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
1259 &old_headers, &new_headers_modified));
1260 ASSERT_TRUE(delta_modified2.get());
1261 EXPECT_TRUE(delta_modified2->deleted_request_headers.empty());
1262 ASSERT_TRUE(
1263 delta_modified2->modified_request_headers.GetHeader("key2", &value));
1264 EXPECT_EQ("value3", value);
1267 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnHeadersReceivedDelta) {
1268 const bool cancel = true;
1269 char base_headers_string[] =
1270 "HTTP/1.0 200 OK\r\n"
1271 "Key1: Value1\r\n"
1272 "Key2: Value2, Bar\r\n"
1273 "Key3: Value3\r\n"
1274 "\r\n";
1275 scoped_refptr<net::HttpResponseHeaders> base_headers(
1276 new net::HttpResponseHeaders(
1277 net::HttpUtil::AssembleRawHeaders(
1278 base_headers_string, sizeof(base_headers_string))));
1280 ResponseHeaders new_headers;
1281 new_headers.push_back(ResponseHeader("kEy1", "Value1")); // Unchanged
1282 new_headers.push_back(ResponseHeader("Key2", "Value1")); // Modified
1283 // Key3 is deleted
1284 new_headers.push_back(ResponseHeader("Key4", "Value4")); // Added
1285 GURL effective_new_url;
1287 scoped_ptr<EventResponseDelta> delta(
1288 CalculateOnHeadersReceivedDelta("extid",
1289 base::Time::Now(),
1290 cancel,
1291 effective_new_url,
1292 base_headers.get(),
1293 &new_headers));
1294 ASSERT_TRUE(delta.get());
1295 EXPECT_TRUE(delta->cancel);
1296 EXPECT_EQ(2u, delta->added_response_headers.size());
1297 EXPECT_TRUE(Contains(delta->added_response_headers,
1298 ResponseHeader("Key2", "Value1")));
1299 EXPECT_TRUE(Contains(delta->added_response_headers,
1300 ResponseHeader("Key4", "Value4")));
1301 EXPECT_EQ(2u, delta->deleted_response_headers.size());
1302 EXPECT_TRUE(Contains(delta->deleted_response_headers,
1303 ResponseHeader("Key2", "Value2, Bar")));
1304 EXPECT_TRUE(Contains(delta->deleted_response_headers,
1305 ResponseHeader("Key3", "Value3")));
1308 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnAuthRequiredDelta) {
1309 const bool cancel = true;
1311 base::string16 username = base::ASCIIToUTF16("foo");
1312 base::string16 password = base::ASCIIToUTF16("bar");
1313 scoped_ptr<net::AuthCredentials> credentials(
1314 new net::AuthCredentials(username, password));
1316 scoped_ptr<EventResponseDelta> delta(
1317 CalculateOnAuthRequiredDelta("extid", base::Time::Now(), cancel,
1318 &credentials));
1319 ASSERT_TRUE(delta.get());
1320 EXPECT_TRUE(delta->cancel);
1321 ASSERT_TRUE(delta->auth_credentials.get());
1322 EXPECT_EQ(username, delta->auth_credentials->username());
1323 EXPECT_EQ(password, delta->auth_credentials->password());
1326 TEST(ExtensionWebRequestHelpersTest, TestMergeCancelOfResponses) {
1327 EventResponseDeltas deltas;
1328 net::BoundTestNetLog capturing_net_log;
1329 net::BoundNetLog net_log = capturing_net_log.bound();
1330 bool canceled = false;
1332 // Single event that does not cancel.
1333 linked_ptr<EventResponseDelta> d1(
1334 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000)));
1335 d1->cancel = false;
1336 deltas.push_back(d1);
1337 MergeCancelOfResponses(deltas, &canceled, &net_log);
1338 EXPECT_FALSE(canceled);
1339 EXPECT_EQ(0u, capturing_net_log.GetSize());
1341 // Second event that cancels the request
1342 linked_ptr<EventResponseDelta> d2(
1343 new EventResponseDelta("extid2", base::Time::FromInternalValue(500)));
1344 d2->cancel = true;
1345 deltas.push_back(d2);
1346 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1347 MergeCancelOfResponses(deltas, &canceled, &net_log);
1348 EXPECT_TRUE(canceled);
1349 EXPECT_EQ(1u, capturing_net_log.GetSize());
1352 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses) {
1353 EventResponseDeltas deltas;
1354 net::BoundTestNetLog capturing_net_log;
1355 net::BoundNetLog net_log = capturing_net_log.bound();
1356 WarningSet warning_set;
1357 GURL effective_new_url;
1359 // No redirect
1360 linked_ptr<EventResponseDelta> d0(
1361 new EventResponseDelta("extid0", base::Time::FromInternalValue(0)));
1362 deltas.push_back(d0);
1363 MergeOnBeforeRequestResponses(
1364 deltas, &effective_new_url, &warning_set, &net_log);
1365 EXPECT_TRUE(effective_new_url.is_empty());
1367 // Single redirect.
1368 GURL new_url_1("http://foo.com");
1369 linked_ptr<EventResponseDelta> d1(
1370 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000)));
1371 d1->new_url = GURL(new_url_1);
1372 deltas.push_back(d1);
1373 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1374 capturing_net_log.Clear();
1375 MergeOnBeforeRequestResponses(
1376 deltas, &effective_new_url, &warning_set, &net_log);
1377 EXPECT_EQ(new_url_1, effective_new_url);
1378 EXPECT_TRUE(warning_set.empty());
1379 EXPECT_EQ(1u, capturing_net_log.GetSize());
1381 // Ignored redirect (due to precedence).
1382 GURL new_url_2("http://bar.com");
1383 linked_ptr<EventResponseDelta> d2(
1384 new EventResponseDelta("extid2", base::Time::FromInternalValue(500)));
1385 d2->new_url = GURL(new_url_2);
1386 deltas.push_back(d2);
1387 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1388 warning_set.clear();
1389 capturing_net_log.Clear();
1390 MergeOnBeforeRequestResponses(
1391 deltas, &effective_new_url, &warning_set, &net_log);
1392 EXPECT_EQ(new_url_1, effective_new_url);
1393 EXPECT_EQ(1u, warning_set.size());
1394 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
1395 EXPECT_EQ(2u, capturing_net_log.GetSize());
1397 // Overriding redirect.
1398 GURL new_url_3("http://baz.com");
1399 linked_ptr<EventResponseDelta> d3(
1400 new EventResponseDelta("extid3", base::Time::FromInternalValue(1500)));
1401 d3->new_url = GURL(new_url_3);
1402 deltas.push_back(d3);
1403 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1404 warning_set.clear();
1405 capturing_net_log.Clear();
1406 MergeOnBeforeRequestResponses(
1407 deltas, &effective_new_url, &warning_set, &net_log);
1408 EXPECT_EQ(new_url_3, effective_new_url);
1409 EXPECT_EQ(2u, warning_set.size());
1410 EXPECT_TRUE(HasWarning(warning_set, "extid1"));
1411 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
1412 EXPECT_EQ(3u, capturing_net_log.GetSize());
1414 // Check that identical redirects don't cause a conflict.
1415 linked_ptr<EventResponseDelta> d4(
1416 new EventResponseDelta("extid4", base::Time::FromInternalValue(2000)));
1417 d4->new_url = GURL(new_url_3);
1418 deltas.push_back(d4);
1419 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1420 warning_set.clear();
1421 capturing_net_log.Clear();
1422 MergeOnBeforeRequestResponses(
1423 deltas, &effective_new_url, &warning_set, &net_log);
1424 EXPECT_EQ(new_url_3, effective_new_url);
1425 EXPECT_EQ(2u, warning_set.size());
1426 EXPECT_TRUE(HasWarning(warning_set, "extid1"));
1427 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
1428 EXPECT_EQ(4u, capturing_net_log.GetSize());
1431 // This tests that we can redirect to data:// urls, which is considered
1432 // a kind of cancelling requests.
1433 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses2) {
1434 EventResponseDeltas deltas;
1435 net::BoundTestNetLog capturing_net_log;
1436 net::BoundNetLog net_log = capturing_net_log.bound();
1437 WarningSet warning_set;
1438 GURL effective_new_url;
1440 // Single redirect.
1441 GURL new_url_0("http://foo.com");
1442 linked_ptr<EventResponseDelta> d0(
1443 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000)));
1444 d0->new_url = GURL(new_url_0);
1445 deltas.push_back(d0);
1446 MergeOnBeforeRequestResponses(
1447 deltas, &effective_new_url, &warning_set, &net_log);
1448 EXPECT_EQ(new_url_0, effective_new_url);
1450 // Cancel request by redirecting to a data:// URL. This shall override
1451 // the other redirect but not cause any conflict warnings.
1452 GURL new_url_1("data://foo");
1453 linked_ptr<EventResponseDelta> d1(
1454 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500)));
1455 d1->new_url = GURL(new_url_1);
1456 deltas.push_back(d1);
1457 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1458 warning_set.clear();
1459 capturing_net_log.Clear();
1460 MergeOnBeforeRequestResponses(
1461 deltas, &effective_new_url, &warning_set, &net_log);
1462 EXPECT_EQ(new_url_1, effective_new_url);
1463 EXPECT_TRUE(warning_set.empty());
1464 EXPECT_EQ(1u, capturing_net_log.GetSize());
1466 // Cancel request by redirecting to the same data:// URL. This shall
1467 // not create any conflicts as it is in line with d1.
1468 GURL new_url_2("data://foo");
1469 linked_ptr<EventResponseDelta> d2(
1470 new EventResponseDelta("extid2", base::Time::FromInternalValue(1000)));
1471 d2->new_url = GURL(new_url_2);
1472 deltas.push_back(d2);
1473 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1474 warning_set.clear();
1475 capturing_net_log.Clear();
1476 MergeOnBeforeRequestResponses(
1477 deltas, &effective_new_url, &warning_set, &net_log);
1478 EXPECT_EQ(new_url_1, effective_new_url);
1479 EXPECT_TRUE(warning_set.empty());
1480 EXPECT_EQ(2u, capturing_net_log.GetSize());
1482 // Cancel redirect by redirecting to a different data:// URL. This needs
1483 // to create a conflict.
1484 GURL new_url_3("data://something_totally_different");
1485 linked_ptr<EventResponseDelta> d3(
1486 new EventResponseDelta("extid3", base::Time::FromInternalValue(500)));
1487 d3->new_url = GURL(new_url_3);
1488 deltas.push_back(d3);
1489 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1490 warning_set.clear();
1491 capturing_net_log.Clear();
1492 MergeOnBeforeRequestResponses(
1493 deltas, &effective_new_url, &warning_set, &net_log);
1494 EXPECT_EQ(new_url_1, effective_new_url);
1495 EXPECT_EQ(1u, warning_set.size());
1496 EXPECT_TRUE(HasWarning(warning_set, "extid3"));
1497 EXPECT_EQ(3u, capturing_net_log.GetSize());
1500 // This tests that we can redirect to about:blank, which is considered
1501 // a kind of cancelling requests.
1502 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses3) {
1503 EventResponseDeltas deltas;
1504 net::BoundTestNetLog capturing_net_log;
1505 net::BoundNetLog net_log = capturing_net_log.bound();
1506 WarningSet warning_set;
1507 GURL effective_new_url;
1509 // Single redirect.
1510 GURL new_url_0("http://foo.com");
1511 linked_ptr<EventResponseDelta> d0(
1512 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000)));
1513 d0->new_url = GURL(new_url_0);
1514 deltas.push_back(d0);
1515 MergeOnBeforeRequestResponses(
1516 deltas, &effective_new_url, &warning_set, &net_log);
1517 EXPECT_EQ(new_url_0, effective_new_url);
1519 // Cancel request by redirecting to about:blank. This shall override
1520 // the other redirect but not cause any conflict warnings.
1521 GURL new_url_1("about:blank");
1522 linked_ptr<EventResponseDelta> d1(
1523 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500)));
1524 d1->new_url = GURL(new_url_1);
1525 deltas.push_back(d1);
1526 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1527 warning_set.clear();
1528 capturing_net_log.Clear();
1529 MergeOnBeforeRequestResponses(
1530 deltas, &effective_new_url, &warning_set, &net_log);
1531 EXPECT_EQ(new_url_1, effective_new_url);
1532 EXPECT_TRUE(warning_set.empty());
1533 EXPECT_EQ(1u, capturing_net_log.GetSize());
1536 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) {
1537 net::HttpRequestHeaders base_headers;
1538 base_headers.AddHeaderFromString("key1: value 1");
1539 base_headers.AddHeaderFromString("key2: value 2");
1540 net::BoundTestNetLog capturing_net_log;
1541 net::BoundNetLog net_log = capturing_net_log.bound();
1542 WarningSet warning_set;
1543 std::string header_value;
1544 EventResponseDeltas deltas;
1546 // Check that we can handle not changing the headers.
1547 linked_ptr<EventResponseDelta> d0(
1548 new EventResponseDelta("extid0", base::Time::FromInternalValue(2500)));
1549 deltas.push_back(d0);
1550 net::HttpRequestHeaders headers0;
1551 headers0.MergeFrom(base_headers);
1552 MergeOnBeforeSendHeadersResponses(deltas, &headers0, &warning_set, &net_log);
1553 ASSERT_TRUE(headers0.GetHeader("key1", &header_value));
1554 EXPECT_EQ("value 1", header_value);
1555 ASSERT_TRUE(headers0.GetHeader("key2", &header_value));
1556 EXPECT_EQ("value 2", header_value);
1557 EXPECT_EQ(0u, warning_set.size());
1558 EXPECT_EQ(0u, capturing_net_log.GetSize());
1560 // Delete, modify and add a header.
1561 linked_ptr<EventResponseDelta> d1(
1562 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1563 d1->deleted_request_headers.push_back("key1");
1564 d1->modified_request_headers.AddHeaderFromString("key2: value 3");
1565 d1->modified_request_headers.AddHeaderFromString("key3: value 3");
1566 deltas.push_back(d1);
1567 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1568 warning_set.clear();
1569 capturing_net_log.Clear();
1570 net::HttpRequestHeaders headers1;
1571 headers1.MergeFrom(base_headers);
1572 MergeOnBeforeSendHeadersResponses(deltas, &headers1, &warning_set, &net_log);
1573 EXPECT_FALSE(headers1.HasHeader("key1"));
1574 ASSERT_TRUE(headers1.GetHeader("key2", &header_value));
1575 EXPECT_EQ("value 3", header_value);
1576 ASSERT_TRUE(headers1.GetHeader("key3", &header_value));
1577 EXPECT_EQ("value 3", header_value);
1578 EXPECT_EQ(0u, warning_set.size());
1579 EXPECT_EQ(1u, capturing_net_log.GetSize());
1581 // Check that conflicts are atomic, i.e. if one header modification
1582 // collides all other conflicts of the same extension are declined as well.
1583 linked_ptr<EventResponseDelta> d2(
1584 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
1585 // This one conflicts:
1586 d2->modified_request_headers.AddHeaderFromString("key3: value 0");
1587 d2->modified_request_headers.AddHeaderFromString("key4: value 4");
1588 deltas.push_back(d2);
1589 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1590 warning_set.clear();
1591 capturing_net_log.Clear();
1592 net::HttpRequestHeaders headers2;
1593 headers2.MergeFrom(base_headers);
1594 MergeOnBeforeSendHeadersResponses(deltas, &headers2, &warning_set, &net_log);
1595 EXPECT_FALSE(headers2.HasHeader("key1"));
1596 ASSERT_TRUE(headers2.GetHeader("key2", &header_value));
1597 EXPECT_EQ("value 3", header_value);
1598 ASSERT_TRUE(headers2.GetHeader("key3", &header_value));
1599 EXPECT_EQ("value 3", header_value);
1600 EXPECT_FALSE(headers2.HasHeader("key4"));
1601 EXPECT_EQ(1u, warning_set.size());
1602 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
1603 EXPECT_EQ(2u, capturing_net_log.GetSize());
1605 // Check that identical modifications don't conflict and operations
1606 // can be merged.
1607 linked_ptr<EventResponseDelta> d3(
1608 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000)));
1609 d3->deleted_request_headers.push_back("key1");
1610 d3->modified_request_headers.AddHeaderFromString("key2: value 3");
1611 d3->modified_request_headers.AddHeaderFromString("key5: value 5");
1612 deltas.push_back(d3);
1613 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1614 warning_set.clear();
1615 capturing_net_log.Clear();
1616 net::HttpRequestHeaders headers3;
1617 headers3.MergeFrom(base_headers);
1618 MergeOnBeforeSendHeadersResponses(deltas, &headers3, &warning_set, &net_log);
1619 EXPECT_FALSE(headers3.HasHeader("key1"));
1620 ASSERT_TRUE(headers3.GetHeader("key2", &header_value));
1621 EXPECT_EQ("value 3", header_value);
1622 ASSERT_TRUE(headers3.GetHeader("key3", &header_value));
1623 EXPECT_EQ("value 3", header_value);
1624 ASSERT_TRUE(headers3.GetHeader("key5", &header_value));
1625 EXPECT_EQ("value 5", header_value);
1626 EXPECT_EQ(1u, warning_set.size());
1627 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
1628 EXPECT_EQ(3u, capturing_net_log.GetSize());
1631 TEST(ExtensionWebRequestHelpersTest,
1632 TestMergeOnBeforeSendHeadersResponses_Cookies) {
1633 net::HttpRequestHeaders base_headers;
1634 base_headers.AddHeaderFromString(
1635 "Cookie: name=value; name2=value2; name3=\"value3\"");
1636 net::BoundTestNetLog capturing_net_log;
1637 net::BoundNetLog net_log = capturing_net_log.bound();
1638 WarningSet warning_set;
1639 std::string header_value;
1640 EventResponseDeltas deltas;
1642 linked_ptr<RequestCookieModification> add_cookie =
1643 make_linked_ptr(new RequestCookieModification);
1644 add_cookie->type = helpers::ADD;
1645 add_cookie->modification.reset(new helpers::RequestCookie);
1646 add_cookie->modification->name.reset(new std::string("name4"));
1647 add_cookie->modification->value.reset(new std::string("\"value 4\""));
1649 linked_ptr<RequestCookieModification> add_cookie_2 =
1650 make_linked_ptr(new RequestCookieModification);
1651 add_cookie_2->type = helpers::ADD;
1652 add_cookie_2->modification.reset(new helpers::RequestCookie);
1653 add_cookie_2->modification->name.reset(new std::string("name"));
1654 add_cookie_2->modification->value.reset(new std::string("new value"));
1656 linked_ptr<RequestCookieModification> edit_cookie =
1657 make_linked_ptr(new RequestCookieModification);
1658 edit_cookie->type = helpers::EDIT;
1659 edit_cookie->filter.reset(new helpers::RequestCookie);
1660 edit_cookie->filter->name.reset(new std::string("name2"));
1661 edit_cookie->modification.reset(new helpers::RequestCookie);
1662 edit_cookie->modification->value.reset(new std::string("new value"));
1664 linked_ptr<RequestCookieModification> remove_cookie =
1665 make_linked_ptr(new RequestCookieModification);
1666 remove_cookie->type = helpers::REMOVE;
1667 remove_cookie->filter.reset(new helpers::RequestCookie);
1668 remove_cookie->filter->name.reset(new std::string("name3"));
1670 linked_ptr<RequestCookieModification> operations[] = {
1671 add_cookie, add_cookie_2, edit_cookie, remove_cookie
1674 for (size_t i = 0; i < arraysize(operations); ++i) {
1675 linked_ptr<EventResponseDelta> delta(
1676 new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5)));
1677 delta->request_cookie_modifications.push_back(operations[i]);
1678 deltas.push_back(delta);
1680 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1681 net::HttpRequestHeaders headers1;
1682 headers1.MergeFrom(base_headers);
1683 warning_set.clear();
1684 MergeOnBeforeSendHeadersResponses(deltas, &headers1, &warning_set, &net_log);
1685 EXPECT_TRUE(headers1.HasHeader("Cookie"));
1686 ASSERT_TRUE(headers1.GetHeader("Cookie", &header_value));
1687 EXPECT_EQ("name=new value; name2=new value; name4=\"value 4\"", header_value);
1688 EXPECT_EQ(0u, warning_set.size());
1689 EXPECT_EQ(0u, capturing_net_log.GetSize());
1692 namespace {
1694 std::string GetCookieExpirationDate(int delta_secs) {
1695 const char* const kWeekDays[] = {
1696 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1698 const char* const kMonthNames[] = {
1699 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1700 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1703 Time::Exploded exploded_time;
1704 (Time::Now() + TimeDelta::FromSeconds(delta_secs)).UTCExplode(&exploded_time);
1706 return base::StringPrintf("%s, %d %s %d %.2d:%.2d:%.2d GMT",
1707 kWeekDays[exploded_time.day_of_week],
1708 exploded_time.day_of_month,
1709 kMonthNames[exploded_time.month - 1],
1710 exploded_time.year,
1711 exploded_time.hour,
1712 exploded_time.minute,
1713 exploded_time.second);
1716 } // namespace
1718 TEST(ExtensionWebRequestHelpersTest,
1719 TestMergeCookiesInOnHeadersReceivedResponses) {
1720 net::BoundTestNetLog capturing_net_log;
1721 net::BoundNetLog net_log = capturing_net_log.bound();
1722 WarningSet warning_set;
1723 std::string header_value;
1724 EventResponseDeltas deltas;
1726 std::string cookie_expiration = GetCookieExpirationDate(1200);
1727 std::string base_headers_string =
1728 "HTTP/1.0 200 OK\r\n"
1729 "Foo: Bar\r\n"
1730 "Set-Cookie: name=value; DOMAIN=google.com; Secure\r\n"
1731 "Set-Cookie: name2=value2\r\n"
1732 "Set-Cookie: name3=value3\r\n"
1733 "Set-Cookie: lBound1=value5; Expires=" + cookie_expiration + "\r\n"
1734 "Set-Cookie: lBound2=value6; Max-Age=1200\r\n"
1735 "Set-Cookie: lBound3=value7; Max-Age=2000\r\n"
1736 "Set-Cookie: uBound1=value8; Expires=" + cookie_expiration + "\r\n"
1737 "Set-Cookie: uBound2=value9; Max-Age=1200\r\n"
1738 "Set-Cookie: uBound3=value10; Max-Age=2000\r\n"
1739 "Set-Cookie: uBound4=value11; Max-Age=2500\r\n"
1740 "Set-Cookie: uBound5=value12; Max-Age=600; Expires=" +
1741 cookie_expiration + "\r\n"
1742 "Set-Cookie: uBound6=removed; Max-Age=600\r\n"
1743 "Set-Cookie: sessionCookie=removed; Max-Age=INVALID\r\n"
1744 "Set-Cookie: sessionCookie2=removed\r\n"
1745 "\r\n";
1746 scoped_refptr<net::HttpResponseHeaders> base_headers(
1747 new net::HttpResponseHeaders(
1748 net::HttpUtil::AssembleRawHeaders(
1749 base_headers_string.c_str(), base_headers_string.size())));
1751 // Check that we can handle if not touching the response headers.
1752 linked_ptr<EventResponseDelta> d0(
1753 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
1754 deltas.push_back(d0);
1755 scoped_refptr<net::HttpResponseHeaders> new_headers0;
1756 MergeCookiesInOnHeadersReceivedResponses(
1757 deltas, base_headers.get(), &new_headers0, &warning_set, &net_log);
1758 EXPECT_FALSE(new_headers0.get());
1759 EXPECT_EQ(0u, warning_set.size());
1760 EXPECT_EQ(0u, capturing_net_log.GetSize());
1762 linked_ptr<ResponseCookieModification> add_cookie =
1763 make_linked_ptr(new ResponseCookieModification);
1764 add_cookie->type = helpers::ADD;
1765 add_cookie->modification.reset(new helpers::ResponseCookie);
1766 add_cookie->modification->name.reset(new std::string("name4"));
1767 add_cookie->modification->value.reset(new std::string("\"value4\""));
1769 linked_ptr<ResponseCookieModification> edit_cookie =
1770 make_linked_ptr(new ResponseCookieModification);
1771 edit_cookie->type = helpers::EDIT;
1772 edit_cookie->filter.reset(new helpers::FilterResponseCookie);
1773 edit_cookie->filter->name.reset(new std::string("name2"));
1774 edit_cookie->modification.reset(new helpers::ResponseCookie);
1775 edit_cookie->modification->value.reset(new std::string("new value"));
1777 linked_ptr<ResponseCookieModification> edit_cookie_2 =
1778 make_linked_ptr(new ResponseCookieModification);
1779 edit_cookie_2->type = helpers::EDIT;
1780 edit_cookie_2->filter.reset(new helpers::FilterResponseCookie);
1781 edit_cookie_2->filter->secure.reset(new bool(false));
1782 edit_cookie_2->modification.reset(new helpers::ResponseCookie);
1783 edit_cookie_2->modification->secure.reset(new bool(true));
1785 // Tests 'ageLowerBound' filter when cookie lifetime is set
1786 // in cookie's 'max-age' attribute and its value is greater than
1787 // the filter's value.
1788 linked_ptr<ResponseCookieModification> edit_cookie_3 =
1789 make_linked_ptr(new ResponseCookieModification);
1790 edit_cookie_3->type = helpers::EDIT;
1791 edit_cookie_3->filter.reset(new helpers::FilterResponseCookie);
1792 edit_cookie_3->filter->name.reset(new std::string("lBound1"));
1793 edit_cookie_3->filter->age_lower_bound.reset(new int(600));
1794 edit_cookie_3->modification.reset(new helpers::ResponseCookie);
1795 edit_cookie_3->modification->value.reset(new std::string("greater_1"));
1797 // Cookie lifetime is set in the cookie's 'expires' attribute.
1798 linked_ptr<ResponseCookieModification> edit_cookie_4 =
1799 make_linked_ptr(new ResponseCookieModification);
1800 edit_cookie_4->type = helpers::EDIT;
1801 edit_cookie_4->filter.reset(new helpers::FilterResponseCookie);
1802 edit_cookie_4->filter->name.reset(new std::string("lBound2"));
1803 edit_cookie_4->filter->age_lower_bound.reset(new int(600));
1804 edit_cookie_4->modification.reset(new helpers::ResponseCookie);
1805 edit_cookie_4->modification->value.reset(new std::string("greater_2"));
1807 // Tests equality of the cookie lifetime with the filter value when
1808 // lifetime is set in the cookie's 'max-age' attribute.
1809 // Note: we don't test the equality when the lifetime is set in the 'expires'
1810 // attribute because the tests will be flaky. The reason is calculations will
1811 // depend on fetching the current time.
1812 linked_ptr<ResponseCookieModification> edit_cookie_5 =
1813 make_linked_ptr(new ResponseCookieModification);
1814 edit_cookie_5->type = helpers::EDIT;
1815 edit_cookie_5->filter.reset(new helpers::FilterResponseCookie);
1816 edit_cookie_5->filter->name.reset(new std::string("lBound3"));
1817 edit_cookie_5->filter->age_lower_bound.reset(new int(2000));
1818 edit_cookie_5->modification.reset(new helpers::ResponseCookie);
1819 edit_cookie_5->modification->value.reset(new std::string("equal_2"));
1821 // Tests 'ageUpperBound' filter when cookie lifetime is set
1822 // in cookie's 'max-age' attribute and its value is lower than
1823 // the filter's value.
1824 linked_ptr<ResponseCookieModification> edit_cookie_6 =
1825 make_linked_ptr(new ResponseCookieModification);
1826 edit_cookie_6->type = helpers::EDIT;
1827 edit_cookie_6->filter.reset(new helpers::FilterResponseCookie);
1828 edit_cookie_6->filter->name.reset(new std::string("uBound1"));
1829 edit_cookie_6->filter->age_upper_bound.reset(new int(2000));
1830 edit_cookie_6->modification.reset(new helpers::ResponseCookie);
1831 edit_cookie_6->modification->value.reset(new std::string("smaller_1"));
1833 // Cookie lifetime is set in the cookie's 'expires' attribute.
1834 linked_ptr<ResponseCookieModification> edit_cookie_7 =
1835 make_linked_ptr(new ResponseCookieModification);
1836 edit_cookie_7->type = helpers::EDIT;
1837 edit_cookie_7->filter.reset(new helpers::FilterResponseCookie);
1838 edit_cookie_7->filter->name.reset(new std::string("uBound2"));
1839 edit_cookie_7->filter->age_upper_bound.reset(new int(2000));
1840 edit_cookie_7->modification.reset(new helpers::ResponseCookie);
1841 edit_cookie_7->modification->value.reset(new std::string("smaller_2"));
1843 // Tests equality of the cookie lifetime with the filter value when
1844 // lifetime is set in the cookie's 'max-age' attribute.
1845 linked_ptr<ResponseCookieModification> edit_cookie_8 =
1846 make_linked_ptr(new ResponseCookieModification);
1847 edit_cookie_8->type = helpers::EDIT;
1848 edit_cookie_8->filter.reset(new helpers::FilterResponseCookie);
1849 edit_cookie_8->filter->name.reset(new std::string("uBound3"));
1850 edit_cookie_8->filter->age_upper_bound.reset(new int(2000));
1851 edit_cookie_8->modification.reset(new helpers::ResponseCookie);
1852 edit_cookie_8->modification->value.reset(new std::string("equal_4"));
1854 // Tests 'ageUpperBound' filter when cookie lifetime is greater
1855 // than the filter value. No modification is expected to be applied.
1856 linked_ptr<ResponseCookieModification> edit_cookie_9 =
1857 make_linked_ptr(new ResponseCookieModification);
1858 edit_cookie_9->type = helpers::EDIT;
1859 edit_cookie_9->filter.reset(new helpers::FilterResponseCookie);
1860 edit_cookie_9->filter->name.reset(new std::string("uBound4"));
1861 edit_cookie_9->filter->age_upper_bound.reset(new int(2501));
1862 edit_cookie_9->modification.reset(new helpers::ResponseCookie);
1863 edit_cookie_9->modification->value.reset(new std::string("Will not change"));
1865 // Tests 'ageUpperBound' filter when both 'max-age' and 'expires' cookie
1866 // attributes are provided. 'expires' value matches the filter, however
1867 // no modification to the cookie is expected because 'max-age' overrides
1868 // 'expires' and it does not match the filter.
1869 linked_ptr<ResponseCookieModification> edit_cookie_10 =
1870 make_linked_ptr(new ResponseCookieModification);
1871 edit_cookie_10->type = helpers::EDIT;
1872 edit_cookie_10->filter.reset(new helpers::FilterResponseCookie);
1873 edit_cookie_10->filter->name.reset(new std::string("uBound5"));
1874 edit_cookie_10->filter->age_upper_bound.reset(new int(800));
1875 edit_cookie_10->modification.reset(new helpers::ResponseCookie);
1876 edit_cookie_10->modification->value.reset(new std::string("Will not change"));
1878 linked_ptr<ResponseCookieModification> remove_cookie =
1879 make_linked_ptr(new ResponseCookieModification);
1880 remove_cookie->type = helpers::REMOVE;
1881 remove_cookie->filter.reset(new helpers::FilterResponseCookie);
1882 remove_cookie->filter->name.reset(new std::string("name3"));
1884 linked_ptr<ResponseCookieModification> remove_cookie_2 =
1885 make_linked_ptr(new ResponseCookieModification);
1886 remove_cookie_2->type = helpers::REMOVE;
1887 remove_cookie_2->filter.reset(new helpers::FilterResponseCookie);
1888 remove_cookie_2->filter->name.reset(new std::string("uBound6"));
1889 remove_cookie_2->filter->age_upper_bound.reset(new int(700));
1891 linked_ptr<ResponseCookieModification> remove_cookie_3 =
1892 make_linked_ptr(new ResponseCookieModification);
1893 remove_cookie_3->type = helpers::REMOVE;
1894 remove_cookie_3->filter.reset(new helpers::FilterResponseCookie);
1895 remove_cookie_3->filter->name.reset(new std::string("sessionCookie"));
1896 remove_cookie_3->filter->session_cookie.reset(new bool(true));
1898 linked_ptr<ResponseCookieModification> remove_cookie_4 =
1899 make_linked_ptr(new ResponseCookieModification);
1900 remove_cookie_4->type = helpers::REMOVE;
1901 remove_cookie_4->filter.reset(new helpers::FilterResponseCookie);
1902 remove_cookie_4->filter->name.reset(new std::string("sessionCookie2"));
1903 remove_cookie_4->filter->session_cookie.reset(new bool(true));
1905 linked_ptr<ResponseCookieModification> operations[] = {
1906 add_cookie, edit_cookie, edit_cookie_2, edit_cookie_3, edit_cookie_4,
1907 edit_cookie_5, edit_cookie_6, edit_cookie_7, edit_cookie_8,
1908 edit_cookie_9, edit_cookie_10, remove_cookie, remove_cookie_2,
1909 remove_cookie_3, remove_cookie_4
1912 for (size_t i = 0; i < arraysize(operations); ++i) {
1913 linked_ptr<EventResponseDelta> delta(
1914 new EventResponseDelta("extid0", base::Time::FromInternalValue(i * 5)));
1915 delta->response_cookie_modifications.push_back(operations[i]);
1916 deltas.push_back(delta);
1918 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1919 scoped_refptr<net::HttpResponseHeaders> headers1(
1920 new net::HttpResponseHeaders(
1921 net::HttpUtil::AssembleRawHeaders(
1922 base_headers_string.c_str(), base_headers_string.size())));
1923 scoped_refptr<net::HttpResponseHeaders> new_headers1;
1924 warning_set.clear();
1925 MergeCookiesInOnHeadersReceivedResponses(
1926 deltas, headers1.get(), &new_headers1, &warning_set, &net_log);
1928 EXPECT_TRUE(new_headers1->HasHeader("Foo"));
1929 void* iter = NULL;
1930 std::string cookie_string;
1931 std::set<std::string> expected_cookies;
1932 expected_cookies.insert("name=value; domain=google.com; secure");
1933 expected_cookies.insert("name2=value2; secure");
1934 expected_cookies.insert("name4=\"value4\"; secure");
1935 expected_cookies.insert(
1936 "lBound1=greater_1; expires=" + cookie_expiration + "; secure");
1937 expected_cookies.insert("lBound2=greater_2; max-age=1200; secure");
1938 expected_cookies.insert("lBound3=equal_2; max-age=2000; secure");
1939 expected_cookies.insert(
1940 "uBound1=smaller_1; expires=" + cookie_expiration + "; secure");
1941 expected_cookies.insert("uBound2=smaller_2; max-age=1200; secure");
1942 expected_cookies.insert("uBound3=equal_4; max-age=2000; secure");
1943 expected_cookies.insert("uBound4=value11; max-age=2500; secure");
1944 expected_cookies.insert(
1945 "uBound5=value12; max-age=600; expires=" + cookie_expiration+ "; secure");
1946 std::set<std::string> actual_cookies;
1947 while (new_headers1->EnumerateHeader(&iter, "Set-Cookie", &cookie_string))
1948 actual_cookies.insert(cookie_string);
1949 EXPECT_EQ(expected_cookies, actual_cookies);
1950 EXPECT_EQ(0u, warning_set.size());
1951 EXPECT_EQ(0u, capturing_net_log.GetSize());
1954 TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) {
1955 net::BoundTestNetLog capturing_net_log;
1956 net::BoundNetLog net_log = capturing_net_log.bound();
1957 WarningSet warning_set;
1958 std::string header_value;
1959 EventResponseDeltas deltas;
1961 char base_headers_string[] =
1962 "HTTP/1.0 200 OK\r\n"
1963 "Key1: Value1\r\n"
1964 "Key2: Value2, Foo\r\n"
1965 "\r\n";
1966 scoped_refptr<net::HttpResponseHeaders> base_headers(
1967 new net::HttpResponseHeaders(
1968 net::HttpUtil::AssembleRawHeaders(
1969 base_headers_string, sizeof(base_headers_string))));
1971 // Check that we can handle if not touching the response headers.
1972 linked_ptr<EventResponseDelta> d0(
1973 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
1974 deltas.push_back(d0);
1975 scoped_refptr<net::HttpResponseHeaders> new_headers0;
1976 GURL allowed_unsafe_redirect_url0;
1977 MergeOnHeadersReceivedResponses(deltas,
1978 base_headers.get(),
1979 &new_headers0,
1980 &allowed_unsafe_redirect_url0,
1981 &warning_set,
1982 &net_log);
1983 EXPECT_FALSE(new_headers0.get());
1984 EXPECT_TRUE(allowed_unsafe_redirect_url0.is_empty());
1985 EXPECT_EQ(0u, warning_set.size());
1986 EXPECT_EQ(0u, capturing_net_log.GetSize());
1988 linked_ptr<EventResponseDelta> d1(
1989 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1990 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value1"));
1991 d1->deleted_response_headers.push_back(ResponseHeader("KEY2", "Value2, Foo"));
1992 d1->added_response_headers.push_back(ResponseHeader("Key2", "Value3"));
1993 deltas.push_back(d1);
1994 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1995 warning_set.clear();
1996 capturing_net_log.Clear();
1997 scoped_refptr<net::HttpResponseHeaders> new_headers1;
1998 GURL allowed_unsafe_redirect_url1;
1999 MergeOnHeadersReceivedResponses(deltas,
2000 base_headers.get(),
2001 &new_headers1,
2002 &allowed_unsafe_redirect_url1,
2003 &warning_set,
2004 &net_log);
2005 ASSERT_TRUE(new_headers1.get());
2006 EXPECT_TRUE(allowed_unsafe_redirect_url1.is_empty());
2007 std::multimap<std::string, std::string> expected1;
2008 expected1.insert(std::pair<std::string, std::string>("Key2", "Value3"));
2009 void* iter = NULL;
2010 std::string name;
2011 std::string value;
2012 std::multimap<std::string, std::string> actual1;
2013 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) {
2014 actual1.insert(std::pair<std::string, std::string>(name, value));
2016 EXPECT_EQ(expected1, actual1);
2017 EXPECT_EQ(0u, warning_set.size());
2018 EXPECT_EQ(1u, capturing_net_log.GetSize());
2020 // Check that we replace response headers only once.
2021 linked_ptr<EventResponseDelta> d2(
2022 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
2023 // Note that we use a different capitalization of KeY2. This should not
2024 // matter.
2025 d2->deleted_response_headers.push_back(ResponseHeader("KeY2", "Value2, Foo"));
2026 d2->added_response_headers.push_back(ResponseHeader("Key2", "Value4"));
2027 deltas.push_back(d2);
2028 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
2029 warning_set.clear();
2030 capturing_net_log.Clear();
2031 scoped_refptr<net::HttpResponseHeaders> new_headers2;
2032 GURL allowed_unsafe_redirect_url2;
2033 MergeOnHeadersReceivedResponses(deltas,
2034 base_headers.get(),
2035 &new_headers2,
2036 &allowed_unsafe_redirect_url2,
2037 &warning_set,
2038 &net_log);
2039 ASSERT_TRUE(new_headers2.get());
2040 EXPECT_TRUE(allowed_unsafe_redirect_url2.is_empty());
2041 iter = NULL;
2042 std::multimap<std::string, std::string> actual2;
2043 while (new_headers2->EnumerateHeaderLines(&iter, &name, &value)) {
2044 actual2.insert(std::pair<std::string, std::string>(name, value));
2046 EXPECT_EQ(expected1, actual2);
2047 EXPECT_EQ(1u, warning_set.size());
2048 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
2049 EXPECT_EQ(2u, capturing_net_log.GetSize());
2052 // Check that we do not delete too much
2053 TEST(ExtensionWebRequestHelpersTest,
2054 TestMergeOnHeadersReceivedResponsesDeletion) {
2055 net::BoundTestNetLog capturing_net_log;
2056 net::BoundNetLog net_log = capturing_net_log.bound();
2057 WarningSet warning_set;
2058 std::string header_value;
2059 EventResponseDeltas deltas;
2061 char base_headers_string[] =
2062 "HTTP/1.0 200 OK\r\n"
2063 "Key1: Value1\r\n"
2064 "Key1: Value2\r\n"
2065 "Key1: Value3\r\n"
2066 "Key2: Value4\r\n"
2067 "\r\n";
2068 scoped_refptr<net::HttpResponseHeaders> base_headers(
2069 new net::HttpResponseHeaders(
2070 net::HttpUtil::AssembleRawHeaders(
2071 base_headers_string, sizeof(base_headers_string))));
2073 linked_ptr<EventResponseDelta> d1(
2074 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
2075 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value2"));
2076 deltas.push_back(d1);
2077 scoped_refptr<net::HttpResponseHeaders> new_headers1;
2078 GURL allowed_unsafe_redirect_url1;
2079 MergeOnHeadersReceivedResponses(deltas,
2080 base_headers.get(),
2081 &new_headers1,
2082 &allowed_unsafe_redirect_url1,
2083 &warning_set,
2084 &net_log);
2085 ASSERT_TRUE(new_headers1.get());
2086 EXPECT_TRUE(allowed_unsafe_redirect_url1.is_empty());
2087 std::multimap<std::string, std::string> expected1;
2088 expected1.insert(std::pair<std::string, std::string>("Key1", "Value1"));
2089 expected1.insert(std::pair<std::string, std::string>("Key1", "Value3"));
2090 expected1.insert(std::pair<std::string, std::string>("Key2", "Value4"));
2091 void* iter = NULL;
2092 std::string name;
2093 std::string value;
2094 std::multimap<std::string, std::string> actual1;
2095 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) {
2096 actual1.insert(std::pair<std::string, std::string>(name, value));
2098 EXPECT_EQ(expected1, actual1);
2099 EXPECT_EQ(0u, warning_set.size());
2100 EXPECT_EQ(1u, capturing_net_log.GetSize());
2103 // Tests whether onHeadersReceived can initiate a redirect.
2104 // The URL merge logic is shared with onBeforeRequest, so we only need to test
2105 // whether the URLs are merged at all.
2106 TEST(ExtensionWebRequestHelpersTest,
2107 TestMergeOnHeadersReceivedResponsesRedirect) {
2108 EventResponseDeltas deltas;
2109 net::BoundTestNetLog capturing_net_log;
2110 net::BoundNetLog net_log = capturing_net_log.bound();
2111 WarningSet warning_set;
2113 char base_headers_string[] =
2114 "HTTP/1.0 200 OK\r\n"
2115 "\r\n";
2116 scoped_refptr<net::HttpResponseHeaders> base_headers(
2117 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
2118 base_headers_string, sizeof(base_headers_string))));
2120 // No redirect
2121 linked_ptr<EventResponseDelta> d0(
2122 new EventResponseDelta("extid0", base::Time::FromInternalValue(0)));
2123 deltas.push_back(d0);
2124 scoped_refptr<net::HttpResponseHeaders> new_headers0;
2125 GURL allowed_unsafe_redirect_url0;
2126 MergeOnHeadersReceivedResponses(deltas,
2127 base_headers.get(),
2128 &new_headers0,
2129 &allowed_unsafe_redirect_url0,
2130 &warning_set,
2131 &net_log);
2132 EXPECT_FALSE(new_headers0.get());
2133 EXPECT_TRUE(allowed_unsafe_redirect_url0.is_empty());
2134 EXPECT_EQ(0u, warning_set.size());
2135 EXPECT_EQ(0u, capturing_net_log.GetSize());
2137 // Single redirect.
2138 GURL new_url_1("http://foo.com");
2139 linked_ptr<EventResponseDelta> d1(
2140 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000)));
2141 d1->new_url = GURL(new_url_1);
2142 deltas.push_back(d1);
2143 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
2144 capturing_net_log.Clear();
2145 scoped_refptr<net::HttpResponseHeaders> new_headers1;
2146 GURL allowed_unsafe_redirect_url1;
2147 MergeOnHeadersReceivedResponses(deltas,
2148 base_headers.get(),
2149 &new_headers1,
2150 &allowed_unsafe_redirect_url1,
2151 &warning_set,
2152 &net_log);
2154 EXPECT_TRUE(new_headers1.get());
2155 EXPECT_TRUE(new_headers1->HasHeaderValue("Location", new_url_1.spec()));
2156 EXPECT_EQ(new_url_1, allowed_unsafe_redirect_url1);
2157 EXPECT_TRUE(warning_set.empty());
2158 EXPECT_EQ(1u, capturing_net_log.GetSize());
2161 TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) {
2162 net::BoundTestNetLog capturing_net_log;
2163 net::BoundNetLog net_log = capturing_net_log.bound();
2164 WarningSet warning_set;
2165 EventResponseDeltas deltas;
2166 base::string16 username = base::ASCIIToUTF16("foo");
2167 base::string16 password = base::ASCIIToUTF16("bar");
2168 base::string16 password2 = base::ASCIIToUTF16("baz");
2170 // Check that we can handle if not returning credentials.
2171 linked_ptr<EventResponseDelta> d0(
2172 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
2173 deltas.push_back(d0);
2174 net::AuthCredentials auth0;
2175 bool credentials_set = MergeOnAuthRequiredResponses(
2176 deltas, &auth0, &warning_set, &net_log);
2177 EXPECT_FALSE(credentials_set);
2178 EXPECT_TRUE(auth0.Empty());
2179 EXPECT_EQ(0u, warning_set.size());
2180 EXPECT_EQ(0u, capturing_net_log.GetSize());
2182 // Check that we can set AuthCredentials.
2183 linked_ptr<EventResponseDelta> d1(
2184 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
2185 d1->auth_credentials.reset(new net::AuthCredentials(username, password));
2186 deltas.push_back(d1);
2187 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
2188 warning_set.clear();
2189 capturing_net_log.Clear();
2190 net::AuthCredentials auth1;
2191 credentials_set = MergeOnAuthRequiredResponses(
2192 deltas, &auth1, &warning_set, &net_log);
2193 EXPECT_TRUE(credentials_set);
2194 EXPECT_FALSE(auth1.Empty());
2195 EXPECT_EQ(username, auth1.username());
2196 EXPECT_EQ(password, auth1.password());
2197 EXPECT_EQ(0u, warning_set.size());
2198 EXPECT_EQ(1u, capturing_net_log.GetSize());
2200 // Check that we set AuthCredentials only once.
2201 linked_ptr<EventResponseDelta> d2(
2202 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
2203 d2->auth_credentials.reset(new net::AuthCredentials(username, password2));
2204 deltas.push_back(d2);
2205 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
2206 warning_set.clear();
2207 capturing_net_log.Clear();
2208 net::AuthCredentials auth2;
2209 credentials_set = MergeOnAuthRequiredResponses(
2210 deltas, &auth2, &warning_set, &net_log);
2211 EXPECT_TRUE(credentials_set);
2212 EXPECT_FALSE(auth2.Empty());
2213 EXPECT_EQ(username, auth1.username());
2214 EXPECT_EQ(password, auth1.password());
2215 EXPECT_EQ(1u, warning_set.size());
2216 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
2217 EXPECT_EQ(2u, capturing_net_log.GetSize());
2219 // Check that we can set identical AuthCredentials twice without causing
2220 // a conflict.
2221 linked_ptr<EventResponseDelta> d3(
2222 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000)));
2223 d3->auth_credentials.reset(new net::AuthCredentials(username, password));
2224 deltas.push_back(d3);
2225 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
2226 warning_set.clear();
2227 capturing_net_log.Clear();
2228 net::AuthCredentials auth3;
2229 credentials_set = MergeOnAuthRequiredResponses(
2230 deltas, &auth3, &warning_set, &net_log);
2231 EXPECT_TRUE(credentials_set);
2232 EXPECT_FALSE(auth3.Empty());
2233 EXPECT_EQ(username, auth1.username());
2234 EXPECT_EQ(password, auth1.password());
2235 EXPECT_EQ(1u, warning_set.size());
2236 EXPECT_TRUE(HasWarning(warning_set, "extid2"));
2237 EXPECT_EQ(3u, capturing_net_log.GetSize());
2240 } // namespace extensions