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

Side by Side Diff: chrome/browser/extensions/api/web_request/web_request_api_unittest.cc

Issue 10694055: Add read-only access to POST data for webRequest's onBeforeRequest (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <queue> 5 #include <queue>
6 #include <map> 6 #include <map>
7 7
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/json/json_reader.h"
11 #include "base/json/json_string_value_serializer.h" 12 #include "base/json/json_string_value_serializer.h"
12 #include "base/memory/weak_ptr.h" 13 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop.h" 14 #include "base/message_loop.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/string_piece.h"
16 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/content_settings/cookie_settings.h" 19 #include "chrome/browser/content_settings/cookie_settings.h"
18 #include "chrome/browser/extensions/api/web_request/web_request_api.h" 20 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
19 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h" 21 #include "chrome/browser/extensions/api/web_request/web_request_api_constants.h"
20 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h" 22 #include "chrome/browser/extensions/api/web_request/web_request_api_helpers.h"
21 #include "chrome/browser/extensions/event_router_forwarder.h" 23 #include "chrome/browser/extensions/event_router_forwarder.h"
22 #include "chrome/browser/net/chrome_network_delegate.h" 24 #include "chrome/browser/net/chrome_network_delegate.h"
23 #include "chrome/browser/prefs/pref_member.h" 25 #include "chrome/browser/prefs/pref_member.h"
24 #include "chrome/common/extensions/extension_messages.h" 26 #include "chrome/common/extensions/extension_messages.h"
25 #include "chrome/common/pref_names.h" 27 #include "chrome/common/pref_names.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 } 68 }
67 69
68 // Searches |key| in |collection| by iterating over its elements and returns 70 // Searches |key| in |collection| by iterating over its elements and returns
69 // true if found. 71 // true if found.
70 template <typename Collection, typename Key> 72 template <typename Collection, typename Key>
71 bool Contains(const Collection& collection, const Key& key) { 73 bool Contains(const Collection& collection, const Key& key) {
72 return std::find(collection.begin(), collection.end(), key) != 74 return std::find(collection.begin(), collection.end(), key) !=
73 collection.end(); 75 collection.end();
74 } 76 }
75 77
78 // Parses |json_string| as a Value. Returns NULL on failure. The caller owns
79 // the returned object.
80 const Value* GetValueFromJson(const base::StringPiece& json_string) {
81 const Value* parsed = base::JSONReader::Read(json_string);
82 return parsed;
83 }
84
85 // Parses |json_string| as a DictionaryValue. Returns NULL on failure. The
86 // caller owns the returned object.
87 const DictionaryValue* GetDictionaryFromJson(
88 const base::StringPiece& json_string) {
89 const Value* value = GetValueFromJson(json_string);
90 if (value == NULL)
91 return NULL;
92 // Now we own the object pointed to by |value|.
93 const DictionaryValue* dictionary = NULL;
94 if (value->GetAsDictionary(&dictionary)) {
95 // We pass the ownership of the object |value|==|dictionary| to the caller.
96 return dictionary;
97 } else {
98 // The object at |value| is no longer needed.
99 delete value;
100 return NULL;
101 }
102 }
103
104 // Parses the JSON data attached to the |message| and tries to return it.
105 // Returns NULL on failure.
106 scoped_ptr<const DictionaryValue> GetPartOfMessageArguments(
107 IPC::Message* message) {
108 CHECK(message->type() == ExtensionMsg_MessageInvoke::ID);
109 ExtensionMsg_MessageInvoke::Param param;
110 Value* temp_value = NULL;
111 CHECK(ExtensionMsg_MessageInvoke::Read(message, &param));
112 CHECK(param.c.GetSize() >= 2);
113 CHECK(param.c.Get(1, &temp_value));
114 std::string args;
115 CHECK(temp_value->GetAsString(&args));
116 const Value* value = GetValueFromJson(args);
117 if (value == NULL) {
118 DLOG(INFO) << "Failed to parse JSON in the message arguments.";
119 return scoped_ptr<const DictionaryValue>();
120 }
121 const ListValue* list = NULL;
122 if (!value->GetAsList(&list)) {
123 DLOG(INFO) << "Parsed message argument is not a ListValue.";
124 return scoped_ptr<const DictionaryValue>();
125 }
126 scoped_ptr<const ListValue> list_scoped(list); // To ensure clean-up.
127 if (list->GetSize() != 1) {
128 DLOG(INFO) << "The Listvalue in message arguments has not size 1.";
129 return scoped_ptr<const DictionaryValue>();
130 }
131 // TODO(vabr): Add const once ListValue getters get corrected.
132 DictionaryValue* dictionary = NULL;
133 if (!list->GetDictionary(0, &dictionary)) {
134 DLOG(INFO) << "The only Value in the list in message arguments"
135 "is not a DictionaryiValue.";
136 return scoped_ptr<const DictionaryValue>();
137 }
138 return scoped_ptr<const DictionaryValue>(dictionary->DeepCopy());
139 }
140
76 } // namespace 141 } // namespace
77 142
78 // A mock event router that responds to events with a pre-arranged queue of 143 // A mock event router that responds to events with a pre-arranged queue of
79 // Tasks. 144 // Tasks.
80 class TestIPCSender : public IPC::Sender { 145 class TestIPCSender : public IPC::Sender {
81 public: 146 public:
82 typedef std::list<linked_ptr<IPC::Message> > SentMessages; 147 typedef std::list<linked_ptr<IPC::Message> > SentMessages;
83 148
84 // Adds a Task to the queue. We will fire these in order as events are 149 // Adds a Task to the queue. We will fire these in order as events are
85 // dispatched. 150 // dispatched.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL); 192 prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
128 network_delegate_.reset(new ChromeNetworkDelegate( 193 network_delegate_.reset(new ChromeNetworkDelegate(
129 event_router_.get(), NULL, NULL, &profile_, 194 event_router_.get(), NULL, NULL, &profile_,
130 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_, 195 CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_,
131 NULL)); 196 NULL));
132 context_.reset(new TestURLRequestContext(true)); 197 context_.reset(new TestURLRequestContext(true));
133 context_->set_network_delegate(network_delegate_.get()); 198 context_->set_network_delegate(network_delegate_.get());
134 context_->Init(); 199 context_->Init();
135 } 200 }
136 201
202 // Fires a URLRequest with the specified |content_type|. Method will be "POST"
203 // and the data will be |bytes|.
204 void FireURLRequestWithPostData(const char* content_type,
205 const char* bytes, size_t bytes_length);
206
137 MessageLoopForIO message_loop_; 207 MessageLoopForIO message_loop_;
138 content::TestBrowserThread ui_thread_; 208 content::TestBrowserThread ui_thread_;
139 content::TestBrowserThread io_thread_; 209 content::TestBrowserThread io_thread_;
140 TestingProfile profile_; 210 TestingProfile profile_;
141 TestDelegate delegate_; 211 TestDelegate delegate_;
142 BooleanPrefMember enable_referrers_; 212 BooleanPrefMember enable_referrers_;
143 TestIPCSender ipc_sender_; 213 TestIPCSender ipc_sender_;
144 scoped_refptr<extensions::EventRouterForwarder> event_router_; 214 scoped_refptr<extensions::EventRouterForwarder> event_router_;
145 scoped_refptr<ExtensionInfoMap> extension_info_map_; 215 scoped_refptr<ExtensionInfoMap> extension_info_map_;
146 scoped_ptr<ChromeNetworkDelegate> network_delegate_; 216 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 EXPECT_TRUE(!request.is_pending()); 462 EXPECT_TRUE(!request.is_pending());
393 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status()); 463 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
394 EXPECT_EQ(net::ERR_ABORTED, request.status().error()); 464 EXPECT_EQ(net::ERR_ABORTED, request.status().error());
395 EXPECT_EQ(request_url, request.url()); 465 EXPECT_EQ(request_url, request.url());
396 EXPECT_EQ(1U, request.url_chain().size()); 466 EXPECT_EQ(1U, request.url_chain().size());
397 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 467 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
398 468
399 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 469 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
400 &profile_, extension_id, kEventName + "/1"); 470 &profile_, extension_id, kEventName + "/1");
401 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 471 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
402 &profile_, extension_id, kEventName2 + "/1"); 472 &profile_, extension_id, kEventName2 + "/1");
473 }
474
475 void ExtensionWebRequestTest::FireURLRequestWithPostData(
476 const char* content_type,
477 const char* bytes, size_t bytes_length) {
478 // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
479 GURL request_url("http://www.example.com");
480 net::URLRequest request(request_url, &delegate_, context_.get());
481 request.set_method("POST");
482 request.SetExtraRequestHeaderByName(
483 net::HttpRequestHeaders::kContentType, content_type, true);
484 request.AppendBytesToUpload(bytes, bytes_length);
485 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
486 request.Start();
487 }
488
489 TEST_F(ExtensionWebRequestTest, AccessPostData) {
490 // We verify that POST data are accessible to OnBeforeRequest listeners.
491 // Three testing steps:
492 // 1. Register an extension requesting ExtraInfoSpec::POST_DATA and file a
493 // URLRequest with a multipart-encoded form. See it getting parsed.
494 // 2. Do the same, but without requesting ExtraInfoSpec::POST_DATA. Nothing
495 // should be parsed.
496 // 3. With ExtraInfoSpec::POST_DATA , fire a URLRequest with a chunked
497 // upload. Get the error message.
498 #define kBoundary "THIS_IS_A_BOUNDARY"
499 #define kBlock "--" kBoundary "\r\n" \
500 "Content-Disposition: form-data; name=\"text\"\r\n" \
501 "\r\n" \
502 "test text\r\n" \
503 "--" kBoundary "--"
504 // POST data input.
505 const char kMultipartBytes[] = kBlock;
506 // Expected POST data output.
507 const std::string kPostDataPath(keys::kPostDataKey);
508 const std::string kFormDataPath(kPostDataPath + "." + keys::kFormDataKey);
509 const std::string kErrorPath(kPostDataPath + "." + keys::kPostDataErrorKey);
510 const std::string* kPath[] = {&kFormDataPath, &kPostDataPath, &kErrorPath};
511 // formData
512 const char kFormDataString[] = "{\"text\":[\"test text\"]}";
513 scoped_ptr<const DictionaryValue> form_data(
514 GetDictionaryFromJson(kFormDataString));
515 ASSERT_TRUE(form_data.get() != NULL);
516 // error
517 const StringValue error("chunked_encoding");
518 // Summary.
519 const Value* kExpected[] = {form_data.get(), NULL, &error};
520 // Header.
521 const char kMultipart[] = "multipart/form-data; boundary=" kBoundary;
522 #undef kBlock
523 #undef kBoundary
524
525 // Set up a dummy extension name.
526 ExtensionWebRequestEventRouter::RequestFilter filter;
527 std::string extension_id("1");
528 int extra_info_spec_post =
529 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
530 ExtensionWebRequestEventRouter::ExtraInfoSpec::POST_DATA;
531 int extra_info_spec_no_post =
532 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING;
533
534 // Part 1.
535 // Subscribe to OnBeforeRequest with POST data requirement.
536 const std::string kEventName(keys::kOnBeforeRequest);
537 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
538 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
539 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
540 filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
541
542 FireURLRequestWithPostData(
543 kMultipart, kMultipartBytes, strlen(kMultipartBytes));
544
545 MessageLoop::current()->RunAllPending();
546
547 // Part 2.
548 // Now remove the requirement of POST data.
549 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
550 &profile_, extension_id, kEventName + "/1");
551 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
552 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
553 filter, extra_info_spec_no_post, ipc_sender_factory.GetWeakPtr());
554
555 FireURLRequestWithPostData(
556 kMultipart, kMultipartBytes, strlen(kMultipartBytes));
557
558 // Part 3.
559 // Get back the requirement of POST data.
560 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
561 &profile_, extension_id, kEventName + "/1");
562 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
563 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
564 filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
565 {
566 GURL request_url("http://www.example.com");
567 net::URLRequest request(request_url, &delegate_, context_.get());
568 request.set_method("POST");
569 request.EnableChunkedUpload();
570 const char kDummyBytes[] = "dummy";
571 request.AppendChunkToUpload(kDummyBytes, strlen(kDummyBytes), true);
572 net::HttpRequestHeaders headers(request.extra_request_headers());
573 headers.SetHeader(net::HttpRequestHeaders::kTransferEncoding, "chunked");
574 request.SetExtraRequestHeaders(headers);
575 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
576 request.Start();
577 }
578
579 MessageLoop::current()->RunAllPending();
580
581 IPC::Message* message = NULL;
582 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin();
583 for (size_t test = 0; test < arraysize(kExpected); ++test) {
584 EXPECT_NE(i, ipc_sender_.sent_end());
585 message = (i++)->get();
586 scoped_ptr<const DictionaryValue>
587 details(GetPartOfMessageArguments(message).Pass());
588 ASSERT_TRUE(details.get() != NULL);
589 const Value* result = NULL;
590 EXPECT_EQ(kExpected[test] != NULL, details->Get(*(kPath[test]), &result));
591 if (kExpected[test] != NULL) {
592 EXPECT_TRUE(kExpected[test]->Equals(result));
593 }
594 }
595
596 EXPECT_EQ(i, ipc_sender_.sent_end());
597
598 // Clean-up.
599 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
600 &profile_, extension_id, kEventName + "/1");
403 } 601 }
404 602
405 struct HeaderModificationTest_Header { 603 struct HeaderModificationTest_Header {
406 const char* name; 604 const char* name;
407 const char* value; 605 const char* value;
408 }; 606 };
409 607
410 struct HeaderModificationTest_Modification { 608 struct HeaderModificationTest_Modification {
411 enum Type { 609 enum Type {
412 SET, 610 SET,
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 true, 856 true,
659 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS); 857 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS);
660 TestInitFromValue( 858 TestInitFromValue(
661 "blocking", 859 "blocking",
662 true, 860 true,
663 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 861 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
664 TestInitFromValue( 862 TestInitFromValue(
665 "asyncBlocking", 863 "asyncBlocking",
666 true, 864 true,
667 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING); 865 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING);
866 TestInitFromValue(
867 "postData",
868 true,
869 ExtensionWebRequestEventRouter::ExtraInfoSpec::POST_DATA);
668 870
669 // Multiple valid values are bitwise-or'ed. 871 // Multiple valid values are bitwise-or'ed.
670 TestInitFromValue( 872 TestInitFromValue(
671 "requestHeaders,blocking", 873 "requestHeaders,blocking",
672 true, 874 true,
673 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS | 875 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS |
674 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 876 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
675 877
676 // Any invalid values lead to a bad parse. 878 // Any invalid values lead to a bad parse.
677 TestInitFromValue("invalidValue", false, 0); 879 TestInitFromValue("invalidValue", false, 0);
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after
1481 credentials_set = MergeOnAuthRequiredResponses( 1683 credentials_set = MergeOnAuthRequiredResponses(
1482 deltas, &auth3, &conflicting_extensions, &net_log); 1684 deltas, &auth3, &conflicting_extensions, &net_log);
1483 EXPECT_TRUE(credentials_set); 1685 EXPECT_TRUE(credentials_set);
1484 EXPECT_FALSE(auth3.Empty()); 1686 EXPECT_FALSE(auth3.Empty());
1485 EXPECT_EQ(username, auth1.username()); 1687 EXPECT_EQ(username, auth1.username());
1486 EXPECT_EQ(password, auth1.password()); 1688 EXPECT_EQ(password, auth1.password());
1487 EXPECT_EQ(1u, conflicting_extensions.size()); 1689 EXPECT_EQ(1u, conflicting_extensions.size());
1488 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2")); 1690 EXPECT_TRUE(ContainsKey(conflicting_extensions, "extid2"));
1489 EXPECT_EQ(3u, capturing_net_log.GetSize()); 1691 EXPECT_EQ(3u, capturing_net_log.GetSize());
1490 } 1692 }
1491
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698