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