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