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