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