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

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: Corrected broken unit-tests 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.
vabr (Chromium) 2012/07/30 16:05:57 I am concurrently taking care of correction the Li
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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 enable_referrers_.Init( 191 enable_referrers_.Init(
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 context_.reset(new TestURLRequestContext(true)); 196 context_.reset(new TestURLRequestContext(true));
132 context_->set_network_delegate(network_delegate_.get()); 197 context_->set_network_delegate(network_delegate_.get());
133 context_->Init(); 198 context_->Init();
134 } 199 }
135 200
201 // Fires a URLRequest with the specified |content_type|. Method will be "POST"
202 // and the data will be |bytes|.
203 void FireURLRequestWithPostData(const char* content_type,
204 const char* bytes, size_t bytes_length);
205
136 MessageLoopForIO message_loop_; 206 MessageLoopForIO message_loop_;
137 content::TestBrowserThread ui_thread_; 207 content::TestBrowserThread ui_thread_;
138 content::TestBrowserThread io_thread_; 208 content::TestBrowserThread io_thread_;
139 TestingProfile profile_; 209 TestingProfile profile_;
140 TestDelegate delegate_; 210 TestDelegate delegate_;
141 BooleanPrefMember enable_referrers_; 211 BooleanPrefMember enable_referrers_;
142 TestIPCSender ipc_sender_; 212 TestIPCSender ipc_sender_;
143 scoped_refptr<extensions::EventRouterForwarder> event_router_; 213 scoped_refptr<extensions::EventRouterForwarder> event_router_;
144 scoped_refptr<ExtensionInfoMap> extension_info_map_; 214 scoped_refptr<ExtensionInfoMap> extension_info_map_;
145 scoped_ptr<ChromeNetworkDelegate> network_delegate_; 215 scoped_ptr<ChromeNetworkDelegate> network_delegate_;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 EXPECT_TRUE(!request.is_pending()); 461 EXPECT_TRUE(!request.is_pending());
392 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status()); 462 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
393 EXPECT_EQ(net::ERR_ABORTED, request.status().error()); 463 EXPECT_EQ(net::ERR_ABORTED, request.status().error());
394 EXPECT_EQ(request_url, request.url()); 464 EXPECT_EQ(request_url, request.url());
395 EXPECT_EQ(1U, request.url_chain().size()); 465 EXPECT_EQ(1U, request.url_chain().size());
396 EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); 466 EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
397 467
398 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 468 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
399 &profile_, extension_id, kEventName + "/1"); 469 &profile_, extension_id, kEventName + "/1");
400 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( 470 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
401 &profile_, extension_id, kEventName2 + "/1"); 471 &profile_, extension_id, kEventName2 + "/1");
472 }
473
474 void ExtensionWebRequestTest::FireURLRequestWithPostData(
475 const char* content_type,
476 const char* bytes, size_t bytes_length) {
477 // The request URL can be arbitrary but must have an HTTP or HTTPS scheme.
478 GURL request_url("http://www.example.com");
479 net::URLRequest request(request_url, &delegate_, context_.get());
480 request.set_method("POST");
481 request.SetExtraRequestHeaderByName(
482 net::HttpRequestHeaders::kContentType, content_type, true);
483 request.AppendBytesToUpload(bytes, bytes_length);
484 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
485 request.Start();
486 }
487
488 TEST_F(ExtensionWebRequestTest, AccessPostData) {
489 // We verify that POST data are accessible to OnBeforeRequest listeners.
490 // Three testing steps:
491 // 1. Register an extension requesting ExtraInfoSpec::POST_DATA and file a
492 // URLRequest with a multipart-encoded form. See it getting parsed.
493 // 2. Do the same, but without requesting ExtraInfoSpec::POST_DATA. Nothing
494 // should be parsed.
495 // 3. With ExtraInfoSpec::POST_DATA , fire a URLRequest with a chunked
496 // upload. Get the error message.
497 #define kBoundary "THIS_IS_A_BOUNDARY"
498 #define kBlock "--" kBoundary "\r\n" \
499 "Content-Disposition: form-data; name=\"text\"\r\n" \
500 "\r\n" \
501 "test text\r\n" \
502 "--" kBoundary "--"
503 // POST data input.
504 const char kMultipartBytes[] = kBlock;
505 // Expected POST data output.
506 const std::string kPostDataPath(keys::kPostDataKey);
507 const std::string kFormDataPath(kPostDataPath + "." + keys::kFormDataKey);
508 const std::string kErrorPath(kPostDataPath + "." + keys::kPostDataErrorKey);
509 const std::string* kPath[] = {&kFormDataPath, &kPostDataPath, &kErrorPath};
510 // formData
511 const char kFormDataString[] = "{\"text\":[\"test text\"]}";
512 scoped_ptr<const DictionaryValue> form_data(
513 GetDictionaryFromJson(kFormDataString));
514 ASSERT_TRUE(form_data.get() != NULL);
515 // error
516 const StringValue error("chunked_encoding");
517 // Summary.
518 const Value* kExpected[] = {form_data.get(), NULL, &error};
519 // Header.
520 const char kMultipart[] = "multipart/form-data; boundary=" kBoundary;
521 #undef kBlock
522 #undef kBoundary
523
524 // Set up a dummy extension name.
525 ExtensionWebRequestEventRouter::RequestFilter filter;
526 std::string extension_id("1");
527 int extra_info_spec_post =
528 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
529 ExtensionWebRequestEventRouter::ExtraInfoSpec::POST_DATA;
530 int extra_info_spec_no_post =
531 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING;
532
533 // Part 1.
534 // Subscribe to OnBeforeRequest with POST data requirement.
535 const std::string kEventName(keys::kOnBeforeRequest);
536 base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
537 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
538 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
539 filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
540
541 FireURLRequestWithPostData(
542 kMultipart, kMultipartBytes, strlen(kMultipartBytes));
543
544 MessageLoop::current()->RunAllPending();
545
546 // Part 2.
547 // Now remove the requirement of POST data.
548 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
549 &profile_, extension_id, kEventName + "/1");
550 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
551 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
552 filter, extra_info_spec_no_post, ipc_sender_factory.GetWeakPtr());
553
554 FireURLRequestWithPostData(
555 kMultipart, kMultipartBytes, strlen(kMultipartBytes));
556
557 // Part 3.
558 // Get back the requirement of POST data.
559 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
560 &profile_, extension_id, kEventName + "/1");
561 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
562 &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
563 filter, extra_info_spec_post, ipc_sender_factory.GetWeakPtr());
564 {
565 GURL request_url("http://www.example.com");
566 net::URLRequest request(request_url, &delegate_, context_.get());
567 request.set_method("POST");
568 request.EnableChunkedUpload();
569 const char kDummyBytes[] = "dummy";
570 request.AppendChunkToUpload(kDummyBytes, strlen(kDummyBytes), true);
571 net::HttpRequestHeaders headers(request.extra_request_headers());
572 headers.SetHeader(net::HttpRequestHeaders::kTransferEncoding, "chunked");
573 request.SetExtraRequestHeaders(headers);
574 ipc_sender_.PushTask(base::Bind(&base::DoNothing));
575 request.Start();
576 }
577
578 MessageLoop::current()->RunAllPending();
579
580 IPC::Message* message = NULL;
581 TestIPCSender::SentMessages::const_iterator i = ipc_sender_.sent_begin();
582 for (size_t test = 0; test < arraysize(kExpected); ++test) {
583 EXPECT_NE(i, ipc_sender_.sent_end());
584 message = (i++)->get();
585 scoped_ptr<const DictionaryValue>
586 details(GetPartOfMessageArguments(message).Pass());
587 ASSERT_TRUE(details.get() != NULL);
588 const Value* result;
589 EXPECT_EQ(kExpected[test] != NULL, details->Get(*(kPath[test]), &result));
590 if (kExpected[test] != NULL) {
591 EXPECT_TRUE(kExpected[test]->Equals(result));
592 }
593 }
594
595 EXPECT_EQ(i, ipc_sender_.sent_end());
596
597 // Clean-up.
598 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
599 &profile_, extension_id, kEventName + "/1");
402 } 600 }
403 601
404 struct HeaderModificationTest_Header { 602 struct HeaderModificationTest_Header {
405 const char* name; 603 const char* name;
406 const char* value; 604 const char* value;
407 }; 605 };
408 606
409 struct HeaderModificationTest_Modification { 607 struct HeaderModificationTest_Modification {
410 enum Type { 608 enum Type {
411 SET, 609 SET,
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 true, 854 true,
657 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS); 855 ExtensionWebRequestEventRouter::ExtraInfoSpec::RESPONSE_HEADERS);
658 TestInitFromValue( 856 TestInitFromValue(
659 "blocking", 857 "blocking",
660 true, 858 true,
661 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 859 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
662 TestInitFromValue( 860 TestInitFromValue(
663 "asyncBlocking", 861 "asyncBlocking",
664 true, 862 true,
665 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING); 863 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING);
864 TestInitFromValue(
865 "postData",
866 true,
867 ExtensionWebRequestEventRouter::ExtraInfoSpec::POST_DATA);
666 868
667 // Multiple valid values are bitwise-or'ed. 869 // Multiple valid values are bitwise-or'ed.
668 TestInitFromValue( 870 TestInitFromValue(
669 "requestHeaders,blocking", 871 "requestHeaders,blocking",
670 true, 872 true,
671 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS | 873 ExtensionWebRequestEventRouter::ExtraInfoSpec::REQUEST_HEADERS |
672 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING); 874 ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
673 875
674 // Any invalid values lead to a bad parse. 876 // Any invalid values lead to a bad parse.
675 TestInitFromValue("invalidValue", false, 0); 877 TestInitFromValue("invalidValue", false, 0);
(...skipping 849 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 // Check that requests are rejected if their first party url is sensitive. 1727 // Check that requests are rejected if their first party url is sensitive.
1526 ASSERT_GE(arraysize(non_sensitive_urls), 1u); 1728 ASSERT_GE(arraysize(non_sensitive_urls), 1u);
1527 GURL non_sensitive_url(non_sensitive_urls[0]); 1729 GURL non_sensitive_url(non_sensitive_urls[0]);
1528 for (size_t i = 0; i < arraysize(sensitive_urls); ++i) { 1730 for (size_t i = 0; i < arraysize(sensitive_urls); ++i) {
1529 TestURLRequest request(non_sensitive_url, NULL, &context); 1731 TestURLRequest request(non_sensitive_url, NULL, &context);
1530 GURL sensitive_url(sensitive_urls[i]); 1732 GURL sensitive_url(sensitive_urls[i]);
1531 request.set_first_party_for_cookies(sensitive_url); 1733 request.set_first_party_for_cookies(sensitive_url);
1532 EXPECT_TRUE(helpers::HideRequest(&request)) << sensitive_urls[i]; 1734 EXPECT_TRUE(helpers::HideRequest(&request)) << sensitive_urls[i];
1533 } 1735 }
1534 } 1736 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698