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