Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(718)

Side by Side Diff: chrome/browser/extensions/api/webrequest/webrequest_api_unittest.cc

Issue 9701039: Refactor folders in chrome/browser/extensions/api (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Small change to includes in extension_event_router.cc Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include <queue>
6 #include <map>
7
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/file_util.h"
11 #include "base/json/json_string_value_serializer.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/stl_util.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/content_settings/cookie_settings.h"
18 #include "chrome/browser/extensions/api/webrequest/webrequest_api.h"
19 #include "chrome/browser/extensions/api/webrequest/webrequest_api_constants.h"
20 #include "chrome/browser/extensions/api/webrequest/webrequest_api_helpers.h"
21 #include "chrome/browser/extensions/extension_event_router_forwarder.h"
22 #include "chrome/browser/net/chrome_network_delegate.h"
23 #include "chrome/browser/prefs/pref_member.h"
24 #include "chrome/common/extensions/extension_messages.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_pref_service.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "content/test/test_browser_thread.h"
30 #include "net/base/auth.h"
31 #include "net/base/net_util.h"
32 #include "net/url_request/url_request_test_util.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 namespace helpers = extension_webrequest_api_helpers;
36 namespace keys = extension_webrequest_api_constants;
37
38 using helpers::CalculateOnAuthRequiredDelta;
39 using helpers::CalculateOnBeforeRequestDelta;
40 using helpers::CalculateOnBeforeSendHeadersDelta;
41 using helpers::CalculateOnHeadersReceivedDelta;
42 using helpers::CharListToString;
43 using helpers::EventLogEntries;
44 using helpers::EventResponseDelta;
45 using helpers::EventResponseDeltas;
46 using helpers::EventResponseDeltas;
47 using helpers::InDecreasingExtensionInstallationTimeOrder;
48 using helpers::MergeCancelOfResponses;
49 using helpers::MergeOnBeforeRequestResponses;
50 using helpers::ResponseHeader;
51 using helpers::ResponseHeaders;
52 using helpers::StringToCharList;
53
54 namespace {
55 static void EventHandledOnIOThread(
56 void* profile,
57 const std::string& extension_id,
58 const std::string& event_name,
59 const std::string& sub_event_name,
60 uint64 request_id,
61 ExtensionWebRequestEventRouter::EventResponse* response) {
62 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
63 profile, extension_id, event_name, sub_event_name, request_id,
64 response);
65 }
66
67 // Searches |key| in |collection| by iterating over its elements and returns
68 // true if found.
69 template <typename Collection, typename Key>
70 bool Contains(const Collection& collection, const Key& key) {
71 return std::find(collection.begin(), collection.end(), key) !=
72 collection.end();
73 }
74
75 } // namespace
76
77 // A mock event router that responds to events with a pre-arranged queue of
78 // Tasks.
79 class TestIPCSender : public IPC::Message::Sender {
80 public:
81 typedef std::list<linked_ptr<IPC::Message> > SentMessages;
82
83 // Adds a Task to the queue. We will fire these in order as events are
84 // dispatched.
85 void PushTask(const base::Closure& task) {
86 task_queue_.push(task);
87 }
88
89 size_t GetNumTasks() { return task_queue_.size(); }
90
91 SentMessages::const_iterator sent_begin() const {
92 return sent_messages_.begin();
93 }
94
95 SentMessages::const_iterator sent_end() const {
96 return sent_messages_.end();
97 }
98
99 private:
100 // IPC::Message::Sender
101 virtual bool Send(IPC::Message* message) {
102 EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type());
103
104 EXPECT_FALSE(task_queue_.empty());
105 MessageLoop::current()->PostTask(FROM_HERE, task_queue_.front());
106 task_queue_.pop();
107
108 sent_messages_.push_back(linked_ptr<IPC::Message>(message));
109 return true;
110 }
111
112 std::queue<base::Closure> task_queue_;
113 SentMessages sent_messages_;
114 };
115
116 class ExtensionWebRequestTest : public testing::Test {
117 public:
118 ExtensionWebRequestTest()
119 : ui_thread_(content::BrowserThread::UI, &message_loop_),
120 io_thread_(content::BrowserThread::IO, &message_loop_) {}
121
122 protected:
123 virtual void SetUp() OVERRIDE {
124 event_router_ = new ExtensionEventRouterForwarder();
125 enable_referrers_.Init(
126 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
127 network_delegate_.reset(new ChromeNetworkDelegate(
128 event_router_.get(), NULL, NULL, &profile_,
129 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_));
130 context_ = new TestURLRequestContext();
131 context_->set_network_delegate(network_delegate_.get());
132 }
133
134 MessageLoopForIO message_loop_;
135 content::TestBrowserThread ui_thread_;
136 content::TestBrowserThread io_thread_;
137 TestingProfile profile_;
138 TestDelegate delegate_;
139 BooleanPrefMember enable_referrers_;
140 TestIPCSender ipc_sender_;
141 scoped_refptr<ExtensionEventRouterForwarder> event_router_;
142 scoped_refptr<ExtensionInfoMap> extension_info_map_;
143 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
144 scoped_refptr<TestURLRequestContext> context_;
145 };
146
147 // Tests that we handle disagreements among extensions about responses to
148 // blocking events (redirection) by choosing the response from the
149 // most-recently-installed extension.
150 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) {
151 std::string extension1_id("1");
152 std::string extension2_id("2");
153 ExtensionWebRequestEventRouter::RequestFilter filter;
154 const std::string kEventName(keys::kOnBeforeRequest);
155 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
156 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
157 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
158 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
159 ipc_sender_factory.GetWeakPtr());
160 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
161 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
162 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
163 ipc_sender_factory.GetWeakPtr());
164
165 GURL redirect_url("about:redirected");
166 GURL not_chosen_redirect_url("about:not_chosen");
167
168 net::URLRequest request(GURL("about:blank"), &delegate_);
169 request.set_context(context_);
170 {
171 // onBeforeRequest will be dispatched twice initially. The second response -
172 // the redirect - should win, since it has a later |install_time|. The
173 // redirect will dispatch another pair of onBeforeRequest. There, the first
174 // response should win (later |install_time|).
175 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
176
177 // Extension1 response. Arrives first, but ignored due to install_time.
178 response = new ExtensionWebRequestEventRouter::EventResponse(
179 extension1_id, base::Time::FromDoubleT(1));
180 response->new_url = not_chosen_redirect_url;
181 ipc_sender_.PushTask(
182 base::Bind(&EventHandledOnIOThread,
183 &profile_, extension1_id, kEventName, kEventName + "/1",
184 request.identifier(), response));
185
186 // Extension2 response. Arrives second, and chosen because of install_time.
187 response = new ExtensionWebRequestEventRouter::EventResponse(
188 extension2_id, base::Time::FromDoubleT(2));
189 response->new_url = redirect_url;
190 ipc_sender_.PushTask(
191 base::Bind(&EventHandledOnIOThread,
192 &profile_, extension2_id, kEventName, kEventName + "/2",
193 request.identifier(), response));
194
195 // Extension2 response to the redirected URL. Arrives first, and chosen.
196 response = new ExtensionWebRequestEventRouter::EventResponse(
197 extension2_id, base::Time::FromDoubleT(2));
198 ipc_sender_.PushTask(
199 base::Bind(&EventHandledOnIOThread,
200 &profile_, extension2_id, kEventName, kEventName + "/2",
201 request.identifier(), response));
202
203 // Extension1 response to the redirected URL. Arrives second, and ignored.
204 response = new ExtensionWebRequestEventRouter::EventResponse(
205 extension1_id, base::Time::FromDoubleT(1));
206 ipc_sender_.PushTask(
207 base::Bind(&EventHandledOnIOThread,
208 &profile_, extension1_id, kEventName, kEventName + "/1",
209 request.identifier(), response));
210
211 request.Start();
212 MessageLoop::current()->Run();
213
214 EXPECT_TRUE(!request.is_pending());
215 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
216 EXPECT_EQ(0, request.status().error());
217 EXPECT_EQ(redirect_url, request.url());
218 EXPECT_EQ(2U, request.url_chain().size());
219 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
220 }
221
222 // Now test the same thing but the extensions answer in reverse order.
223 net::URLRequest request2(GURL("about:blank"), &delegate_);
224 request2.set_context(context_);
225 {
226 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
227
228 // Extension2 response. Arrives first, and chosen because of install_time.
229 response = new ExtensionWebRequestEventRouter::EventResponse(
230 extension2_id, base::Time::FromDoubleT(2));
231 response->new_url = redirect_url;
232 ipc_sender_.PushTask(
233 base::Bind(&EventHandledOnIOThread,
234 &profile_, extension2_id, kEventName, kEventName + "/2",
235 request2.identifier(), response));
236
237 // Extension1 response. Arrives second, but ignored due to install_time.
238 response = new ExtensionWebRequestEventRouter::EventResponse(
239 extension1_id, base::Time::FromDoubleT(1));
240 response->new_url = not_chosen_redirect_url;
241 ipc_sender_.PushTask(
242 base::Bind(&EventHandledOnIOThread,
243 &profile_, extension1_id, kEventName, kEventName + "/1",
244 request2.identifier(), response));
245
246 // Extension2 response to the redirected URL. Arrives first, and chosen.
247 response = new ExtensionWebRequestEventRouter::EventResponse(
248 extension2_id, base::Time::FromDoubleT(2));
249 ipc_sender_.PushTask(
250 base::Bind(&EventHandledOnIOThread,
251 &profile_, extension2_id, kEventName, kEventName + "/2",
252 request2.identifier(), response));
253
254 // Extension1 response to the redirected URL. Arrives second, and ignored.
255 response = new ExtensionWebRequestEventRouter::EventResponse(
256 extension1_id, base::Time::FromDoubleT(1));
257 ipc_sender_.PushTask(
258 base::Bind(&EventHandledOnIOThread,
259 &profile_, extension1_id, kEventName, kEventName + "/1",
260 request2.identifier(), response));
261
262 request2.Start();
263 MessageLoop::current()->Run();
264
265 EXPECT_TRUE(!request2.is_pending());
266 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request2.status().status());
267 EXPECT_EQ(0, request2.status().error());
268 EXPECT_EQ(redirect_url, request2.url());
269 EXPECT_EQ(2U, request2.url_chain().size());
270 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
271 }
272
273 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
274 &profile_, extension1_id, kEventName + "/1");
275 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
276 &profile_, extension2_id, kEventName + "/2");
277 }
278
279 // Test that a request is canceled if this is requested by any extension
280 // regardless whether it is the extension with the highest precedence.
281 TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceCancel) {
282 std::string extension1_id("1");
283 std::string extension2_id("2");
284 ExtensionWebRequestEventRouter::RequestFilter filter;
285 const std::string kEventName(keys::kOnBeforeRequest);
286 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
287 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
288 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
289 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
290 ipc_sender_factory.GetWeakPtr());
291 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
292 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
293 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
294 ipc_sender_factory.GetWeakPtr());
295
296 GURL request_url("about:blank");
297 net::URLRequest request(request_url, &delegate_);
298 request.set_context(context_);
299
300 // onBeforeRequest will be dispatched twice. The second response -
301 // the redirect - would win, since it has a later |install_time|, but
302 // the first response takes precedence because cancel >> redirect.
303 GURL redirect_url("about:redirected");
304 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
305
306 // Extension1 response. Arrives first, would be ignored in principle due to
307 // install_time but "cancel" always wins.
308 response = new ExtensionWebRequestEventRouter::EventResponse(
309 extension1_id, base::Time::FromDoubleT(1));
310 response->cancel = true;
311 ipc_sender_.PushTask(
312 base::Bind(&EventHandledOnIOThread,
313 &profile_, extension1_id, kEventName, kEventName + "/1",
314 request.identifier(), response));
315
316 // Extension2 response. Arrives second, but has higher precedence
317 // due to its later install_time.
318 response = new ExtensionWebRequestEventRouter::EventResponse(
319 extension2_id, base::Time::FromDoubleT(2));
320 response->new_url = redirect_url;
321 ipc_sender_.PushTask(
322 base::Bind(&EventHandledOnIOThread,
323 &profile_, extension2_id, kEventName, kEventName + "/2",
324 request.identifier(), response));
325
326 request.Start();
327
328 MessageLoop::current()->Run();
329
330 EXPECT_TRUE(!request.is_pending());
331 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
332 EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, request.status().error());
333 EXPECT_EQ(request_url, request.url());
334 EXPECT_EQ(1U, request.url_chain().size());
335 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
336
337 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
338 &profile_, extension1_id, kEventName + "/1");
339 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
340 &profile_, extension2_id, kEventName + "/2");
341 }
342
343 TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) {
344 // We subscribe to OnBeforeRequest and OnErrorOccurred.
345 // While the OnBeforeRequest handler is blocked, we cancel the request.
346 // We verify that the response of the blocked OnBeforeRequest handler
347 // is ignored.
348
349 std::string extension_id("1");
350 ExtensionWebRequestEventRouter::RequestFilter filter;
351
352 // Subscribe to OnBeforeRequest and OnErrorOccurred.
353 const std::string kEventName(keys::kOnBeforeRequest);
354 const std::string kEventName2(keys::kOnErrorOccurred);
355 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
356 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
357 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
358 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
359 ipc_sender_factory.GetWeakPtr());
360 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
361 &profile_, extension_id, extension_id, kEventName2, kEventName2 + "/1",
362 filter, 0, ipc_sender_factory.GetWeakPtr());
363
364 GURL request_url("about:blank");
365 net::URLRequest request(request_url, &delegate_);
366 request.set_context(context_);
367
368 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
369
370 // Extension response for the OnBeforeRequest handler. This should not be
371 // processed because request is canceled before the handler responds.
372 response = new ExtensionWebRequestEventRouter::EventResponse(
373 extension_id, base::Time::FromDoubleT(1));
374 GURL redirect_url("about:redirected");
375 response->new_url = redirect_url;
376 ipc_sender_.PushTask(
377 base::Bind(&EventHandledOnIOThread,
378 &profile_, extension_id, kEventName, kEventName + "/1",
379 request.identifier(), response));
380
381 // Extension response for OnErrorOccurred: Terminate the message loop.
382 ipc_sender_.PushTask(
383 base::Bind(&MessageLoop::PostTask,
384 base::Unretained(MessageLoop::current()),
385 FROM_HERE, MessageLoop::QuitClosure()
386 ));
387
388 request.Start();
389 // request.Start() will have submitted OnBeforeRequest by the time we cancel.
390 request.Cancel();
391 MessageLoop::current()->Run();
392
393 EXPECT_TRUE(!request.is_pending());
394 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
395 EXPECT_EQ(net::ERR_ABORTED, request.status().error());
396 EXPECT_EQ(request_url, request.url());
397 EXPECT_EQ(1U, request.url_chain().size());
398 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
399
400 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
401 &profile_, extension_id, kEventName + "/1");
402 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
403 &profile_, extension_id, kEventName2 + "/1");
404 }
405
406 struct HeaderModificationTest_Header {
407 const char* name;
408 const char* value;
409 };
410
411 struct HeaderModificationTest_Modification {
412 enum Type {
413 SET,
414 REMOVE
415 };
416
417 int extension_id;
418 Type type;
419 const char* key;
420 const char* value;
421 };
422
423 struct HeaderModificationTest {
424 int before_size;
425 HeaderModificationTest_Header before[10];
426 int modification_size;
427 HeaderModificationTest_Modification modification[10];
428 int after_size;
429 HeaderModificationTest_Header after[10];
430 };
431
432 class ExtensionWebRequestHeaderModificationTest :
433 public testing::TestWithParam<HeaderModificationTest> {
434 public:
435 ExtensionWebRequestHeaderModificationTest()
436 : ui_thread_(content::BrowserThread::UI, &message_loop_),
437 io_thread_(content::BrowserThread::IO, &message_loop_) {}
438
439 protected:
440 virtual void SetUp() {
441 event_router_ = new ExtensionEventRouterForwarder();
442 enable_referrers_.Init(
443 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
444 network_delegate_.reset(new ChromeNetworkDelegate(
445 event_router_.get(), NULL, NULL, &profile_,
446 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_));
447 context_ = new TestURLRequestContext();
448 context_->set_network_delegate(network_delegate_.get());
449 }
450
451 MessageLoopForIO message_loop_;
452 content::TestBrowserThread ui_thread_;
453 content::TestBrowserThread io_thread_;
454 TestingProfile profile_;
455 TestDelegate delegate_;
456 BooleanPrefMember enable_referrers_;
457 TestIPCSender ipc_sender_;
458 scoped_refptr<ExtensionEventRouterForwarder> event_router_;
459 scoped_refptr<ExtensionInfoMap> extension_info_map_;
460 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
461 scoped_refptr<TestURLRequestContext> context_;
462 };
463
464 TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) {
465 std::string extension1_id("1");
466 std::string extension2_id("2");
467 std::string extension3_id("3");
468 ExtensionWebRequestEventRouter::RequestFilter filter;
469 const std::string kEventName(keys::kOnBeforeSendHeaders);
470 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
471
472 // Install two extensions that can modify headers. Extension 2 has
473 // higher precedence than extension 1.
474 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
475 &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
476 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
477 ipc_sender_factory.GetWeakPtr());
478 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
479 &profile_, extension2_id, extension2_id, kEventName, kEventName + "/2",
480 filter, ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
481 ipc_sender_factory.GetWeakPtr());
482
483 // Install one extension that observes the final headers.
484 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
485 &profile_, extension3_id, extension3_id, keys::kOnSendHeaders,
486 std::string(keys::kOnSendHeaders) + "/3", filter,
487 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS,
488 ipc_sender_factory.GetWeakPtr());
489
490 GURL request_url("http://doesnotexist/does_not_exist.html");
491 net::URLRequest request(request_url, &delegate_);
492 request.set_context(context_);
493
494 // Initialize headers available before extensions are notified of the
495 // onBeforeSendHeaders event.
496 HeaderModificationTest test = GetParam();
497 net::HttpRequestHeaders before_headers;
498 for (int i = 0; i < test.before_size; ++i)
499 before_headers.SetHeader(test.before[i].name, test.before[i].value);
500 request.SetExtraRequestHeaders(before_headers);
501
502 // Gather the modifications to the headers for the respective extensions.
503 // We assume here that all modifications of one extension are listed
504 // in a continuous block of |test.modifications_|.
505 ExtensionWebRequestEventRouter::EventResponse* response = NULL;
506 for (int i = 0; i < test.modification_size; ++i) {
507 const HeaderModificationTest_Modification& mod = test.modification[i];
508 if (response == NULL) {
509 response = new ExtensionWebRequestEventRouter::EventResponse(
510 mod.extension_id == 1 ? extension1_id : extension2_id,
511 base::Time::FromDoubleT(mod.extension_id));
512 response->request_headers.reset(new net::HttpRequestHeaders());
513 response->request_headers->MergeFrom(request.extra_request_headers());
514 }
515
516 switch (mod.type) {
517 case HeaderModificationTest_Modification::SET:
518 response->request_headers->SetHeader(mod.key, mod.value);
519 break;
520 case HeaderModificationTest_Modification::REMOVE:
521 response->request_headers->RemoveHeader(mod.key);
522 break;
523 }
524
525 // Trigger the result when this is the last modification statement or
526 // the block of modifications for the next extension starts.
527 if (i+1 == test.modification_size ||
528 mod.extension_id != test.modification[i+1].extension_id) {
529 ipc_sender_.PushTask(
530 base::Bind(&EventHandledOnIOThread,
531 &profile_, mod.extension_id == 1 ? extension1_id : extension2_id,
532 kEventName, kEventName + (mod.extension_id == 1 ? "/1" : "/2"),
533 request.identifier(), response));
534 response = NULL;
535 }
536 }
537
538 // Don't do anything for the onSendHeaders message.
539 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
540
541 // Note that we mess up the headers slightly:
542 // request.Start() will first add additional headers (e.g. the User-Agent)
543 // and then send an event to the extension. When we have prepared our
544 // answers to the onBeforeSendHeaders events above, these headers did not
545 // exists and are therefore not listed in the responses. This makes
546 // them seem deleted.
547 request.Start();
548 MessageLoop::current()->Run();
549
550 EXPECT_TRUE(!request.is_pending());
551 // This cannot succeed as we send the request to a server that does not exist.
552 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
553 EXPECT_EQ(request_url, request.url());
554 EXPECT_EQ(1U, request.url_chain().size());
555 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
556
557 // Calculate the expected headers.
558 net::HttpRequestHeaders expected_headers;
559 for (int i = 0; i < test.after_size; ++i) {
560 expected_headers.SetHeader(test.after[i].name,
561 test.after[i].value);
562 }
563
564 // Counter for the number of observed onSendHeaders events.
565 int num_headers_observed = 0;
566
567 // Search the onSendHeaders signal in the IPC messages and check that
568 // it contained the correct headers.
569 TestIPCSender::SentMessages::const_iterator i;
570 for (i = ipc_sender_.sent_begin(); i != ipc_sender_.sent_end(); ++i) {
571 IPC::Message* message = i->get();
572 if (ExtensionMsg_MessageInvoke::ID != message->type())
573 continue;
574 ExtensionMsg_MessageInvoke::Param message_tuple;
575 ExtensionMsg_MessageInvoke::Read(message, &message_tuple);
576 ListValue& args = message_tuple.c;
577
578 std::string event_name;
579 if (!args.GetString(0, &event_name) ||
580 event_name != std::string(keys::kOnSendHeaders) + "/3") {
581 continue;
582 }
583
584 std::string event_arg_string;
585 ASSERT_TRUE(args.GetString(1, &event_arg_string));
586
587 scoped_ptr<Value> event_arg_value(
588 JSONStringValueSerializer(event_arg_string).Deserialize(NULL, NULL));
589 ASSERT_TRUE(event_arg_value.get() &&
590 event_arg_value->IsType(Value::TYPE_LIST));
591
592 DictionaryValue* event_arg_dict = NULL;
593 ASSERT_TRUE(
594 static_cast<ListValue*>(event_arg_value.get())->GetDictionary(
595 0, &event_arg_dict));
596
597 ListValue* request_headers = NULL;
598 ASSERT_TRUE(event_arg_dict->GetList(keys::kRequestHeadersKey,
599 &request_headers));
600
601 net::HttpRequestHeaders observed_headers;
602 for (size_t j = 0; j < request_headers->GetSize(); ++j) {
603 DictionaryValue* header = NULL;
604 ASSERT_TRUE(request_headers->GetDictionary(j, &header));
605 std::string key;
606 std::string value;
607 ASSERT_TRUE(header->GetString(keys::kHeaderNameKey, &key));
608 ASSERT_TRUE(header->GetString(keys::kHeaderValueKey, &value));
609 observed_headers.SetHeader(key, value);
610 }
611
612 EXPECT_EQ(expected_headers.ToString(), observed_headers.ToString());
613 ++num_headers_observed;
614 }
615 EXPECT_EQ(1, num_headers_observed);
616 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
617 &profile_, extension1_id, kEventName + "/1");
618 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
619 &profile_, extension2_id, kEventName + "/2");
620 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
621 &profile_, extension3_id, std::string(keys::kOnSendHeaders) + "/3");
622 };
623
624 namespace {
625
626 void TestInitFromValue(const std::string& values, bool expected_return_code,
627 int expected_extra_info_spec) {
628 // Create a ListValue of strings.
629 std::vector<std::string> split_values;
630 scoped_ptr<base::ListValue> list_value(new base::ListValue());
631 size_t num_values = Tokenize(values, ",", &split_values);
632 for (size_t i = 0; i < num_values ; ++i)
633 list_value->Append(new base::StringValue(split_values[i]));
634 int actual_info_spec;
635 bool actual_return_code =
636 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
637 *list_value, &actual_info_spec);
638 EXPECT_EQ(expected_return_code, actual_return_code);
639 if (expected_return_code)
640 EXPECT_EQ(expected_extra_info_spec, actual_info_spec);
641 }
642
643 }
644 TEST_F(ExtensionWebRequestTest, InitFromValue) {
645 TestInitFromValue("", true, 0);
646
647 // Single valid values.
648 TestInitFromValue(
649 "requestHeaders",
650 true,
651 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS);
652 TestInitFromValue(
653 "responseHeaders",
654 true,
655 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS);
656 TestInitFromValue(
657 "blocking",
658 true,
659 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
660 TestInitFromValue(
661 "asyncBlocking",
662 true,
663 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING);
664
665 // Multiple valid values are bitwise-or'ed.
666 TestInitFromValue(
667 "requestHeaders,blocking",
668 true,
669 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS |
670 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
671
672 // Any invalid values lead to a bad parse.
673 TestInitFromValue("invalidValue", false, 0);
674 TestInitFromValue("blocking,invalidValue", false, 0);
675 TestInitFromValue("invalidValue1,invalidValue2", false, 0);
676
677 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
678 TestInitFromValue("blocking,asyncBlocking", false, 0);
679 }
680
681 namespace {
682
683 const HeaderModificationTest_Modification::Type SET =
684 HeaderModificationTest_Modification::SET;
685 const HeaderModificationTest_Modification::Type REMOVE =
686 HeaderModificationTest_Modification::REMOVE;
687
688 HeaderModificationTest kTests[] = {
689 // Check that extension 2 always wins when settings the same header.
690 {
691 // Headers before test.
692 2, { {"header1", "value1"},
693 {"header2", "value2"} },
694 // Modifications in test.
695 2, { {1, SET, "header1", "foo"},
696 {2, SET, "header1", "bar"} },
697 // Headers after test.
698 2, { {"header1", "bar"},
699 {"header2", "value2"} }
700 },
701 // Same as before in reverse execution order.
702 {
703 // Headers before test.
704 2, { {"header1", "value1"},
705 {"header2", "value2"} },
706 // Modifications in test.
707 2, { {2, SET, "header1", "bar"},
708 {1, SET, "header1", "foo"} },
709 // Headers after test.
710 2, { {"header1", "bar"},
711 {"header2", "value2"} }
712 },
713 // Check that two extensions can modify different headers that do not
714 // conflict.
715 {
716 // Headers before test.
717 2, { {"header1", "value1"},
718 {"header2", "value2"} },
719 // Modifications in test.
720 2, { {1, SET, "header1", "foo"},
721 {2, SET, "header2", "bar"} },
722 // Headers after test.
723 2, { {"header1", "foo"},
724 {"header2", "bar"} }
725 },
726 // Check insert/delete conflict.
727 {
728 // Headers before test.
729 1, { {"header1", "value1"} },
730 // Modifications in test.
731 2, { {1, SET, "header1", "foo"},
732 {2, REMOVE, "header1", NULL} },
733 // Headers after test.
734 0, { }
735 },
736 {
737 // Headers before test.
738 1, { {"header1", "value1"} },
739 // Modifications in test.
740 2, { {2, REMOVE, "header1", NULL},
741 {1, SET, "header1", "foo"} },
742 // Headers after test.
743 0, {}
744 },
745 {
746 // Headers before test.
747 1, { {"header1", "value1"} },
748 // Modifications in test.
749 2, { {1, REMOVE, "header1", NULL},
750 {2, SET, "header1", "foo"} },
751 // Headers after test.
752 1, { {"header1", "foo"} }
753 },
754 {
755 // Headers before test.
756 1, { {"header1", "value1"} },
757 // Modifications in test.
758 2, { {2, SET, "header1", "foo"},
759 {1, REMOVE, "header1", NULL} },
760 // Headers after test.
761 1, { {"header1", "foo"} }
762 },
763 // Check that edits are atomic (i.e. either all edit requests of an
764 // extension are executed or none).
765 {
766 // Headers before test.
767 0, { },
768 // Modifications in test.
769 3, { {1, SET, "header1", "value1"},
770 {1, SET, "header2", "value2"},
771 {2, SET, "header1", "foo"} },
772 // Headers after test.
773 1, { {"header1", "foo"} } // set(header2) is ignored
774 },
775 // Check that identical edits do not conflict (set(header2) would be ignored
776 // if set(header1) were considered a conflict).
777 {
778 // Headers before test.
779 0, { },
780 // Modifications in test.
781 3, { {1, SET, "header1", "value2"},
782 {1, SET, "header2", "foo"},
783 {2, SET, "header1", "value2"} },
784 // Headers after test.
785 2, { {"header1", "value2"},
786 {"header2", "foo"} }
787 },
788 // Check that identical deletes do not conflict (set(header2) would be ignored
789 // if delete(header1) were considered a conflict).
790 {
791 // Headers before test.
792 1, { {"header1", "value1"} },
793 // Modifications in test.
794 3, { {1, REMOVE, "header1", NULL},
795 {1, SET, "header2", "foo"},
796 {2, REMOVE, "header1", NULL} },
797 // Headers after test.
798 1, { {"header2", "foo"} }
799 },
800 // Check that setting a value to an identical value is not considered an
801 // edit operation that can conflict.
802 {
803 // Headers before test.
804 1, { {"header1", "value1"} },
805 // Modifications in test.
806 3, { {1, SET, "header1", "foo"},
807 {1, SET, "header2", "bar"},
808 {2, SET, "header1", "value1"} },
809 // Headers after test.
810 2, { {"header1", "foo"},
811 {"header2", "bar"} }
812 },
813 };
814
815 INSTANTIATE_TEST_CASE_P(
816 ExtensionWebRequest,
817 ExtensionWebRequestHeaderModificationTest,
818 ::testing::ValuesIn(kTests));
819
820 } // namespace
821
822
823 TEST(ExtensionWebRequestHelpersTest,
824 TestInDecreasingExtensionInstallationTimeOrder) {
825 linked_ptr<EventResponseDelta> a(
826 new EventResponseDelta("ext_1", base::Time::FromInternalValue(0)));
827 linked_ptr<EventResponseDelta> b(
828 new EventResponseDelta("ext_2", base::Time::FromInternalValue(1000)));
829 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, a));
830 EXPECT_FALSE(InDecreasingExtensionInstallationTimeOrder(a, b));
831 EXPECT_TRUE(InDecreasingExtensionInstallationTimeOrder(b, a));
832 }
833
834 TEST(ExtensionWebRequestHelpersTest, TestStringToCharList) {
835 ListValue list_value;
836 list_value.Append(Value::CreateIntegerValue('1'));
837 list_value.Append(Value::CreateIntegerValue('2'));
838 list_value.Append(Value::CreateIntegerValue('3'));
839 list_value.Append(Value::CreateIntegerValue(0xFE));
840 list_value.Append(Value::CreateIntegerValue(0xD1));
841
842 unsigned char char_value[] = {'1', '2', '3', 0xFE, 0xD1};
843 std::string string_value(reinterpret_cast<char *>(char_value), 5);
844
845 scoped_ptr<ListValue> converted_list(StringToCharList(string_value));
846 EXPECT_TRUE(list_value.Equals(converted_list.get()));
847
848 std::string converted_string;
849 EXPECT_TRUE(CharListToString(&list_value, &converted_string));
850 EXPECT_EQ(string_value, converted_string);
851 }
852
853 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeRequestDelta) {
854 const bool cancel = true;
855 const GURL localhost("http://localhost");
856 scoped_ptr<EventResponseDelta> delta(
857 CalculateOnBeforeRequestDelta("extid", base::Time::Now(),
858 cancel, localhost));
859 ASSERT_TRUE(delta.get());
860 EXPECT_TRUE(delta->cancel);
861 EXPECT_EQ(localhost, delta->new_url);
862 }
863
864 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnBeforeSendHeadersDelta) {
865 const bool cancel = true;
866 std::string value;
867 net::HttpRequestHeaders old_headers;
868 old_headers.AddHeadersFromString("key1: value1\r\n"
869 "key2: value2\r\n");
870
871 // Test adding a header.
872 net::HttpRequestHeaders new_headers_added;
873 new_headers_added.AddHeadersFromString("key1: value1\r\n"
874 "key3: value3\r\n"
875 "key2: value2\r\n");
876 scoped_ptr<EventResponseDelta> delta_added(
877 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
878 &old_headers, &new_headers_added));
879 ASSERT_TRUE(delta_added.get());
880 EXPECT_TRUE(delta_added->cancel);
881 ASSERT_TRUE(delta_added->modified_request_headers.GetHeader("key3", &value));
882 EXPECT_EQ("value3", value);
883
884 // Test deleting a header.
885 net::HttpRequestHeaders new_headers_deleted;
886 new_headers_deleted.AddHeadersFromString("key1: value1\r\n");
887 scoped_ptr<EventResponseDelta> delta_deleted(
888 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
889 &old_headers, &new_headers_deleted));
890 ASSERT_TRUE(delta_deleted.get());
891 ASSERT_EQ(1u, delta_deleted->deleted_request_headers.size());
892 ASSERT_EQ("key2", delta_deleted->deleted_request_headers.front());
893
894 // Test modifying a header.
895 net::HttpRequestHeaders new_headers_modified;
896 new_headers_modified.AddHeadersFromString("key1: value1\r\n"
897 "key2: value3\r\n");
898 scoped_ptr<EventResponseDelta> delta_modified(
899 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
900 &old_headers, &new_headers_modified));
901 ASSERT_TRUE(delta_modified.get());
902 EXPECT_TRUE(delta_modified->deleted_request_headers.empty());
903 ASSERT_TRUE(
904 delta_modified->modified_request_headers.GetHeader("key2", &value));
905 EXPECT_EQ("value3", value);
906
907 // Test modifying a header if extension author just appended a new (key,
908 // value) pair with a key that existed before. This is incorrect
909 // usage of the API that shall be handled gracefully.
910 net::HttpRequestHeaders new_headers_modified2;
911 new_headers_modified2.AddHeadersFromString("key1: value1\r\n"
912 "key2: value2\r\n"
913 "key2: value3\r\n");
914 scoped_ptr<EventResponseDelta> delta_modified2(
915 CalculateOnBeforeSendHeadersDelta("extid", base::Time::Now(), cancel,
916 &old_headers, &new_headers_modified));
917 ASSERT_TRUE(delta_modified2.get());
918 EXPECT_TRUE(delta_modified2->deleted_request_headers.empty());
919 ASSERT_TRUE(
920 delta_modified2->modified_request_headers.GetHeader("key2", &value));
921 EXPECT_EQ("value3", value);
922 }
923
924 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnHeadersReceivedDelta) {
925 const bool cancel = true;
926 char base_headers_string[] =
927 "HTTP/1.0 200 OK\r\n"
928 "Key1: Value1\r\n"
929 "Key2: Value2\r\n"
930 "Key3: Value3\r\n"
931 "\r\n";
932 scoped_refptr<net::HttpResponseHeaders> base_headers(
933 new net::HttpResponseHeaders(
934 net::HttpUtil::AssembleRawHeaders(
935 base_headers_string, sizeof(base_headers_string))));
936
937 ResponseHeaders new_headers;
938 new_headers.push_back(ResponseHeader("kEy1", "Value1")); // Unchanged
939 new_headers.push_back(ResponseHeader("Key2", "Value1")); // Modified
940 // Key3 is deleted
941 new_headers.push_back(ResponseHeader("Key4", "Value4")); // Added
942
943 scoped_ptr<EventResponseDelta> delta(
944 CalculateOnHeadersReceivedDelta("extid", base::Time::Now(), cancel,
945 base_headers, &new_headers));
946 ASSERT_TRUE(delta.get());
947 EXPECT_TRUE(delta->cancel);
948 EXPECT_EQ(2u, delta->added_response_headers.size());
949 EXPECT_TRUE(Contains(delta->added_response_headers,
950 ResponseHeader("Key2", "Value1")));
951 EXPECT_TRUE(Contains(delta->added_response_headers,
952 ResponseHeader("Key4", "Value4")));
953 EXPECT_EQ(2u, delta->deleted_response_headers.size());
954 EXPECT_TRUE(Contains(delta->deleted_response_headers,
955 ResponseHeader("Key2", "Value2")));
956 EXPECT_TRUE(Contains(delta->deleted_response_headers,
957 ResponseHeader("Key3", "Value3")));
958 }
959
960 TEST(ExtensionWebRequestHelpersTest, TestCalculateOnAuthRequiredDelta) {
961 const bool cancel = true;
962
963 string16 username = ASCIIToUTF16("foo");
964 string16 password = ASCIIToUTF16("bar");
965 scoped_ptr<net::AuthCredentials> credentials(
966 new net::AuthCredentials(username, password));
967
968 scoped_ptr<EventResponseDelta> delta(
969 CalculateOnAuthRequiredDelta("extid", base::Time::Now(), cancel,
970 &credentials));
971 ASSERT_TRUE(delta.get());
972 EXPECT_TRUE(delta->cancel);
973 ASSERT_TRUE(delta->auth_credentials.get());
974 EXPECT_EQ(username, delta->auth_credentials->username());
975 EXPECT_EQ(password, delta->auth_credentials->password());
976 }
977
978 TEST(ExtensionWebRequestHelpersTest, TestMergeCancelOfResponses) {
979 EventResponseDeltas deltas;
980 EventLogEntries event_log;
981 bool canceled = false;
982
983 // Single event that does not cancel.
984 linked_ptr<EventResponseDelta> d1(
985 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000)));
986 d1->cancel = false;
987 deltas.push_back(d1);
988 MergeCancelOfResponses(deltas, &canceled, &event_log);
989 EXPECT_FALSE(canceled);
990 EXPECT_TRUE(event_log.empty());
991
992 // Second event that cancels the request
993 linked_ptr<EventResponseDelta> d2(
994 new EventResponseDelta("extid2", base::Time::FromInternalValue(500)));
995 d2->cancel = true;
996 deltas.push_back(d2);
997 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
998 MergeCancelOfResponses(deltas, &canceled, &event_log);
999 EXPECT_TRUE(canceled);
1000 EXPECT_EQ(1u, event_log.size());
1001 }
1002
1003 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses) {
1004 EventResponseDeltas deltas;
1005 EventLogEntries event_log;
1006 std::set<std::string> conflicting_extensions;
1007 GURL effective_new_url;
1008
1009 // No redirect
1010 linked_ptr<EventResponseDelta> d0(
1011 new EventResponseDelta("extid0", base::Time::FromInternalValue(0)));
1012 deltas.push_back(d0);
1013 MergeOnBeforeRequestResponses(
1014 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1015 EXPECT_TRUE(effective_new_url.is_empty());
1016
1017 // Single redirect.
1018 GURL new_url_1("http://foo.com");
1019 linked_ptr<EventResponseDelta> d1(
1020 new EventResponseDelta("extid1", base::Time::FromInternalValue(1000)));
1021 d1->new_url = GURL(new_url_1);
1022 deltas.push_back(d1);
1023 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1024 event_log.clear();
1025 MergeOnBeforeRequestResponses(
1026 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1027 EXPECT_EQ(new_url_1, effective_new_url);
1028 EXPECT_TRUE(conflicting_extensions.empty());
1029 EXPECT_EQ(1u, event_log.size());
1030
1031 // Ignored redirect (due to precedence).
1032 GURL new_url_2("http://bar.com");
1033 linked_ptr<EventResponseDelta> d2(
1034 new EventResponseDelta("extid2", base::Time::FromInternalValue(500)));
1035 d2->new_url = GURL(new_url_2);
1036 deltas.push_back(d2);
1037 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1038 event_log.clear();
1039 MergeOnBeforeRequestResponses(
1040 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1041 EXPECT_EQ(new_url_1, effective_new_url);
1042 EXPECT_EQ(1u, conflicting_extensions.size());
1043 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1044 EXPECT_EQ(2u, event_log.size());
1045
1046 // Overriding redirect.
1047 GURL new_url_3("http://baz.com");
1048 linked_ptr<EventResponseDelta> d3(
1049 new EventResponseDelta("extid3", base::Time::FromInternalValue(1500)));
1050 d3->new_url = GURL(new_url_3);
1051 deltas.push_back(d3);
1052 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1053 conflicting_extensions.clear();
1054 event_log.clear();
1055 MergeOnBeforeRequestResponses(
1056 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1057 EXPECT_EQ(new_url_3, effective_new_url);
1058 EXPECT_EQ(2u, conflicting_extensions.size());
1059 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid1"));
1060 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1061 EXPECT_EQ(3u, event_log.size());
1062
1063 // Check that identical redirects don't cause a conflict.
1064 linked_ptr<EventResponseDelta> d4(
1065 new EventResponseDelta("extid4", base::Time::FromInternalValue(2000)));
1066 d4->new_url = GURL(new_url_3);
1067 deltas.push_back(d4);
1068 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1069 conflicting_extensions.clear();
1070 event_log.clear();
1071 MergeOnBeforeRequestResponses(
1072 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1073 EXPECT_EQ(new_url_3, effective_new_url);
1074 EXPECT_EQ(2u, conflicting_extensions.size());
1075 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid1"));
1076 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1077 EXPECT_EQ(4u, event_log.size());
1078 }
1079
1080 // This tests that we can redirect to data:// urls, which is considered
1081 // a kind of cancelling requests.
1082 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeRequestResponses2) {
1083 EventResponseDeltas deltas;
1084 EventLogEntries event_log;
1085 std::set<std::string> conflicting_extensions;
1086 GURL effective_new_url;
1087
1088 // Single redirect.
1089 GURL new_url_0("http://foo.com");
1090 linked_ptr<EventResponseDelta> d0(
1091 new EventResponseDelta("extid0", base::Time::FromInternalValue(2000)));
1092 d0->new_url = GURL(new_url_0);
1093 deltas.push_back(d0);
1094 MergeOnBeforeRequestResponses(
1095 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1096 EXPECT_EQ(new_url_0, effective_new_url);
1097
1098 // Cancel request by redirecting to a data:// URL. This shall override
1099 // the other redirect but not cause any conflict warnings.
1100 GURL new_url_1("data://foo");
1101 linked_ptr<EventResponseDelta> d1(
1102 new EventResponseDelta("extid1", base::Time::FromInternalValue(1500)));
1103 d1->new_url = GURL(new_url_1);
1104 deltas.push_back(d1);
1105 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1106 event_log.clear();
1107 MergeOnBeforeRequestResponses(
1108 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1109 EXPECT_EQ(new_url_1, effective_new_url);
1110 EXPECT_TRUE(conflicting_extensions.empty());
1111 EXPECT_EQ(1u, event_log.size());
1112
1113 // Cancel request by redirecting to the same data:// URL. This shall
1114 // not create any conflicts as it is in line with d1.
1115 GURL new_url_2("data://foo");
1116 linked_ptr<EventResponseDelta> d2(
1117 new EventResponseDelta("extid2", base::Time::FromInternalValue(1000)));
1118 d2->new_url = GURL(new_url_2);
1119 deltas.push_back(d2);
1120 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1121 event_log.clear();
1122 MergeOnBeforeRequestResponses(
1123 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1124 EXPECT_EQ(new_url_1, effective_new_url);
1125 EXPECT_TRUE(conflicting_extensions.empty());
1126 EXPECT_EQ(2u, event_log.size());
1127
1128 // Cancel redirect by redirecting to a different data:// URL. This needs
1129 // to create a conflict.
1130 GURL new_url_3("data://something_totally_different");
1131 linked_ptr<EventResponseDelta> d3(
1132 new EventResponseDelta("extid3", base::Time::FromInternalValue(500)));
1133 d3->new_url = GURL(new_url_3);
1134 deltas.push_back(d3);
1135 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1136 event_log.clear();
1137 MergeOnBeforeRequestResponses(
1138 deltas, &effective_new_url, &conflicting_extensions, &event_log);
1139 EXPECT_EQ(new_url_1, effective_new_url);
1140 EXPECT_EQ(1u, conflicting_extensions.size());
1141 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid3"));
1142 EXPECT_EQ(3u, event_log.size());
1143 }
1144
1145 TEST(ExtensionWebRequestHelpersTest, TestMergeOnBeforeSendHeadersResponses) {
1146 net::HttpRequestHeaders base_headers;
1147 base_headers.AddHeaderFromString("key1: value 1");
1148 base_headers.AddHeaderFromString("key2: value 2");
1149 EventLogEntries event_log;
1150 std::set<std::string> conflicting_extensions;
1151 std::string header_value;
1152 EventResponseDeltas deltas;
1153
1154 // Check that we can handle not changing the headers.
1155 linked_ptr<EventResponseDelta> d0(
1156 new EventResponseDelta("extid0", base::Time::FromInternalValue(2500)));
1157 deltas.push_back(d0);
1158 net::HttpRequestHeaders headers0;
1159 headers0.MergeFrom(base_headers);
1160 MergeOnBeforeSendHeadersResponses(
1161 deltas, &headers0, &conflicting_extensions, &event_log);
1162 ASSERT_TRUE(headers0.GetHeader("key1", &header_value));
1163 EXPECT_EQ("value 1", header_value);
1164 ASSERT_TRUE(headers0.GetHeader("key2", &header_value));
1165 EXPECT_EQ("value 2", header_value);
1166 EXPECT_EQ(0u, conflicting_extensions.size());
1167 EXPECT_EQ(0u, event_log.size());
1168
1169 // Delete, modify and add a header.
1170 linked_ptr<EventResponseDelta> d1(
1171 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1172 d1->deleted_request_headers.push_back("key1");
1173 d1->modified_request_headers.AddHeaderFromString("key2: value 3");
1174 d1->modified_request_headers.AddHeaderFromString("key3: value 3");
1175 deltas.push_back(d1);
1176 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1177 net::HttpRequestHeaders headers1;
1178 headers1.MergeFrom(base_headers);
1179 MergeOnBeforeSendHeadersResponses(
1180 deltas, &headers1, &conflicting_extensions, &event_log);
1181 EXPECT_FALSE(headers1.HasHeader("key1"));
1182 ASSERT_TRUE(headers1.GetHeader("key2", &header_value));
1183 EXPECT_EQ("value 3", header_value);
1184 ASSERT_TRUE(headers1.GetHeader("key3", &header_value));
1185 EXPECT_EQ("value 3", header_value);
1186 EXPECT_EQ(0u, conflicting_extensions.size());
1187 EXPECT_EQ(1u, event_log.size());
1188
1189 // Check that conflicts are atomic, i.e. if one header modification
1190 // collides all other conflicts of the same extension are declined as well.
1191 linked_ptr<EventResponseDelta> d2(
1192 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
1193 // This one conflicts:
1194 d2->modified_request_headers.AddHeaderFromString("key3: value 0");
1195 d2->modified_request_headers.AddHeaderFromString("key4: value 4");
1196 deltas.push_back(d2);
1197 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1198 conflicting_extensions.clear();
1199 event_log.clear();
1200 net::HttpRequestHeaders headers2;
1201 headers2.MergeFrom(base_headers);
1202 MergeOnBeforeSendHeadersResponses(
1203 deltas, &headers2, &conflicting_extensions, &event_log);
1204 EXPECT_FALSE(headers2.HasHeader("key1"));
1205 ASSERT_TRUE(headers2.GetHeader("key2", &header_value));
1206 EXPECT_EQ("value 3", header_value);
1207 ASSERT_TRUE(headers2.GetHeader("key3", &header_value));
1208 EXPECT_EQ("value 3", header_value);
1209 EXPECT_FALSE(headers2.HasHeader("key4"));
1210 EXPECT_EQ(1u, conflicting_extensions.size());
1211 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1212 EXPECT_EQ(2u, event_log.size());
1213
1214 // Check that identical modifications don't conflict and operations
1215 // can be merged.
1216 linked_ptr<EventResponseDelta> d3(
1217 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000)));
1218 d3->deleted_request_headers.push_back("key1");
1219 d3->modified_request_headers.AddHeaderFromString("key2: value 3");
1220 d3->modified_request_headers.AddHeaderFromString("key5: value 5");
1221 deltas.push_back(d3);
1222 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1223 conflicting_extensions.clear();
1224 event_log.clear();
1225 net::HttpRequestHeaders headers3;
1226 headers3.MergeFrom(base_headers);
1227 MergeOnBeforeSendHeadersResponses(
1228 deltas, &headers3, &conflicting_extensions, &event_log);
1229 EXPECT_FALSE(headers3.HasHeader("key1"));
1230 ASSERT_TRUE(headers3.GetHeader("key2", &header_value));
1231 EXPECT_EQ("value 3", header_value);
1232 ASSERT_TRUE(headers3.GetHeader("key3", &header_value));
1233 EXPECT_EQ("value 3", header_value);
1234 ASSERT_TRUE(headers3.GetHeader("key5", &header_value));
1235 EXPECT_EQ("value 5", header_value);
1236 EXPECT_EQ(1u, conflicting_extensions.size());
1237 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1238 EXPECT_EQ(3u, event_log.size());
1239 }
1240
1241 TEST(ExtensionWebRequestHelpersTest, TestMergeOnHeadersReceivedResponses) {
1242 EventLogEntries event_log;
1243 std::set<std::string> conflicting_extensions;
1244 std::string header_value;
1245 EventResponseDeltas deltas;
1246
1247 char base_headers_string[] =
1248 "HTTP/1.0 200 OK\r\n"
1249 "Key1: Value1\r\n"
1250 "Key2: Value2\r\n"
1251 "\r\n";
1252 scoped_refptr<net::HttpResponseHeaders> base_headers(
1253 new net::HttpResponseHeaders(
1254 net::HttpUtil::AssembleRawHeaders(
1255 base_headers_string, sizeof(base_headers_string))));
1256
1257 // Check that we can handle if not touching the response headers.
1258 linked_ptr<EventResponseDelta> d0(
1259 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
1260 deltas.push_back(d0);
1261 scoped_refptr<net::HttpResponseHeaders> new_headers0;
1262 MergeOnHeadersReceivedResponses(
1263 deltas, base_headers.get(), &new_headers0, &conflicting_extensions,
1264 &event_log);
1265 EXPECT_FALSE(new_headers0.get());
1266 EXPECT_EQ(0u, conflicting_extensions.size());
1267 EXPECT_EQ(0u, event_log.size());
1268
1269 linked_ptr<EventResponseDelta> d1(
1270 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1271 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value1"));
1272 d1->deleted_response_headers.push_back(ResponseHeader("KEY2", "Value2"));
1273 d1->added_response_headers.push_back(ResponseHeader("Key2", "Value3"));
1274 deltas.push_back(d1);
1275 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1276 conflicting_extensions.clear();
1277 event_log.clear();
1278 scoped_refptr<net::HttpResponseHeaders> new_headers1;
1279 MergeOnHeadersReceivedResponses(
1280 deltas, base_headers.get(), &new_headers1, &conflicting_extensions,
1281 &event_log);
1282 ASSERT_TRUE(new_headers1.get());
1283 std::multimap<std::string, std::string> expected1;
1284 expected1.insert(std::pair<std::string, std::string>("Key2", "Value3"));
1285 void* iter = NULL;
1286 std::string name;
1287 std::string value;
1288 std::multimap<std::string, std::string> actual1;
1289 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) {
1290 actual1.insert(std::pair<std::string, std::string>(name, value));
1291 }
1292 EXPECT_EQ(expected1, actual1);
1293 EXPECT_EQ(0u, conflicting_extensions.size());
1294 EXPECT_EQ(1u, event_log.size());
1295
1296 // Check that we replace response headers only once.
1297 linked_ptr<EventResponseDelta> d2(
1298 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
1299 // Note that we use a different capitalization of KeY2. This should not
1300 // matter.
1301 d2->deleted_response_headers.push_back(ResponseHeader("KeY2", "Value2"));
1302 d2->added_response_headers.push_back(ResponseHeader("Key2", "Value4"));
1303 deltas.push_back(d2);
1304 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1305 conflicting_extensions.clear();
1306 event_log.clear();
1307 scoped_refptr<net::HttpResponseHeaders> new_headers2;
1308 MergeOnHeadersReceivedResponses(
1309 deltas, base_headers.get(), &new_headers2, &conflicting_extensions,
1310 &event_log);
1311 ASSERT_TRUE(new_headers2.get());
1312 iter = NULL;
1313 std::multimap<std::string, std::string> actual2;
1314 while (new_headers2->EnumerateHeaderLines(&iter, &name, &value)) {
1315 actual2.insert(std::pair<std::string, std::string>(name, value));
1316 }
1317 EXPECT_EQ(expected1, actual2);
1318 EXPECT_EQ(1u, conflicting_extensions.size());
1319 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1320 EXPECT_EQ(2u, event_log.size());
1321 }
1322
1323 // Check that we do not delete too much
1324 TEST(ExtensionWebRequestHelpersTest,
1325 TestMergeOnHeadersReceivedResponsesDeletion) {
1326 EventLogEntries event_log;
1327 std::set<std::string> conflicting_extensions;
1328 std::string header_value;
1329 EventResponseDeltas deltas;
1330
1331 char base_headers_string[] =
1332 "HTTP/1.0 200 OK\r\n"
1333 "Key1: Value1\r\n"
1334 "Key1: Value2\r\n"
1335 "Key1: Value3\r\n"
1336 "Key2: Value4\r\n"
1337 "\r\n";
1338 scoped_refptr<net::HttpResponseHeaders> base_headers(
1339 new net::HttpResponseHeaders(
1340 net::HttpUtil::AssembleRawHeaders(
1341 base_headers_string, sizeof(base_headers_string))));
1342
1343 linked_ptr<EventResponseDelta> d1(
1344 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1345 d1->deleted_response_headers.push_back(ResponseHeader("KEY1", "Value2"));
1346 deltas.push_back(d1);
1347 scoped_refptr<net::HttpResponseHeaders> new_headers1;
1348 MergeOnHeadersReceivedResponses(
1349 deltas, base_headers.get(), &new_headers1, &conflicting_extensions,
1350 &event_log);
1351 ASSERT_TRUE(new_headers1.get());
1352 std::multimap<std::string, std::string> expected1;
1353 expected1.insert(std::pair<std::string, std::string>("Key1", "Value1"));
1354 expected1.insert(std::pair<std::string, std::string>("Key1", "Value3"));
1355 expected1.insert(std::pair<std::string, std::string>("Key2", "Value4"));
1356 void* iter = NULL;
1357 std::string name;
1358 std::string value;
1359 std::multimap<std::string, std::string> actual1;
1360 while (new_headers1->EnumerateHeaderLines(&iter, &name, &value)) {
1361 actual1.insert(std::pair<std::string, std::string>(name, value));
1362 }
1363 EXPECT_EQ(expected1, actual1);
1364 EXPECT_EQ(0u, conflicting_extensions.size());
1365 EXPECT_EQ(1u, event_log.size());
1366 }
1367
1368 TEST(ExtensionWebRequestHelpersTest, TestMergeOnAuthRequiredResponses) {
1369 EventLogEntries event_log;
1370 std::set<std::string> conflicting_extensions;
1371 EventResponseDeltas deltas;
1372 string16 username = ASCIIToUTF16("foo");
1373 string16 password = ASCIIToUTF16("bar");
1374 string16 password2 = ASCIIToUTF16("baz");
1375
1376 // Check that we can handle if not returning credentials.
1377 linked_ptr<EventResponseDelta> d0(
1378 new EventResponseDelta("extid0", base::Time::FromInternalValue(3000)));
1379 deltas.push_back(d0);
1380 net::AuthCredentials auth0;
1381 bool credentials_set = MergeOnAuthRequiredResponses(
1382 deltas, &auth0, &conflicting_extensions, &event_log);
1383 EXPECT_FALSE(credentials_set);
1384 EXPECT_TRUE(auth0.Empty());
1385 EXPECT_EQ(0u, conflicting_extensions.size());
1386 EXPECT_EQ(0u, event_log.size());
1387
1388 // Check that we can set AuthCredentials.
1389 linked_ptr<EventResponseDelta> d1(
1390 new EventResponseDelta("extid1", base::Time::FromInternalValue(2000)));
1391 d1->auth_credentials.reset(new net::AuthCredentials(username, password));
1392 deltas.push_back(d1);
1393 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1394 conflicting_extensions.clear();
1395 event_log.clear();
1396 net::AuthCredentials auth1;
1397 credentials_set = MergeOnAuthRequiredResponses(
1398 deltas, &auth1, &conflicting_extensions, &event_log);
1399 EXPECT_TRUE(credentials_set);
1400 EXPECT_FALSE(auth1.Empty());
1401 EXPECT_EQ(username, auth1.username());
1402 EXPECT_EQ(password, auth1.password());
1403 EXPECT_EQ(0u, conflicting_extensions.size());
1404 EXPECT_EQ(1u, event_log.size());
1405
1406 // Check that we set AuthCredentials only once.
1407 linked_ptr<EventResponseDelta> d2(
1408 new EventResponseDelta("extid2", base::Time::FromInternalValue(1500)));
1409 d2->auth_credentials.reset(new net::AuthCredentials(username, password2));
1410 deltas.push_back(d2);
1411 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1412 conflicting_extensions.clear();
1413 event_log.clear();
1414 net::AuthCredentials auth2;
1415 credentials_set = MergeOnAuthRequiredResponses(
1416 deltas, &auth2, &conflicting_extensions, &event_log);
1417 EXPECT_TRUE(credentials_set);
1418 EXPECT_FALSE(auth2.Empty());
1419 EXPECT_EQ(username, auth1.username());
1420 EXPECT_EQ(password, auth1.password());
1421 EXPECT_EQ(1u, conflicting_extensions.size());
1422 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1423 EXPECT_EQ(2u, event_log.size());
1424
1425 // Check that we can set identical AuthCredentials twice without causing
1426 // a conflict.
1427 linked_ptr<EventResponseDelta> d3(
1428 new EventResponseDelta("extid3", base::Time::FromInternalValue(1000)));
1429 d3->auth_credentials.reset(new net::AuthCredentials(username, password));
1430 deltas.push_back(d3);
1431 deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
1432 conflicting_extensions.clear();
1433 event_log.clear();
1434 net::AuthCredentials auth3;
1435 credentials_set = MergeOnAuthRequiredResponses(
1436 deltas, &auth3, &conflicting_extensions, &event_log);
1437 EXPECT_TRUE(credentials_set);
1438 EXPECT_FALSE(auth3.Empty());
1439 EXPECT_EQ(username, auth1.username());
1440 EXPECT_EQ(password, auth1.password());
1441 EXPECT_EQ(1u, conflicting_extensions.size());
1442 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1443 EXPECT_EQ(3u, event_log.size());
1444 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698