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